You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
node:test: assertion failures inside async callback (done-style test) are ignored and test incorrectly passes #28501
When using callback-style tests (done) with node:test, assertion failures thrown inside asynchronous callbacks (e.g. setTimeout) are not captured by Bun's test runner. As a result, the test is reported as passing even though an assertion fails.
PoC
"use strict";const{ describe, test }=require("node:test");constassert=require("node:assert");describe("describe wrapper",()=>{test("callback test",(t,done)=>{setTimeout(()=>{assert.ok(false,"oh no an assert failed");done();});});});
What is the expected behavior?
root@KContainer:~/51381# node --test b.test.cjs
▶ describe wrapper
✖ callback test (3.315869ms)
✖ describe wrapper (4.996912ms)
ℹ tests 1
ℹ suites 1
ℹ pass 0
ℹ fail 1
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 96.535574
✖ failing tests:
test at b.test.cjs:6:3
✖ callback test (3.315869ms)
AssertionError [ERR_ASSERTION]: oh no an assert failed
at Timeout._onTimeout (/51381/b.test.cjs:8:14)
at listOnTimeout (node:internal/timers:605:17)
at process.processTimers (node:internal/timers:541:7) {
generatedMessage: false,
code: 'ERR_ASSERTION',
actual: false,
expected: true,
operator: '==',
diff: 'simple'
}
What do you see instead?
root@KContainer:~/51381# bun test b.test.cjs
bun test v1.3.11-canary.1 (9e93bfa1)
b.test.cjs:
✓ describe wrapper > callback test [1.25ms]
1 pass
0 fail
Ran 1 test across 1 file. [55.00ms]
Root cause:createTest() in node:test never passed a done callback to callback-style test functions — the test completed synchronously before async callbacks fired.
Fix: Check fn.length >= 2 and pass a guarded done callback instead of completing immediately. Handles sync throws, async rejections, and double-call protection.
CI status: Latest build failures are Zig compiler download infrastructure issues (not code-related). Awaiting retrigger.
Verified on main at df84f8d: node:test done-style tests now wait for the callback, so assertion failures inside async callbacks (e.g. setTimeout) correctly fail the test.
$ bun test repro-28501.cjs
AssertionError: oh no an assert failed
(fail) describe wrapper > callback test
0 pass
1 fail
# exit code 1
Activity
robobun commentedon Mar 24, 2026
✅ Fix submitted: PR #28502
Root cause:
createTest()innode:testnever passed adonecallback to callback-style test functions — the test completed synchronously before async callbacks fired.Fix: Check
fn.length >= 2and pass a guarded done callback instead of completing immediately. Handles sync throws, async rejections, and double-call protection.CI status: Latest build failures are Zig compiler download infrastructure issues (not code-related). Awaiting retrigger.
Verification (local):
USE_SYSTEM_BUN=1→ 2 fail (bug exists)bun bd test→ 5 pass (fix works)fix: pass done callback to node:test callback-style tests
fix: pass done callback to node:test callback-style tests
computer4000 commentedon Mar 25, 2026
Verified. Bun's test runner passes assertions in async callbacks that should fail.
Why this matters: Tests with
donecallbacks that fail insetTimeout/async code will pass silently, hiding real bugs.Workaround: Avoid done-style tests. Use async/await pattern:
fix: pass done callback to node:test callback-style tests
node:test: support the (t, done) callback signature in tests and hooks
robobun commentedon Jul 24, 2026
Fixed by #32631.
Verified on main at df84f8d:
node:testdone-style tests now wait for the callback, so assertion failures inside async callbacks (e.g.setTimeout) correctly fail the test.vs 1498d7b (before fix):