镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

test_runner: directory arguments to --test fail with MODULE_NOT_FOUND on Windows (regression since v20) #64555

Description

@dhruvvv0913

Version

test_runner: directory arguments to --test crash with MODULE_NOT_FOUND instead of being searched (since v21)

Platform

Microsoft Windows NT 10.0.26200.0 x64

Subsystem

test_runner

What steps will reproduce the bug?

Create a directory containing a single test file:

tests/sample.test.mjs:

import test from 'node:test';
test('ok', () => {});

Then, on Windows, pass the directory to the test runner:

node --test tests
node --test tests/
node --test tests\

All three fail with MODULE_NOT_FOUND — the directory is executed as if it
were a test file instead of being searched for test files.

For contrast, all of the following work:

  • node --test with no arguments in the same folder (default discovery finds and runs the test)
  • the same three commands on Node v20.20.2 on Windows
  • passing a directory on Linux/macOS

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 --test should recursively search it for test
files 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:

PS C:\Users\KIIT\node-bug-repro> node --test tests/
node:internal/modules/cjs/loader:1368
  throw err;
  ^

Error: Cannot find module 'C:\Users\KIIT\node-bug-repro\tests'
    at Function._resolveFilename (node:internal/modules/cjs/loader:1365:15)
    at defaultResolveImpl (node:internal/modules/cjs/loader:1021:19)
    at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1026:22)
    at Function._load (node:internal/modules/cjs/loader:1175:37)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:171:5)
    at node:internal/main/run_main_module:36:49 {
  code: 'MODULE_NOT_FOUND',
  requireStack: []
}

Node.js v22.18.0
✖ tests (70.2044ms)
  'test failed'
ℹ tests 1
ℹ suites 0
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 79.0802

✖ failing tests:

test at tests:1:1
✖ tests (70.2044ms)
  'test failed'

The output is identical for node --test tests and node --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 (createTestFileList in lib/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.

Activity

  1. dhruvvv0913 commented on Jul 17, 2026

    @dhruvvv0913
    Author

    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 tests fails 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:

    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.

  2. efekrskl commented on Jul 18, 2026

    @efekrskl
    Member

    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

  3. added
    test_runnerIssues and PRs related to the test runner subsystem.
    on Jul 18, 2026
  4. dhruvvv0913 commented on Jul 18, 2026

    @dhruvvv0913
    Author

    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.

  5. efekrskl commented on Jul 18, 2026

    @efekrskl
    Member

    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.

  6. bitpshr commented on Jul 21, 2026

    @bitpshr
    Contributor

    Confirming this reproduces, and I think it's actually not Windows-specific. On macOS node --test tests fails the same way: node@20 searches the directory and passes, but node@22 and node@24 both fail with MODULE_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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    test_runnerIssues and PRs related to the test runner subsystem.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions