Skip to content

test(install): run bun-install-registry.test.ts concurrently and tighten its assertions - #38504

Open
robobun wants to merge 3 commits into
mainfrom
farm/f1ded6cf/speed-up-install-registry-test
Open

test(install): run bun-install-registry.test.ts concurrently and tighten its assertions#38504
robobun wants to merge 3 commits into
mainfrom
farm/f1ded6cf/speed-up-install-registry-test

Conversation

@robobun

@robobun robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • test/cli/install/bun-install-registry.test.ts is one of the slowest serial-phase files: 58-60s on windows 11 aarch64, ~53s on debian 13 x64-asan, 23s on windows 2019 x64, against 9-11s on the linux release lanes (expected-durations.json: default 10.1s, asan 47.9s, windows 22.1s).
  • Nearly all of that time is ~280 bun install/bun update spawns run one at a time: a module-level beforeEach assigned a shared packageDir/packageJson and mutated the shared env object, so no test could overlap with another. The per-test floor is one spawn (~150-200ms on a debug build), and ~120 of the cases (semver, prereleases, yarn, peer index, ...) are exactly one spawn each.
  • The Windows lanes additionally run the 44 Windows-only bin shim cases (describe("windows bin linking shim should work")), each of which spawns a chain of 2-3 processes; those were serial too, which is most of the gap between the Windows and Linux lanes.
  • A few assertions were weaker than they looked (details under Fix): one test was a no-op, one bun.lockb variant was silently testing bun.lock, one bun outdated assertion checked a misspelled package name, and a number of installs only checked the exit code.

