Repository navigation
Conversation
|
Updated 12:00 PM PT - Nov 10th, 2026
❌ @robobun, your commit 23b684b has 1 failures in
🧪 To try this PR locally: bunx bun-pr 48455That installs a local version of the PR into your bun-48455 --bun |
|
Status: draft. It waits for a maintainer to pick the direction (A, B or C in the description). How I reproduced it: I ran the file under "Repro 1" in the description with CI: no failure touches this diff. Build 139806 (the current head) finished with 187 of 188 jobs passed. The one failed job is a debian 13 x64 test shard, red on PR: #48455 |
A scope that runs no test leaves out its aroundAll hooks. The "bun:test" beforeAll and afterAll hooks of that scope, and of the scopes nested in it, still ran. They ran without the set-up and teardown of the aroundAll, and outside the async context of runSuite(). Order::enter_describe now decides once for a scope. A scope that runs no test and has an aroundAll queues none of its aroundAll, beforeAll and afterAll hooks, and the scopes nested in it inherit that. A file with no aroundAll queues what it queued before.
They now sit beside the tests for the hooks of a describe block that does not run, which hold the "bun:test" rule for a block that runs no test. vitest-flavor.test.ts is as it is on main again.
4e873ca to
23b684b
Compare
Draft: a maintainer picks the direction. Where no test runs, a
bun:testbeforeAllruns and thearoundAllaround it does not. This PR stops thebeforeAll(B). Alternatives: run thearoundAlltoo (A), or document main (C).Problem
bun:testleaves out thearoundAlland runs the block'sbeforeAll/afterAllwithout its set-up. The repro fails:TypeError: undefined is not an object (evaluating 'db.query'), exit 1.Order::generate_all_order(src/runtime/test_runner/Order.rs:43) decides per hook. It drops around hooks and keeps abun:testbeforeAll.Fix
Order::enter_describe, in the pass that builds the run queue, decides per scope: one that runs no test and has anaroundAllqueues none of its suite hooks. Nested scopes inherit that.runSuite()runs those hooks (docs/test/lifecycle.mdx:132). Files with noaroundAllare unchanged.test/js/bun/test/test-test.test.ts, 6 fail on main. Self-reviewed: 18 concerns raised, 18 addressed.Background
aroundAllwraps a file ordescribeblock. No stable release has it (bun test: Vitest compatibility #44833).bun:testrunsbeforeAllin a block of skipped tests (docs/test/writing-tests.mdx:508). Vitest and Jest do not.Downsides
afterAllin such a block stops running. A file-levelafterAllthat needs a gatedbeforeAllfails (exit 0 to 1).vitestortest.extend()beforeAllis left out beside abun:testhook that runs.describescope per file load. Release.text: 256 bytes smaller.Notes
The question
In a
describeblock or file that runs no test (every test skipped or todo, or no test), main decides for each suite hook alone. It leaves out three kinds of hook, and it runs a plainbun:testbeforeAll/afterAllbeside them or in a block nested below them.aroundAll, from any modulearoundAllexportbeforeAll/afterAllfrom"vitest"test.beforeAll/test.afterAllof atest.extend()testtest.extendaroundAllonly. NobeforeAll/afterAllruns inside anaroundAllthat does not run.docs/test/lifecycle.mdx:145stays as written and therunscell ofdocs/test/writing-tests.mdx:508gets "unless itsaroundAlldoesn't".aroundAllruns when abun:testhook inside it runs.writing-tests.mdx:508stays as written andlifecycle.mdx:145gets the exception. The new tests stay, with the expected logs changed.db.query()call into thearoundAll, register it as a secondaroundAll, or importbeforeAllfrom"vitest".generate_all_ordergoes away. I will add that to this PR. For row 2, A gives the output of 1.4.2 back and B runs no hook.Why now
aroundAllis in no stable release:git tag --contains 9e76acc6fbprints nothing. It is on main since 2026-10-31, so canary builds have it.aroundAll. After that release, A and B both change released behaviour.aroundAll: bun:test: hooks of a skippeddescribeare not tests #44832 says "Not changed: adescribewhose tests are alltest.skipstill runs itsbeforeAll/afterAll(bun:test: skip beforeAll/afterAll for describe blocks with no non-skipped tests #35497)". The test atvitest-flavor.test.ts:763pins it and still passes.Repros
Repro 1. main:
(fail) D > (unnamed),(pass) T, exit 1. This PR:(skip) D > S,(pass) T, exit 0.Repro 2. Exit 1 on main and on this PR, exit 0 on bun 1.4.2.
Repro 3. Exit 1 on main and on this PR.
The same as repro 1 on main, and fixed here: hooks in a block nested below the
aroundAll, a file-levelaroundAllover a file of skipped tests, anafterAllalone, a"vitest"aroundAlloverbun:testhooks, and anAsyncLocalStoragestore that readsundefinedinbeforeAll.What B changes besides the repro
A cleanup
afterAllinside a left-outaroundAllno longer runs, as under-t,.onlyanddescribe.skip. Node made the same change fornode:test(test_runner: do not invoke after hook when test is empty nodejs/node#51389, "do not invoke after hook when test is empty") and reverted it (Revert "test_runner: do not invoke after hook when test is empty" nodejs/node#51998).A
bun:testhook of an enclosing scope that has noaroundAllstill runs. This file exits 0 on main and 1 here. Withdescribe.skip("block", ...)and noaroundAllit exits 1 on bun 1.4.2 too.The gate also closes for a block with only
test.todoand for a block with no test.test.concurrenttests before and after a gated block share one concurrent group (5 queue groups become 1), as they do around a block with no hooks.References, run here
aroundAll,beforeAllorafterAllruns, nested blocks included. Repro 1 with the import changed to"vitest"passes.beforeAll/afterAllruns in a block or file whose tests are all skipped.node:teston Node 26.3.0:before()/after()run in a suite whose tests are all skipped.Measurements
Release builds of 2596ac5 and of this diff on it, from one build directory. The diff is the same after the rebase.
describe), +7.0 (describewithbeforeAll,afterAlland a skipped test) and +7.0 (the same with a test that runs) instructions perdescribescope, once per file load. Main-thread user instructions,BUN_JSC_useJIT=0, (I(10,000 scopes) - I(5,000 scopes)) / 5,000, minimum of 9 interleaved runs. The spread between runs is about 6 per scope.valgrindis not installed in the container and could not be installed, so the counts come from the hardware counter (perf_event_open)..text108,257,833 to 108,257,577 bytes.Order::enter_describe2,085 to 2,090 bytes,BunTest::run12,402 to 12,146 bytes, no other code symbol changed size (llvm-size -A, linker map). No struct field, allocation or queue entry is added.WANTS_LOUD=1), main to this PR: repro 1 3 to 2, the nested form 4 to 2, the file-level form 6 to 2, the"vitest"aroundAlloverbun:testhooks 4 to 2. A file that imports every name from"vitest": 10 to 10.aroundAll: the wholeWANTS_LOUD=1log (tree, queue and run, with addresses and times removed) is the same on both builds for thebun:testfixture of the test atvitest-flavor.test.ts:763(180 lines), for anode:testfile withbefore()/after()in skipped, todo and empty suites (566 lines, 11 of 11 hook lines), and for a"vitest"file (428 lines).Other open PRs
an aroundAll from "bun:test" doesn't run either if every test of its block is skipped) that expectslog: ["beforeAll", "afterAll"]for the block of repro 1. Under B that log is[]. The two PRs merge with no textual conflict, so the second one to land must make that edit. The clauseentry_box.around.is_some() ||that bun test: record each entry's module and decide its rules from it #48065 adds togenerate_all_orderhas no effect once both are in.docs/test/lifecycle.mdxandpackages/bun-types/test.d.tstoo.git merge-filegives 0 conflict hunks for both files.Where the tests are
In
test-test.test.ts, besidehooks of a describe block that does not run. That block and the test after it hold thebun:testrule for a block that runs no test. The otheraroundAlltests are invitest-flavor.test.ts. That file starts about 200bun testchildren, and on a debug build some of its tests reach the timeout of 5 seconds when the whole file runs, so it cannot show that a change passes.Suites run
On a debug build of this PR:
vitest-flavor.test.ts,test-test.test.ts,describe.test.ts,jest-hooks.test.ts,bun_test.test.ts,failure-skip.test.ts,nested-describes.test.ts,only-inside-only.test.ts,test-only.test.ts,test-on-test-finished.test.ts,concurrent.test.ts,vi-utils.test.ts,require-bun-test.test.ts,test-filter-lifecycle-snapshot.test.ts,node-test.test.ts, andtest/integration/bun-types/bun-types.test.tsfor the JSDoc line. No expectation of an existing test changes. The 7 new tests also pass when their child runs get--aot(the preload oftest/aot/runner-suites). Invitest-flavor.test.tsandvitest-apis.test.ts, some tests reach that timeout when the whole file runs on the debug build in this container, on main too. Each passes when it runs alone.no test proof · iteration 5 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/bun/test/test-test.test.ts