Reporters and Watch

Reporters, Filtering and Watch Mode

A reporter is a stream transform that consumes the runner's event objects and emits text. Five ship with Node: spec (the default, even when output is piped to a file), dot, tap, junit and lcov. Select one with --test-reporter and pair each with --test-reporter-destination to run several at once. --test-reporter=dot collapses the two test files above to ......, one character per test and suite; junit writes the XML that Jenkins 8,793 , GitLab CI 377 and GitHub Actions 29 summaries parse. A custom reporter is an async generator over the events:

A minimal custom reporterShell
export default async function* failuresOnly(source) {
  for await (const event of source) {
    if (event.type === 'test:fail') {
      yield `${event.data.name} — ${event.data.details.error.message}\n`;
    }
  }
}

Point --test-reporter=./reporters/failures.mjs at it; the events are test:start, test:pass, test:fail, test:plan, test:diagnostic, test:stdout, test:stderr and test:coverage.

--test-name-pattern takes a regular expression matched against the full test name, enclosing suite names included, and --test-skip-pattern is its inverse. Filtered-out tests do not appear at all, so node --test --test-name-pattern="coupon" test/cart.test.js prints one line, ✔ an unknown coupon is rejected (1.0536ms), then ℹ tests 1 / ℹ pass 1; --test-shard=2/4 splits the files across CI machines. Node 26 adds --experimental-test-tag-filter, a boolean expression over tags declared as { tags: ['db'] } such as '(unit or smoke) and not slow', and --test-randomize, which shuffles test order and prints the seed so a failure can be replayed with --test-random-seed. Both are stability 1.0, early development, and absent from Node 25.

Watch mode is experimental, but the dependency graph it uses is the module graph, so editing src/cart.js re-runs every test file that imports it.

✔ subtotal adds up price times quantity (0.7274ms)

✔ an unknown coupon is rejected (0.485ms)

ℹ duration_ms 106.2015

Restarted at 9/17/2026, 8:02:12 PM

✔ subtotal adds up price times quantity (0.727ms)

✔ an unknown coupon is rejected (0.3742ms)

ℹ duration_ms 118.2944

Watch mode re-running after a source edit

The console is cleared between runs unless you pass --watch-preserve-output, and --watch with --test-name-pattern gives a fast inner loop while you fix one test. Watch mode keeps the process alive, so it belongs in a test:watch script and never in CI.