Repository navigation
test_runner: directory arguments to --test fail with MODULE_NOT_FOUND on Windows (regression since v20) #64555
Description
Activity
Update after more digging — this is not Windows-specific; I've updated the title.
I retested on Linux x64 (Ubuntu 24.04 via WSL2, official v24.18.0 binary):
node --test testsfails the same way. My "works on Linux/macOS" note in the
original report was wrong.The root cause appears to be the v20 → v22 change in test file discovery:
- v20:
processPath()callsstatSync()and recursively walks directories
withreaddirSync(), so directory arguments worked:
https://github.com/nodejs/node/blob/v20.20.2/lib/internal/test_runner/runner.js#L91-L126 - v22+: discovery moved to the internal glob in
createTestFileList():
https://github.com/nodejs/node/blob/v22.18.0/lib/internal/test_runner/runner.js#L108-L126
A pattern that literally matches a directory returns the directory path
itself (standard glob semantics — no expansion), and the runner then spawns
it as if it were a test file, which crashes withMODULE_NOT_FOUND.
Worth noting: the v20 docs explicitly documented directory arguments, with a
directory in the example (node --test test1.js test2.mjs custom_test_dir/—
"The test runner will also recursively search the directory"):
https://github.com/nodejs/node/blob/v20.20.2/doc/api/test.md
Current docs mention only glob patterns, but there was no deprecation cycle or
clear error — scripts using the documented form went from working to a cryptic
crash.Proposed fix: in
createTestFileList(), when a user-supplied pattern has no
glob magic and stats to a directory, expand it to<pattern>/<kDefaultPattern>
before matching — restoring the documented v20 behavior while keeping the glob
implementation. Alternatively, if directory support is intentionally dropped, a
clear error message would at least remove the confusing crash. Happy to open a
PR either way.- v20:
I think this started in v21 and not v22. It was also a semver major
That being said I see how it is confusing though. I'd at least expect
node --test tests/to work- addedtest_runnerIssues and PRs related to the test runner subsystem.Issues and PRs related to the test runner subsystem.
on Jul 18, 2026 Thanks — you're right, the glob-based discovery landed in v21, so v21.0.0 is the actual change point (I only had v20 and v22 installed to compare; I'll update the title). And fair point on it being semver-major.
Given you'd also expect node --test tests/ to work, would a PR along the lines I sketched above be welcome? Concretely: in createTestFileList(), when a user-supplied pattern contains no glob magic and statSync says it's a directory, expand it to join(pattern, kDefaultPattern) before matching — restoring the documented v20 behavior on top of the glob implementation, with a test in test/parallel/. Happy to open it if that approach sounds right.
It was just my 2 cents.
You are always welcome to open a PR, it might get some eyes and start a discussion. Worst case it gets rejected, but we all learn something.
Confirming this reproduces, and I think it's actually not Windows-specific. On macOS
node --test testsfails the same way:node@20searches the directory and passes, butnode@22andnode@24both fail withMODULE_NOT_FOUND.It looks like the directory argument is matched as a literal glob pattern, so it resolves to the directory itself and then gets run as a test file, instead of being searched for the test files inside it. Opened #64637 to expand a directory argument back into a search for the default test files within it.
- added a commit that references this issue
on Aug 21, 2026 - added 2 commits that reference this issue
on Aug 25, 2026 - added a commit that references this issue
on Sep 26, 2026 - added a commit that references this issue
on Oct 5, 2026
Version
test_runner: directory arguments to --test crash with MODULE_NOT_FOUND instead of being searched (since v21)
Platform
Subsystem
test_runner
What steps will reproduce the bug?
Create a directory containing a single test file:
tests/sample.test.mjs:Then, on Windows, pass the directory to the test runner:
All three fail with
MODULE_NOT_FOUND— the directory is executed as if itwere a test file instead of being searched for test files.
For contrast, all of the following work:
node --testwith no arguments in the same folder (default discovery finds and runs the test)How often does it reproduce? Is there a required condition?
Always, on Windows, whenever a directory path is passed as an argument to --test.
What is the expected behavior? Why is that the expected behavior?
Passing a directory to
node --testshould recursively search it for testfiles and run them, as documented, as Node v20 does on Windows, and as current
versions still do on Linux/macOS.
What do you see instead?
The directory is treated as a single test file and executed directly, which
fails in the module loader:
The output is identical for
node --test testsandnode --test tests\.Additional information
This appears to be a regression between v20.20.2 (works) and v22.x (broken).
Possibly related to the test runner's file discovery moving to the internal
glob implementation (
createTestFileListinlib/internal/test_runner/runner.js),where a directory pattern seems to match the directory itself rather than
being expanded to the test files inside it.
Happy to work on a fix if a collaborator confirms this is a bug.