test: keep --watch alive when --bail stops a run

Closed
RO
2mo ago
+116-5

What

bun test --watch --bail exits the whole watch process on the first bail-out. The edit that would fix the failing test never re-runs. Without --bail the same watcher survives and reruns on the next edit.

Repro

mkdir d && cd d
cat > b.test.ts <<'EOF'
import { test, expect } from "bun:test";
import { v } from "./v";
test("t1", () => { expect(v).toBe(1); });
test("t2", () => { expect(2).toBe(2); });
EOF
echo 'export const v = 0;' > v.ts
echo '{}' > package.json
bun test --watch --bail
# => prints 'Bailed out after 1 failure' and exits 1 instead of watching

Cause

CommandLineReporter::handle_test_completed calls Global::exit(1) directly when the fail count reaches the bail threshold, inside the per-test completion callback. Under --watch that kills the process before control reaches run_event_loop_for_watch. The module-load-rejection bail path in TestCommand::run has the same hard exit.

The parallel coordinator already handles this correctly: it sets a bailed flag and drains, returning normally.

Fix

Give the serial runner the same flag-based bail:

  • Execution.aborted stops the step loops (step_group, step_group_one, step's per-group loop) so no further tests in the current file run.
  • CommandLineReporter.bailed stops the per-file loop in run_all_tests and the --rerun-each repeat loop in TestCommand::run.

Under --watch the bail path now prints the banner, sets the flags, and lets the run unwind back to exec, which prints the full summary and enters run_event_loop_for_watch. When the watched file changes, reload_process re-execs as before. When not watching, the existing Global::exit(1) is unchanged.

Verification

# fail-before (released bun): process exits, never sees the fixing edit
USE_SYSTEM_BUN=1 bun test test/cli/test/bun-test.test.ts -t 'keeps watching after a bail'
# pass-after
bun bd test test/cli/test/bun-test.test.ts -t bail

The test spawns bun test --watch --bail with a failing test, waits for the bail banner and the end-of-run summary on stderr, then fixes the dep file and waits for 2 pass from the re-run. Skipped on Windows where --watch uses a respawning parent instead of exec-in-place (same as the existing --changed --watch test).


no test proof · iteration 2 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/cli/test/bun-test.test.ts

Supersedes #19918 (same approach against the pre-Rust Zig sources, which no longer exist).

Fixes #20318
Fixes #6453