Skip to content

fix(ext/node): fix node:test hook ordering and error handling#35393

Merged
bartlomieju merged 3 commits into
mainfrom
fix/node-test-after-hook-subtests
Jun 20, 2026
Merged

fix(ext/node): fix node:test hook ordering and error handling#35393
bartlomieju merged 3 commits into
mainfrom
fix/node-test-after-hook-subtests

Conversation

@bartlomieju

@bartlomieju bartlomieju commented Jun 20, 2026

Copy link
Copy Markdown
Member

Fixes #35390. Fixes #35404.

Under node:test, an after() hook registered on a test's context via
t.after(...) is meant to run once, after that test's body and all of its
subtests have completed. Deno's compatibility layer was instead running the
parent's before()/after() hooks inside every subtest's step, so an
after() that tore down a shared resource (a server, a database handle) fired
right after the first subtest and broke every subtest after it.

The fix separates the once-per-test hooks from the per-subtest ones. A
context's before() hooks now run a single time, lazily, just before its first
subtest, and its after() hooks run a single time after its body and all of
its subtests finish. Both are guarded by idempotency flags so the success and
failure paths can invoke them without double-running, and so concurrent
subtests cannot re-trigger them. A subtest's own after() hooks now run at the
end of that subtest (previously a leaf subtest's after() hooks never ran at
all), and the top-level test's after() hooks run in the test wrapper once its
body returns. beforeEach()/afterEach() continue to run per subtest as
before.

This was found running the fastify test suite under deno test, where it
accounted for the bulk of the failures: the premature close cascaded into
server.address() returning null in later subtests.

Added coverage to the node_test_context spec asserting that t.before() runs
exactly once before the first subtest and that t.after() does not fire until
the parent test completes.

beforeEach/afterEach cascade through ancestor suites (#35404)

While fixing the above, a closely related hook bug was addressed in the same
area. A test nested inside multiple describe() blocks only ran its immediate
suite's beforeEach()/afterEach() hooks; the hooks of any enclosing suite
were skipped. Node instead runs every enclosing suite's per-test hooks, plus
the file-scope ones, with beforeEach going outermost-first and afterEach
innermost-first.

TestSuite now carries a parent link, threaded through addSuite() and
wrapSuiteFn(). When a suite test runs it walks that chain (and the root
hooks) at run time, so hooks registered late in a suite body are still seen,
and invokes beforeEach outermost-in and afterEach innermost-out. The
node_test_context spec gained a nested describe() asserting both the
beforeEach order before the test and the afterEach order after it.

A test nested inside multiple `describe()` blocks only ran its immediate
suite's `beforeEach()`/`afterEach()` hooks; an enclosing suite's hooks
were skipped (issue #35404). Node runs every enclosing suite's per-test
hooks, plus the file-scope ones: `beforeEach` outermost-first and
`afterEach` innermost-first.

TestSuite now keeps a `parent` link, threaded through `addSuite()` /
`wrapSuiteFn()`. When a suite test runs, it walks that chain (and the
root hooks) at run time so hooks registered late in a suite body are
still observed, invoking beforeEach outermost-in and afterEach
innermost-out.

Extended the `node_test_context` spec with a nested describe that asserts
both ancestor `beforeEach` hooks run before the test, outermost-first,
and both `afterEach` hooks run after it, innermost-first.
@bartlomieju bartlomieju changed the title fix(node:test): run t.after() once after the parent test, not per-subtest fix(node:test): correct t.after() and nested beforeEach/afterEach hook semantics Jun 20, 2026
@bartlomieju bartlomieju changed the title fix(node:test): correct t.after() and nested beforeEach/afterEach hook semantics fix(ext/node): fix node:test hook ordering and error handling Jun 20, 2026
@bartlomieju
bartlomieju merged commit 9855054 into main Jun 20, 2026
271 of 273 checks passed
@bartlomieju
bartlomieju deleted the fix/node-test-after-hook-subtests branch June 20, 2026 18:16
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.

afterEach() of the parent are not executed node:test: t.after() hook runs after the first subtest instead of after the parent test

1 participant