Skip to content

Commit 966239c

Browse files
committed
Fix spawn handling
Fixes #144 Fixes #189
1 parent fb5e3f1 commit 966239c

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

index.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,19 @@ const baseOpen = async options => {
268268

269269
subprocess.unref();
270270

271-
return subprocess;
271+
// Handle spawn errors before the caller can attach listeners.
272+
// This prevents unhandled error events from crashing the process.
273+
return new Promise((resolve, reject) => {
274+
subprocess.once('error', reject);
275+
276+
// Wait for the subprocess to spawn before resolving.
277+
// This ensures the process is established before the caller continues,
278+
// preventing issues when process.exit() is called immediately after.
279+
subprocess.once('spawn', () => {
280+
subprocess.off('error', reject);
281+
resolve(subprocess);
282+
});
283+
});
272284
};
273285

274286
const open = (target, options) => {

test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import process from 'node:process';
12
import test from 'ava';
23
import open, {openApp, apps} from './index.js';
34

@@ -105,3 +106,18 @@ test('open default browser', async t => {
105106
test('open default browser in incognito mode', async t => {
106107
await t.notThrowsAsync(openApp(apps.browserPrivate, {newInstance: true}));
107108
});
109+
110+
test('subprocess is spawned before promise resolves', async t => {
111+
const childProcess = await open('index.js');
112+
113+
// By the time the promise resolves, the spawn event should have fired
114+
// We verify this by checking that the subprocess has a pid
115+
t.true(childProcess.pid !== undefined && childProcess.pid !== null);
116+
});
117+
118+
if (process.platform === 'linux') {
119+
test('spawn errors reject the promise instead of crashing', async t => {
120+
const error = await t.throwsAsync(openApp('definitely-not-a-real-command-12345'));
121+
t.is(error.code, 'ENOENT');
122+
});
123+
}

0 commit comments

Comments
 (0)