Skip to content

Commit 91d9ded

Browse files
committed
Fix the subprocess error being hidden when the current directory was deleted
1 parent b67f199 commit 91d9ded

2 files changed

Lines changed: 47 additions & 9 deletions

File tree

‎lib/arguments/cwd.js‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,17 @@ const getDefaultCwd = () => {
1818
}
1919
};
2020

21+
// `process.cwd()` throws if the current directory has been deleted.
22+
// This is only used to improve an error message, so it must not throw itself, which would hide that error.
23+
const getCurrentCwd = () => {
24+
try {
25+
return process.cwd();
26+
} catch {}
27+
};
28+
2129
// When `cwd` option has an invalid value, provide with a better error message
2230
export const fixCwdError = (originalMessage, cwd) => {
23-
if (cwd === getDefaultCwd()) {
31+
if (cwd === getCurrentCwd()) {
2432
return originalMessage;
2533
}
2634

‎test/arguments/cwd.js‎

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,54 @@ test('The "cwd" option defaults to process.cwd() - sync', testErrorCwdDefault, e
5050

5151
// Windows does not allow removing a directory used as `cwd` of a running subprocess
5252
if (!isWindows) {
53-
const testCwdPreSpawn = async (t, execaMethod) => {
53+
// Deletes the current directory, which makes `process.cwd()` throw
54+
const chdirToMissingDirectory = async t => {
5455
const currentCwd = process.cwd();
56+
t.teardown(() => {
57+
process.chdir(currentCwd);
58+
});
59+
5560
const filePath = tempfile();
5661
await mkdir(filePath);
5762
process.chdir(filePath);
5863
await rmdir(filePath);
64+
};
5965

60-
try {
61-
t.throws(() => {
62-
execaMethod('empty.js');
63-
}, {message: /The current directory does not exist/});
64-
} finally {
65-
process.chdir(currentCwd);
66-
}
66+
const testCwdPreSpawn = async (t, execaMethod) => {
67+
await chdirToMissingDirectory(t);
68+
69+
t.throws(() => {
70+
execaMethod('empty.js');
71+
}, {message: /The current directory does not exist/});
6772
};
6873

6974
test.serial('The "cwd" option default fails if current cwd is missing', testCwdPreSpawn, execa);
7075
test.serial('The "cwd" option default fails if current cwd is missing - sync', testCwdPreSpawn, execaSync);
76+
77+
// The error message mentions the current directory, but computing it must not fail when it has been deleted.
78+
// Otherwise, this would hide the subprocess' own error, and would throw even with the `reject: false` option.
79+
const testCwdMissingError = async (t, execaMethod) => {
80+
await chdirToMissingDirectory(t);
81+
82+
const {failed, code, message} = await execaMethod('does_not_exist', {cwd: FIXTURES_DIRECTORY, reject: false});
83+
t.true(failed);
84+
t.is(code, 'ENOENT');
85+
t.true(message.includes('does_not_exist'));
86+
};
87+
88+
test.serial('The subprocess error is kept if current cwd is missing', testCwdMissingError, execa);
89+
test.serial('The subprocess error is kept if current cwd is missing - sync', testCwdMissingError, execaSync);
90+
91+
// The `cwd` option is valid, so the error message must not mention it at all
92+
const testCwdMissingValidOption = async (t, execaMethod) => {
93+
await chdirToMissingDirectory(t);
94+
95+
const {message} = await execaMethod('does_not_exist', {cwd: FIXTURES_DIRECTORY, reject: false});
96+
t.false(message.includes('The "cwd" option'));
97+
};
98+
99+
test.serial('The "cwd" option is not reported as invalid if current cwd is missing', testCwdMissingValidOption, execa);
100+
test.serial('The "cwd" option is not reported as invalid if current cwd is missing - sync', testCwdMissingValidOption, execaSync);
71101
}
72102

73103
const cwdNotExisting = {cwd: 'does_not_exist', expectedCode: 'ENOENT', expectedMessage: 'The "cwd" option is invalid'};

0 commit comments

Comments
 (0)