Skip to content

Commit a8895e4

Browse files
committed
test_runner: warn on test file patterns that do not exist
Emit a warning for each literal positional argument that does not match an existing file instead of silently dropping it. A warning rather than an error keeps existing passing invocations passing. Fixes: #64109
1 parent f4c85d5 commit a8895e4

2 files changed

Lines changed: 51 additions & 3 deletions

File tree

lib/internal/test_runner/runner.js

Lines changed: 14 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,19 @@ 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+
process.emitWarning(`Could not find '${ArrayPrototypeJoin(missing, ', ')}'`);
177+
}
167178
}
168179

169180
return ArrayPrototypeSort(results);

test/parallel/test-runner-cli.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,43 @@ 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 warn even when other patterns match,
28+
// and the matching tests should still run.
29+
const args = [
30+
'--test',
31+
`--test-isolation=${isolation}`,
32+
'a-random-file-that-does-not-exist.js',
33+
join(testFixtures, 'default-behavior/test/random.cjs'),
34+
];
35+
const child = spawnSync(process.execPath, args);
36+
37+
assert.strictEqual(child.status, 0);
38+
assert.strictEqual(child.signal, null);
39+
assert.match(child.stderr.toString(),
40+
/Warning: Could not find 'a-random-file-that-does-not-exist\.js'/);
41+
assert.match(child.stdout.toString(), /this should pass/);
42+
}
43+
44+
{
45+
// Options after positional arguments are treated as patterns and should
46+
// warn instead of being silently dropped.
47+
const args = [
48+
'--test',
49+
`--test-isolation=${isolation}`,
50+
join(testFixtures, 'default-behavior/test/random.cjs'),
51+
'--test-reporter',
52+
'tap',
53+
];
54+
const child = spawnSync(process.execPath, args);
55+
56+
assert.strictEqual(child.status, 0);
57+
assert.strictEqual(child.signal, null);
58+
assert.match(child.stderr.toString(),
59+
/Warning: Could not find '--test-reporter, tap'/);
60+
assert.match(child.stdout.toString(), /this should pass/);
61+
}
62+
2663
{
2764
// Default behavior. node_modules is ignored. Files that don't match the
2865
// pattern are ignored except in test/ directories.

0 commit comments

Comments
 (0)