Skip to content

fix: stop test teardowns from silently killing the bun test run#2172

Open
sneakygriff wants to merge 1 commit into
garrytan:mainfrom
sneakygriff:fix/test-suite-silent-early-exit
Open

fix: stop test teardowns from silently killing the bun test run#2172
sneakygriff wants to merge 1 commit into
garrytan:mainfrom
sneakygriff:fix/test-suite-silent-early-exit

Conversation

@sneakygriff

Copy link
Copy Markdown

Problem

Several browse/ and design/ test files armed setTimeout(() => process.exit(0), 500) inside afterAll — a workaround for a browser close() that can hang. That assumes each test file runs in its own process. It doesn't: bun test runs every file in one shared process. The 500ms timer therefore fired partway through a later test file and terminated the entire run with exit code 0 and no summary.

Because the exit code was 0, the suite could not gate: only a fraction of the files ran, and every downstream failure was silently masked.

Fix

  • Remove the delayed process.exit from teardown; instead time-box resource cleanup. Browser teardowns race close() against a short timeout and abandon it if it hangs (the child is reaped at real process exit). The design daemon /shutdown test stubs process.exit around the shutdown timers so they fire harmlessly.
  • Add test/no-suicide-exit.test.ts, a static guard that scans every *.test.ts and fails if any file schedules a delayed process.exit, so the pattern cannot silently return.
  • Make test/user-slug-fallback.test.ts deterministic via HOME isolation.

Verification

  • bun test test/no-suicide-exit.test.ts test/user-slug-fallback.test.ts15 pass, 0 fail (guard green + slug 14/14).
  • bun test browse/test/commands.test.ts243 pass, 0 fail, now runs to a full summary.
  • bun test design/test/daemon.test.ts34 pass, 0 fail, no early exit.

Honest note

With the suite now able to run to completion, it surfaces pre-existing failures that the early exit had been hiding — for example design/test/feedback-roundtrip.test.ts fails identically on unmodified origin/main (a session.clearLoadedHtml stub gap), independent of this change. Those failures are not introduced by this PR; this change only makes them visible so they can be gated on and fixed in follow-ups.

🤖 Generated with Claude Code

Several browse and design test files armed `setTimeout(() => process.exit(0),
500)` inside afterAll as a workaround for a browser close() that can hang. That
assumes each test file runs in its own process. It doesn't: `bun test` runs
EVERY file in one shared process. The 500ms timer therefore fired partway
through a LATER test file and terminated the entire run with exit code 0 and no
summary. Because the exit code was 0, the suite could not gate — only a fraction
of the files ran, and every downstream failure was silently masked.

The fix removes the delayed process.exit from teardown and instead time-boxes
the resource cleanup: browser teardowns race `close()` against a short timeout
and abandon it if it hangs (the child is reaped at real process exit), and the
design daemon /shutdown test stubs `process.exit` around the shutdown timers so
they fire harmlessly. A new static-guard test, test/no-suicide-exit.test.ts,
scans every *.test.ts and fails if any file schedules a delayed process.exit,
so the pattern cannot silently return. test/user-slug-fallback.test.ts is made
deterministic via HOME isolation.

Verified: test/no-suicide-exit.test.ts + test/user-slug-fallback.test.ts pass
(15/15); browse/test/commands.test.ts passes standalone (243/243) and now runs
to a full summary; design/test/daemon.test.ts passes (34/34) with no early exit.

Honest note: with the suite now able to run to completion, it surfaces
pre-existing failures that the early exit had been hiding — e.g.
design/test/feedback-roundtrip.test.ts fails identically on unmodified
origin/main (a `session.clearLoadedHtml` stub gap), independent of this change.
These are not introduced here; this change only makes them visible so they can
be gated on and fixed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@trunk-io

trunk-io Bot commented Jul 4, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

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.

1 participant