Fix

  • Every test now starts with const { packageDir, packageJson, env } = await setupTest(), which wraps the same registry.createTestDir() call the beforeEach made and returns an env whose cache/tmp dirs live inside that directory. The beforeEach and the module-level packageDir/packageJson/env/users are gone, so tests share nothing but the (read-only) registry. This is the same shape bun-install-lifecycle-scripts.test.ts and bun-workspaces.test.ts already use.
  • With that, the describes become describe.concurrent and the top-level tests test.concurrent. Describe-scoped helpers that read the module variables (runBin, checkHoistedFiles/checkUnhoistedFiles, setupWorkspace, installAndCaptureAuth) take the directory/env as parameters instead. No test is deleted, skipped, or renamed; two tests that looped over independent cases are split into one test per case under a describe with the old name (update > exact versions stay exact > a-dep|aliased, update > update different dependency groups > ...), which is where the +8 in the test count comes from.
  • Kept serial, and marked serial so the choice is visible: the whoami tests (they register registry users, and createTestDir() deletes the registry's htpasswd file, so an overlapping test would log the other one out; "rejects npm aliases ..." also registered a user, but its request is refused before anything is sent, so it uses a literal token now, like the test after it, and runs concurrently); the 16 tests that use toMatchSnapshot() (bun rejects external snapshots inside concurrent tests; the outdated tables contain ANSI escapes and are not worth inlining); and hoisting > peers, whose outcome depends on manifest arrival order (test(install): mark "peer *" hoisting case todoIf(isFlaky) #33972, install: resolve deferred * peers after their siblings, not on arrival order #37713), so it keeps running against an idle registry rather than one serving 20 installs. The Windows shim tests only execute bins from one install made at collection time, so they share it and run concurrently.
  • Two things the shared registry/temp state still needed once tests overlap (both found by running this on Windows):
    • createTestDir() deletes the registry's htpasswd file, and when a concurrent group starts every test in it calls setupTest() at once. On Windows, concurrent rm(file, { force: true }) of the same file rejects with EFAULT (bun bug, reproduced standalone and reported separately; node resolves all of them), which is what failed in the first CI run on windows 11 aarch64 in the test right after the whoami block. setupTest() therefore chains the createTestDir() calls through a promise; each one takes a few milliseconds, and the Linux timings below are unchanged. bun-workspaces.test.ts and bun-install-lifecycle-scripts.test.ts have the same latent race.
    • bun --bun creates its fake node.exe under %TEMP%, and debug builds wipe and recreate that directory on every run (create_fake_temporary_node_executable in src/install/lib.rs), so concurrent --bun shim tests occasionally got a debug-only SHARING_VIOLATION warning on stderr, which these tests assert is empty (about 1 run in 6 with a Windows debug build; release builds, i.e. the CI lanes, never wipe the directory). Each --bun shim test now gets its own TMP/TEMP directory, so nothing is shared; 12 of 12 debug runs of the block were clean afterwards, and the fake node.exe shows up inside the per-test directory, so the --bun path is still exercised.
  • Why this is safe: each test only touches its own directory, its own cache (install.cache in its bunfig plus BUN_INSTALL_CACHE_DIR/TMPDIR in its env), and its own port: 0 mock servers; the registry is only read. Bun's default --max-concurrency (20, or 5 in ASAN builds, src/options_types/context.rs) bounds how many are in flight, the same as in the other concurrent install files. setDefaultTimeout is left at 5 minutes on purpose: a concurrent test's wall time now includes waiting on its 19 neighbours, so it should not be tightened in the same change.
  • Slowest cases before (debug+ASAN, serial) and what happened to each:
    • "it should install with missing bun.lockb, node_modules, and/or cache" (2.6s, 14 sequential installs; the 10-iteration loop is deliberate per its comment): unchanged internally, now overlaps with the rest of its group.
    • "update > exact versions stay exact" (1.6s, 2 x 4 runs) and "update > update different dependency groups" (1.5s, 8 runs): split into 2 and 8 independent cases that run concurrently, each now asserting the bun update output (and, for the groups, the installed version).
    • "binaries > bin types" (1.3s): the six bun <bin> checks were sequential; they run under Promise.all now (0.5s) and the bun add summary is asserted.
    • "transitive file dependencies > from (non-)hoisted workspace dependencies" (1.1s each): only blocked on the helpers reading the module variable; now concurrent, and the final reinstall in each also checks the files.
    • the long tail of ~120 one-spawn cases (semver 19, prereleases 43, yarn 15, peerDependency index 7, certificate authority 8, ...) and the 44 Windows shim cases: concurrent.
    • the beforeEach itself: it also ran two Bun.$ rms of paths that do not exist (the real htpasswd is removed by createTestDir()); dropping it took the runner's own CPU time on the debug build from 23s to 18s.
  • Assertion changes:
    • "disabled dev/peer/optional dependencies are still included in the lockfile" did await runBunInstall; (the function object) and asserted nothing. It now installs with --omit=dev --omit=peer --omit=optional, checks that nothing is installed but all three packages are in bun.lock, and that a plain install then installs all three from that lockfile without re-saving it.
    • bundledDependencies: the 20 installs had stdout/stderr: "ignore" and checked the exit code. They now go through two small helpers that assert stderr, Saved lockfile, that the lockfile flavor named in the test title was actually written, and that the second install reports (no changes). The flavor check exposed that "(bun.lockb) git dependencies" wrote a bun.lock: its private bunfig (needed because the git packages depend on zod, which the local registry does not have) predates bun.lock becoming the default and lacked saveTextLockfile = false; fixed.
    • outdated > dependency pattern args asserted not.toContain("prerelease-1"); the package is prereleases-1, so the assertion could never fail. Fixed, and it holds.
    • hoisting > peers: the second and third installs asserted not.toContain("package installed"), which a multi-package reinstall never prints; they now assert the lockfile-less re-resolve reports (no changes) and that the reinstall lists every root dependency. A leftover console.log of stdout is gone.
    • semver (19 cases): also checks the installed node_modules/dep-with-tags/package.json, like the prerelease cases already did.
    • package.json indentation (one spawn was stdio: "inherit"), --config cli flag works, "it will skip ... directories.bin does not exist", transitive file dependencies > from root dependencies: install output and resulting node_modules are asserted instead of just the exit code. The outdated edge cases read stdout/stderr before the exit code.
    • auto-install's 4-line snapshot is inlined; the file-local copy of generateRegistryUser delegates to registry.generateUser (same duplicate-name guard, reset by createTestDir()); the runBin helper reports which bin failed.
  • Verification (the runs alternate baseline and this branch on the same machine; the debug build stands in for the slow lanes):
    • linux x64, debug+ASAN, bun bd test test/cli/install/bun-install-registry.test.ts: before 89.5s / 89.7s / 90.2s (238 tests, 3184 expect calls); after 35.8s / 36.9s / 35.8s (246 tests, 3357 expect calls). Eight further runs of the new file (the last three with the chained setupTest()): 36.0-40.2s, all green (shared machine, hence the spread).
    • windows x64 (Server 2019), debug build of the same source: before 122.9s (282 tests); after 32.1-32.7s across seven full runs (290 tests), plus the 12 runs of the shim block mentioned above. CI durations are only comparable between PR builds, because the runner puts a touched file at the front of its shard (position 3, while the docker prestart is still running), which inflates it; against build 95342 (install(hoisted): track replaced folders instead of deferring and re-verifying nested skips #38303, which touches this file but leaves it serial, same position) this PR's build 96080 measured: x64-asan 55.2s -> 24.1s, windows 11 aarch64 63.3s -> 36.5s (46.8s on the attempt that hit the peer * flake), alpine x64 27.2s -> 17.5s, windows 2019 x64 30.0s -> 23.5s, debian x64 15.8s -> 14.1s. The release lanes gain less than the local runs because they have 4 vCPUs and, with the tests themselves cheap there, the single-threaded verdaccio process serving every install is most of what is left; the asan lane also only runs 5 tests at a time. One test fails on Windows with a debug build before and after this change ("npm manifest cache entries are only reused for the package name they were saved for", from Robustness and input-handling pass across install, shell, TLS/QUIC, HTTP/3, SQL and crypto #37669; it passes on the release Windows lanes); test(install): don't require the refetched manifest to be cached before install exits #38580 fixes that test on main, and the lines it touches are identical here, so the two do not conflict.
    • tsc over the file reports the same pre-existing diagnostics as before and nothing new; prettier is clean.
  • Not changed, for the record: the two git dependencies cases still fetch from github.com and resolve zod from registry.npmjs.org, and "manifest cache will invalidate when registry changes" still uses the public registry for its second install; making those hermetic is a separate change. VerdaccioRegistry.stop() leaving the registry process behind is test(harness): make VerdaccioRegistry.stop() actually terminate the process #36352. Once install: resolve deferred * peers after their siblings, not on arrival order #37713 lands, hoisting > peers can drop its describe.serial. The natural follow-up, kept out of this PR because test: replace verdaccio and the mock npm servers with an in-process spec-compliant registry #33115 and test(harness): make VerdaccioRegistry.stop() actually terminate the process #36352 are both reshaping that class, is to have createTestDir() itself return the per-directory env and stop deleting htpasswd (start()/stop() already do), which would replace setupTest() here and the identical blocks in bun-install-lifecycle-scripts, bun-workspaces and bun-install-native-binlink, remove the chaining, and make the remaining serial verdaccio files (isolated-install, bun-publish, bun-lock, catalogs, bun-lockb, public-hoist-pattern, pnpm-migration) a mechanical conversion.

Background

  • Concurrent groups: bun runs consecutive test.concurrent tests (including across describe boundaries) as one group with up to --max-concurrency (20; 5 in ASAN builds) in flight; a serial test waits for the group to drain and runs alone. So each serial holdout costs its own duration plus one drain; the remaining serial stretches are the whoami block, the outdated snapshot block, hoisting > peers, and the individual snapshot tests.
  • describe.concurrent marks every test declared inside it (including nested describes) concurrent; test.serial / describe.serial inside it opt individual tests back out. This keeps the per-test headers unchanged for tests inside describes, which is what keeps this diff mostly to one added line per test.
  • registry.createTestDir() (test/harness.ts) makes a fresh temp directory with a bunfig.toml pointing at the file's single verdaccio instance (started once at module load, as before) and resets the registry's htpasswd file; setupTest() is a thin wrapper that adds the per-directory env.
  • toMatchSnapshot() stores snapshots by test name in a shared .snap file and is rejected inside concurrent tests; toMatchInlineSnapshot() is allowed, which is why the one small snapshot was inlined and the others stayed serial.
  • The serial-phase note: the CI runner executes regular test files one at a time, so a file's own wall time adds directly to its shard, and concurrency inside the file uses cores that are otherwise idle.

…ten its assertions

Every test now creates its own project directory and env through setupTest()
instead of sharing the ones assigned by a module-level beforeEach, which lets
the describes run as describe.concurrent. Tests that use toMatchSnapshot(),
register registry users, or depend on manifest arrival order (hoisting > peers)
are marked serial. The 44 Windows-only bin shim tests share their read-only
install and run concurrently as well.

While there:
- "disabled dev/peer/optional dependencies are still included in the lockfile"
  awaited the runBunInstall function object and asserted nothing; it now installs
  with all three groups omitted and checks the lockfile and the reinstall.
- the "(bun.lockb) git dependencies" case wrote a bun.lock because its bunfig
  dropped saveTextLockfile = false; bundledDependencies installs now assert the
  lockfile flavor, the install output, and that the reinstall is a no-op.
- "exact versions stay exact" and "update different dependency groups" become
  one test per case with the update output asserted.
- bin types runs its six bins concurrently and asserts the add summary; outdated
  "dependency pattern args" asserted on a misspelled package name; several
  installs that only checked the exit code now check their output and the
  resulting node_modules; the peers loop asserts the re-resolve is a no-op.
- the auto-install snapshot is inlined and the duplicated generateRegistryUser
  delegates to the registry helper.
@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Review was skipped as selected files did not have any reviewable changes.

💤 Files selected but had no reviewable changes (1)
  • test/cli/install/bun-install-registry.test.ts
⛔ Files ignored due to path filters (1)
  • test/cli/install/__snapshots__/bun-install-registry.test.ts.snap is excluded by !**/*.snap
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0cb586cd-9eb3-477d-913e-3d4c33d8df89

📥 Commits

Reviewing files that changed from the base of the PR and between 5a34f8d and bb64645.

⛔ Files ignored due to path filters (1)
  • test/cli/install/__snapshots__/bun-install-registry.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • test/cli/install/bun-install-registry.test.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 6:43 AM PT - Aug 14th, 2026

@robobun, your commit de573e4 is building: #96080

@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

Status: test-only change, ready for review (head: bb64645).

Reproduced the slowness locally: bun bd test test/cli/install/bun-install-registry.test.ts (debug+ASAN) took 89.5-90.2s on main across three interleaved runs and 36-40s on this branch; a Windows x64 debug build went from 122.9s to 32.1-32.7s across seven runs.

CI, compared at the same shard position against build 95342 (a PR that touches this file but leaves it serial): x64-asan 55.2s -> 24.1s, windows 11 aarch64 63.3s -> 36.5s, alpine x64 27.2s -> 17.5s, windows 2019 x64 30.0s -> 23.5s, debian x64 15.8s -> 14.1s. The 4-vCPU release lanes gain less than the local runs because the single-threaded verdaccio process becomes the floor there; details in the description.

Commits after the first CI run: de573e4 chains the createTestDir() calls (concurrent rm of the registry's htpasswd file rejects with EFAULT on Windows, a bun bug reported separately) and gives the --bun shim tests their own TEMP; bb64645 makes the alias host-pinning test concurrent by using a literal token. No CI job has failed since; the only entry for this file is the pre-existing peer * flake (#33972, fixed by #37713), which shows up in 3 of the last 12 main builds and stays serial here.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reviewed this PR and didn't find any bugs. Because it's a large refactor (~250 tests moved to concurrent execution) whose correctness depends on per-platform CI behavior, a human look — mainly confirming BuildKite is green across the Windows and ASAN lanes — would still be worthwhile.

What was reviewed:

  • Checked that every test that mutates shared registry state (generateRegistryUser, htpasswd) is kept .serial, and that createTestDir()'s this.users = {} reset can't race with them since serial tests drain the concurrent group first.
  • Verified test.serial.todo / test.serial.todoIf / describe.concurrent.each chain correctly per the Test<T>/Describe<T> types.
  • Confirmed registry.generateUser in harness.ts matches the deleted local copy's contract (duplicate-name guard, same endpoint).
  • Spot-checked the tightened assertions (prereleases-1 typo fix, the no-op await runBunInstall; rewrite, the saveTextLockfile: false fix for the bun.lockb git test) against the surrounding code.
Extended reasoning...

Overview

This PR refactors test/cli/install/bun-install-registry.test.ts (~9700 lines, ~280 tests) from serial to concurrent execution and tightens a number of weak assertions along the way. The mechanical part is: delete the module-level beforeEach/packageDir/packageJson/env, add a setupTest() helper that returns per-test copies, insert const { packageDir, packageJson, env } = await setupTest() at the top of every test, and switch describedescribe.concurrent / testtest.concurrent. The non-mechanical parts are assertion tightening (fixing a no-op test, a misspelled package name, a wrong-lockfile-flavor bunfig, several exit-code-only checks) and splitting two looped tests into test.each cases. The snapshot file drops one entry that was inlined. No production code is touched.

Security risks

None. This is a test-only change with no production code paths, no auth/crypto/permissions logic, and no new external network access (the pre-existing github.com/npmjs.org fetches are explicitly called out as unchanged).

Level of scrutiny

Medium. The change is test-only, so the blast radius is CI, not user-facing behavior. The mechanical portion (~200 identical one-line insertions plus describe.concurrent markers) is low-risk and follows the same pattern already used in bun-install-lifecycle-scripts.test.ts and bun-workspaces.test.ts. The higher-risk portion is whether concurrent execution introduces flakiness on specific CI lanes (Windows shim tests, ASAN timing, Verdaccio under 20 concurrent installs). The PR description shows local verification on linux debug+ASAN and Windows Server 2019 debug, but the real signal is BuildKite across all lanes, which was still building when this review ran.

Other factors

  • The PR description is unusually thorough: it enumerates every serial holdout with a stated reason, every assertion change with what it exposed, and before/after timings on two platforms. This substantially reduces review burden.
  • The concurrency-safety argument checks out: each test gets its own temp dir, its own BUN_INSTALL_CACHE_DIR/TMPDIR, and its own port: 0 servers; the only shared resource is the read-only Verdaccio registry. Tests that write to the registry (user registration → htpasswd) are all kept .serial, and createTestDir()'s reset of registry.users on the shared instance is harmless because concurrent tests never call generateUser() and serial tests drain the concurrent group before running.
  • The assertion tightening is exactly what REVIEW.md asks for (assert exact values, assert the strongest invariant, no vacuous not.toContain on a misspelling). These are strict improvements.
  • The Windows shim describe now uses bunEnv directly instead of the (now-removed) mutated module-level env; the shared install happens once at collection time and the 44 tests only exec bins from it, so sharing that directory is safe.
  • Given the ~800-line diff size and the fact that concurrency flakiness typically only surfaces on specific CI configurations, deferring so a human can confirm BuildKite is green across all lanes before merging.

…their own TEMP

Concurrent rm() of the registry's htpasswd file rejects with EFAULT on
Windows, and concurrent --bun runs share the fake node directory in TEMP.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reviewed this PR and didn't find any bugs. Because it's a large refactor (~280 tests moved to concurrent execution, per-test state isolation, and a dozen or so tightened assertions), a human look would still be worthwhile — particularly to confirm the new exact-output assertions hold across all CI lanes.

What was reviewed:

  • setupTest() promise-chaining: reads/writes previousSetup before the first await, so concurrent callers chain deterministically; rejection is swallowed so one failure doesn't poison the chain.
  • Serial holdouts (whoami, snapshot tests, hoisting > peers, npm-alias auth test) each have a stated reason; registry.generateUser matches the removed local copy.
  • Tightened assertions spot-checked (bundledDependencies helpers, rewritten "disabled dev/peer/optional" test, prereleases-1 typo fix, --config output) — all look consistent with the fixture packages.
Extended reasoning...

Overview

Test-only change to test/cli/install/bun-install-registry.test.ts and its .snap file. The module-level beforeEach and shared packageDir/packageJson/env are replaced with a per-test setupTest() helper, describes become describe.concurrent, and helpers that closed over the module state now take explicit parameters. Two loop-over-cases tests are split into test.each/nested describes, one no-op test is rewritten, and roughly a dozen tests gain stronger assertions on stdout/stderr/lockfile/node_modules.

Security risks

None. No production code is touched; the only runtime effect is on the test file itself.

Level of scrutiny

Moderate-to-high. The mechanical bulk (adding await setupTest() and .concurrent) is low-risk, but the non-mechanical parts warrant a human pass: the previousSetup chaining for Windows EFAULT avoidance, the per-test TMP/TEMP for the --bun shim tests, and the tightened exact-output assertions (e.g. the new bun add summary in "bin types", the (no changes) regex in expectReinstallIsNoop, the rewritten "disabled dev/peer/optional" test). Any of these could be subtly over-tight on a lane the author didn't run.

Other factors

  • Follows the same shape as bun-install-lifecycle-scripts.test.ts and bun-workspaces.test.ts, which the description cites.
  • Verification is thorough (multiple Linux debug+ASAN and Windows debug runs, before/after timings, CI run in progress).
  • No tests are deleted or skipped; the +8 test count is accounted for by the two split loops.
  • The .snap change only removes the one snapshot that was inlined.
  • installAndCaptureAuth now calls setupTest() internally, so its describe-level tests each get their own dir — checked that nothing else in that describe reads a shared packageDir.

@robobun

robobun commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

The Windows debug-build failure of "npm manifest cache entries are only reused for the package name they were saved for" mentioned under Verification is addressed in #38580 (test-only: the final assertion no longer requires the background manifest cache write to have landed before the install exits). The lines it changes are identical in this branch and main, so whichever of the two lands second rebases trivially.

…it can run concurrently

The request is refused before anything is sent, so registering a registry
user (which kept the test serial) was not needed.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I reviewed this PR and didn't find any bugs. It's a test-only refactor that follows the same per-test setupTest() + describe.concurrent pattern already used in bun-install-lifecycle-scripts.test.ts and bun-workspaces.test.ts, with an unusually thorough writeup and 18+ green runs across Linux and Windows. Because it flips ~280 tests to concurrent and tightens a number of stdout assertions in one go, a human skim would still be worthwhile before merging.

What was reviewed:

  • setupTest() chaining via previousSetup — a rejected createTestDir() doesn't poison later calls (both handlers are no-ops), and createTestDir() resets this.users, so the generateRegistryUser delegation is safe.
  • Serial holdouts (whoami, snapshot tests, hoisting > peers) are correctly opted out via test.serial/describe.serial; the alias host-pinning test was made concurrent by switching to a literal token (last commit).
  • Tightened assertions checked for order-sensitivity — hoisting > peers reinstall uses per-dep toContain (order-agnostic); bin types summary follows the fixed bun add argument order.
  • The Windows --bun shim tests get a per-test TMP/TEMP and share one install directory built at collection time, so concurrency there only affects bin execution, not the install.
Extended reasoning...

Overview

This PR converts test/cli/install/bun-install-registry.test.ts (~280 tests, ~9,700 lines) from a serial beforeEach-driven file to a concurrent one where each test calls await setupTest() for its own packageDir/packageJson/env. Along the way it strengthens a handful of weak or vacuous assertions (a no-op await runBunInstall;, a misspelled prerelease-1 check, a bun.lockb case that was silently writing bun.lock, several installs that only checked exit code), splits two loop-over-cases tests into test.each, inlines one snapshot, and removes the corresponding entry from the .snap file. No production code is touched.

Security risks

None. The change is confined to test infrastructure and assertions. No auth, crypto, permissions, or user-facing code paths are modified. The one auth-adjacent change (the alias host-pinning test now uses a literal token instead of registering a Verdaccio user) is safe because the test asserts the request is refused before it's sent, so token validity is irrelevant.

Level of scrutiny

Moderate. This is a test-only change, so it can't break users, but it flips a large test file to concurrent execution, which is exactly the kind of change that can introduce CI flakiness that only surfaces on specific lanes under load. The mitigations are well thought out: per-test cache/tmp directories, chained createTestDir() calls to avoid the Windows htpasswd rm race, per-test TEMP for --bun shim tests, and explicitly serial blocks for the tests that share registry state (whoami) or are order-sensitive (hoisting > peers) or use file snapshots. The 11 Linux debug+ASAN runs and 7 Windows debug runs plus green CI give reasonable confidence, but a maintainer familiar with the flakiest lanes (macOS, Windows aarch64) should confirm they're comfortable with the tightened stdout assertions.

Other factors

The pattern matches sibling files (bun-install-lifecycle-scripts.test.ts, bun-workspaces.test.ts) that already went through this conversion. The bug hunting system found nothing. registry.generateUser and test.serial/describe.serial exist in the harness/runner. The previousSetup promise chain correctly swallows rejections so one failed setup doesn't wedge every subsequent test. The tightened assertions I spot-checked are either order-agnostic (toContain per item) or follow deterministic ordering (argument order for bun add, lockfile section order for the omit test). Nothing is deleted or skipped; the +8 test count is explained by the two split loops. Given the sheer size of the diff and its potential to affect CI stability across many lanes, I'm deferring rather than approving.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant