Skip to content

feat(ext/node): Node-compatible TAP reporter for node:test#34255

Merged
littledivy merged 4 commits into
mainfrom
orch/divybot-147
May 20, 2026
Merged

feat(ext/node): Node-compatible TAP reporter for node:test#34255
littledivy merged 4 commits into
mainfrom
orch/divybot-147

Conversation

@divybot
Copy link
Copy Markdown
Contributor

@divybot divybot commented May 20, 2026

Closes denoland/orchid#147

divybot and others added 2 commits May 20, 2026 05:36
When `--test-reporter=tap` is passed to a Deno process via `node` child
process semantics, route node:test's output through a Node-compatible
TAP reporter instead of Deno's default test runner. The flag is consumed
by node_shim during child_process spawn translation and forwarded to the
child via `NODE_OPTIONS` so the polyfill can detect it from the env.

Covers the simplest test-runner output fixture (test-output-tap-escape):
flat tests with skip/todo/diagnostic and Node's TAP escape rules. More
complex fixtures (nested suites, errors, plans) still need follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both pass with the new TAP reporter:
- test-output-describe-nested: exercises nested describe()/it() blocks.
- test-output-no-refs: top-level t.test() subtest whose unref'd timer
  doesn't keep the loop alive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@divybot divybot changed the title node compat: improve node:test output/reporters for absent test-output fixtures feat(ext/node): Node-compatible TAP reporter for node:test May 20, 2026
Copy link
Copy Markdown
Member

@littledivy littledivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deno test --reporter=tap already exists. Can we reuse that code path instead of rewriting in JS?

@divybot
Copy link
Copy Markdown
Contributor Author

divybot commented May 20, 2026

Good question. The two reporters target different output formats:

  • Deno's existing --reporter=tap (cli/tools/test/reporters/tap.rs) emits TAP v14 with JSON-in-YAML diagnostics and a minimal 1..N summary.
  • Node's snapshot fixtures expect TAP v13 with # Subtest: headers, typed YAML blocks (type: 'test' / type: 'suite'), and the trailing # tests N / # suites N / # pass N / ... block.

Reusing the existing reporter would also need a routing path: these fixtures are spawned via deno run script.js (not deno test), so the Rust reporter — which is wired into the deno test runner's TestReporter trait — isn't reached by the polyfill at all. Bridging that gap (either making deno run invoke the test runner when --test-reporter is set, or rewriting the format inside cli/tools/test/reporters/tap.rs to be Node-shaped) is a much bigger change.

The JS implementation here only activates when NODE_OPTIONS contains --test-reporter=tap for a polyfill-served node:test invocation, so it doesn't touch deno test --reporter=tap behavior. Happy to refactor toward a shared format if you want to go that route — let me know which direction you'd prefer.

divybot and others added 2 commits May 20, 2026 06:33
Extends the TAP-mode polyfill to cover more node:test snapshot fixtures:

- Nested subtests via `t.test()` and `describe()/it()`, with depth-correct
  indentation and per-context plan lines.
- `describe()` body tracks the active suite through `await` boundaries
  using `AsyncLocalStorage`, so tests scheduled after an inner `await`
  still register against the surrounding describe (matches Node's
  async-scheduled-tests behavior).
- Top-level `before()/after()` hooks fire around the run in TAP mode, so
  the `global-hooks-with-no-tests` fixture (bare hooks, no tests) emits
  hook output around the `TAP version 13` / `1..0` lines.
- `--test-skip-pattern` filtering: matching tests/suites are not
  registered (string and `/regex/flags` literals supported); forwarded
  from `node_shim` via `NODE_OPTIONS` so child Deno processes see it.
- `--test-only` diagnostic warning: when a child entry uses `only: true`
  and the flag isn't set, the `'only' and 'runOnly' require the
  --test-only command-line option.` warning is emitted once per parent
  at the child's depth, matching Node's placement.
- Suite vs test stats: suites count toward `# suites`, not `# tests` or
  `# skipped`.
- Keeps the event loop alive during the TAP run so fixtures using
  `setTimeout(...).unref()` (Node's runner keeps itself alive
  internally) don't exit before subtests complete.

Enables eight previously-absent fixtures in `tests/node_compat/config.jsonc`:
before-and-after-each (two), describe-nested, global-hooks-with-no-tests,
hooks-with-no-global-test, name-and-skip-patterns, no-refs, skip-pattern.

Co-Authored-By: Divy Srivastava <me@littledivy.com>
@littledivy littledivy merged commit 0f79e1d into main May 20, 2026
136 checks passed
@littledivy littledivy deleted the orch/divybot-147 branch May 20, 2026 13:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants