Skip to content

Test runner file exits with code 1 when awaiting tests + filtering #64203

Description

@simonbuchan

Version

v26.3.0

Platform

Microsoft Windows NT 10.0.26200.0 x64

also reproduces under WSL:

Linux dell-xps-3 6.18.33.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun 18 21:54:43 UTC 2026 x86_64 GNU/Linux

Subsystem

node:test

What steps will reproduce the bug?

Weird one to minify, here's what I got it down to:

import test from "node:test";

await test.suite("Suite A", async (t) => {
});

await test.suite("Suite B", async (t) => {
  await test("Test 1", async () => {
  });
  await test("Test 2", async () => {
  });
});

await test.suite("Suite C", async () => {
  await test("Test 3", async () => {
  });
});

Then node --test --test-name-pattern=C test.js (or any other pattern than B) gives the following error output:

▶ Suite C
  ✔ Test 3 (0.8439ms)
✔ Suite C (1.0333ms)
✖ test.js (54.3035ms)
ℹ tests 2
ℹ suites 1
ℹ pass 1
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 59.748

Also reproduces using .only rather than --test-name-pattern

Without --test it produces the following output, with an exit code of 1 - note the change to cancelled!:

▶ Suite C
  ✔ Test 3 (0.175ms)
✔ Suite C (1.024ms)
ℹ tests 2
ℹ suites 1
ℹ pass 1
ℹ fail 0
ℹ cancelled 1
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 6.6097

--trace-exit does not list anything additional.
Logging exitCode in process.on("exit") is 1.

Using --test-reporter=tap only lists expected ok tests without --test, with it it also lists:

# Subtest: test.js
not ok 1 - test.js
  ---
  duration_ms: 59.742
  type: 'test'
  location: 'D:\\scratch\\node-test-repro\\test.js:1:1'
  failureType: 'testCodeFailure'
  exitCode: 1
  signal: ~
  error: 'test failed'
  code: 'ERR_TEST_FAILURE'
  ...
1..2

as expected.

Removing any of the awaits, from either suites or tests seems to resolve the issue.

How often does it reproduce? Is there a required condition?

Seemingly reliably, though given it seems to be a timing related issue I can't promise that...

What is the expected behavior? Why is that the expected behavior?

It's quite possible there is some legitimate usage error here, but it should at least report what it is clearly, and certainly not only in such specific conditions!

The reason I'm using awaits in the tests in the suites is due to the editor / linter getting fussy about unawaited promises due to the types. This is a generally very handy check, so I'm loath to ignore it...

What do you see instead?

(provided above)

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions