Skip to content

Commit e2d29cb

Browse files
committed
test_runner: error on test file patterns that do not exist
Report each literal positional argument that does not match an existing file instead of silently dropping it. Fixes: #64109
1 parent f4c85d5 commit e2d29cb

2 files changed

Lines changed: 51 additions & 3 deletions

File tree

lib/internal/test_runner/runner.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const {
3434
} = primordials;
3535

3636
const { spawn } = require('child_process');
37+
const { existsSync } = require('fs');
3738
const { finished } = require('internal/streams/end-of-stream');
3839
const { availableParallelism } = require('os');
3940
const { resolve, sep, isAbsolute } = require('path');
@@ -161,9 +162,20 @@ function createTestFileList(patterns, cwd) {
161162
});
162163
const results = glob.globSync();
163164

164-
if (hasUserSuppliedPattern && results.length === 0 && ArrayPrototypeEvery(glob.matchers, (m) => !m.hasMagic())) {
165-
console.error(`Could not find '${ArrayPrototypeJoin(patterns, ', ')}'`);
166-
process.exit(kGenericUserError);
165+
if (hasUserSuppliedPattern) {
166+
if (results.length === 0 && ArrayPrototypeEvery(glob.matchers, (m) => !m.hasMagic())) {
167+
console.error(`Could not find '${ArrayPrototypeJoin(patterns, ', ')}'`);
168+
process.exit(kGenericUserError);
169+
}
170+
171+
const missing = ArrayPrototypeFilter(patterns, (pattern, i) => {
172+
return !glob.matchers[i].hasMagic() && !existsSync(resolve(cwd, pattern));
173+
});
174+
175+
if (missing.length > 0) {
176+
console.error(`Could not find '${ArrayPrototypeJoin(missing, ', ')}'`);
177+
process.exit(kGenericUserError);
178+
}
167179
}
168180

169181
return ArrayPrototypeSort(results);

test/parallel/test-runner-cli.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,42 @@ for (const isolation of ['none', 'process']) {
2323
assert.match(child.stderr.toString(), /^Could not find/);
2424
}
2525

26+
{
27+
// A file that is not found should error even when other patterns match.
28+
const args = [
29+
'--test',
30+
`--test-isolation=${isolation}`,
31+
'a-random-file-that-does-not-exist.js',
32+
join(testFixtures, 'default-behavior/test/random.cjs'),
33+
];
34+
const child = spawnSync(process.execPath, args);
35+
36+
assert.strictEqual(child.status, 1);
37+
assert.strictEqual(child.signal, null);
38+
assert.strictEqual(child.stdout.toString(), '');
39+
assert.match(child.stderr.toString(),
40+
/^Could not find 'a-random-file-that-does-not-exist\.js'/);
41+
}
42+
43+
{
44+
// Options after positional arguments are treated as patterns and should
45+
// error instead of being silently dropped.
46+
const args = [
47+
'--test',
48+
`--test-isolation=${isolation}`,
49+
join(testFixtures, 'default-behavior/test/random.cjs'),
50+
'--test-reporter',
51+
'tap',
52+
];
53+
const child = spawnSync(process.execPath, args);
54+
55+
assert.strictEqual(child.status, 1);
56+
assert.strictEqual(child.signal, null);
57+
assert.strictEqual(child.stdout.toString(), '');
58+
assert.match(child.stderr.toString(),
59+
/^Could not find '--test-reporter, tap'/);
60+
}
61+
2662
{
2763
// Default behavior. node_modules is ignored. Files that don't match the
2864
// pattern are ignored except in test/ directories.

0 commit comments

Comments
 (0)