Skip to content

Conversation

robobun
Copy link
Collaborator

@robobun robobun commented Oct 6, 2025

Summary

Adds a new --only-failures flag to bun test that only displays test failures, similar to --dots but without printing dots for each test.

Motivation

When running large test suites or in CI environments, users often only care about test failures. The existing --dots reporter reduces verbosity by showing dots, but still requires visual scanning to find failures. The --only-failures flag provides a cleaner output by completely suppressing passing tests.

Changes

  • Added --only-failures CLI flag in Arguments.zig
  • Added only_failures boolean to the test reporters struct in cli.zig
  • Updated test output logic in test_command.zig to skip non-failures when flag is set
  • Updated jest.zig and bun_test.zig to handle the new flag
  • Added comprehensive tests in only-failures.test.ts

Usage

bun test --only-failures

Example output (only shows failures):

test/example.test.ts:
(fail) failing test
error: expect(received).toBe(expected)

Expected: 3
Received: 2

5 pass
1 skip
2 fail
Ran 8 tests across 1 file.

Test Plan

  • Verified --only-failures flag only shows failing tests
  • Verified normal test output still works without the flag
  • Verified --dots reporter still works correctly
  • Added regression tests with snapshot comparisons

🤖 Generated with Claude Code

This flag only displays test failures, similar to --dots but without
printing dots for each test. This is useful for CI environments or when
running large test suites where you only care about failures.

Usage:
  bun test --only-failures

The flag works by:
- Suppressing output for passing, skipped, and todo tests
- Only showing full error details for failing tests
- Still showing the final test summary with pass/fail counts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@robobun
Copy link
Collaborator Author

robobun commented Oct 6, 2025

Updated 5:20 PM PT - Oct 8th, 2025

@pfgithub, your commit b28d83c has 1 failures in Build #28586 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 23312

That installs a local version of the PR into your bun-23312 executable, so you can run:

bun-23312 --bun

@github-actions github-actions bot added the claude label Oct 6, 2025
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

Walkthrough

Adds an --only-failures reporter mode and wires it through CLI args and bunfig parsing, TestCommand reporter state, and bun.js test reporters; updates reporter conditionals to suppress non-failure output and dot printing; and adds fixtures and tests validating the behavior.

Changes

Cohort / File(s) Summary of changes
CLI options & config
src/cli.zig, src/cli/Arguments.zig, src/bunfig.zig
Added reporters.only_failures: bool = false to TestOptions, added --only-failures CLI flag handling, and added parsing support for test.onlyFailures in bunfig.
CLI test reporter behavior
src/cli/test_command.zig
Added only_failures to CommandLineReporter.reporters (default false) and updated per-test printing, completion logic, and dot-queuing to suppress non-failure output when only_failures is true; TestCommand.exec propagates the flag from CLI/bunfig or AI-agent detection.
bun.js test reporters
src/bun.js/test/bun_test.zig, src/bun.js/test/jest.zig
Updated conditionals to treat reporter.reporters.only_failures similarly to dots (removed AI-agent-specific checks), changing when error messages are printed, when last_printed_dot is reset, and when early returns/clears occur.
Tests & fixtures
test/js/bun/test/only-failures.fixture.ts, test/js/bun/test/only-failures.test.ts
Added fixture with passing/failing/skip/todo tests and test suites that spawn Bun with --only-failures or bunfig config; new tests assert exit codes and that only failing tests are shown.
Documentation
docs/runtime/bunfig.md
Documented test.onlyFailures, plus test.reporter.dots and test.reporter.junit entries, with TOML examples and notes that test.onlyFailures corresponds to --only-failures.

Possibly related PRs

  • bun test dots reporter #22919 — Extends reporters API with an only_failures flag and updates conditionals in the same test/CLI code paths (e.g., jest.zig, bun_test.zig, test_command.zig).

Suggested reviewers

  • Jarred-Sumner
  • nektro

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The description does not follow the required template headings and structure, as it uses custom sections like “## Summary” and “## Test Plan” instead of the mandated “### What does this PR do?” and “### How did you verify your code works?”. Please update the pull request description to include the required template sections with the exact headings “### What does this PR do?” and “### How did you verify your code works?” and migrate the existing content under those sections accordingly.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly describes the primary change of adding a new CLI flag (--only-failures) to the bun test command and is both clear and focused on the main change without extraneous detail.

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
test/js/bun/test/only-failures.test.ts (1)

59-79: Consider using inline snapshots for consistency.

The multi-file test uses manual assertions instead of snapshots. For consistency and better maintainability, consider using toMatchInlineSnapshot() or toMatchSnapshot() to capture the full output, similar to the first test.

Apply this diff to use inline snapshots:

-  expect(exitCode).toBe(1);
-  expect(normalizeBunSnapshot(stderr)).toContain("(fail) failing test");
-  expect(normalizeBunSnapshot(stderr)).toContain("(fail) another failing test");
-  expect(normalizeBunSnapshot(stderr)).not.toContain("(pass)");
+  expect({
+    exitCode,
+    stderr: normalizeBunSnapshot(stderr),
+  }).toMatchInlineSnapshot();

Then update the snapshot to capture the expected output. This provides better documentation and catches unexpected output changes.

src/cli/test_command.zig (1)

904-904: Consider optimizing the repeat buffer printing logic.

The logic correctly prevents queueing output when only_failures is true. However, the repeat buffer printing at lines 1532-1563 doesn't explicitly check only_failures, so it will attempt to print from empty buffers when the flag is set. While harmless, you could optimize by adding and !reporter.reporters.only_failures to the condition at line 1532.

Apply this diff to optimize the repeat buffer printing:

-        if (reporter.summary().pass > 20 and !Output.isAIAgent() and !reporter.reporters.dots) {
+        if (reporter.summary().pass > 20 and !Output.isAIAgent() and !reporter.reporters.dots and !reporter.reporters.only_failures) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fc9db83 and ebecc68.

📒 Files selected for processing (7)
  • src/bun.js/test/bun_test.zig (1 hunks)
  • src/bun.js/test/jest.zig (1 hunks)
  • src/cli.zig (1 hunks)
  • src/cli/Arguments.zig (2 hunks)
  • src/cli/test_command.zig (3 hunks)
  • test/js/bun/test/only-failures.fixture.ts (1 hunks)
  • test/js/bun/test/only-failures.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
src/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)

Implement debug logs in Zig using const log = bun.Output.scoped(.${SCOPE}, false); and invoking log("...", .{})

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: In Zig source files, place all @import statements at the bottom of the file
Use @import("bun") instead of @import("root").bun when importing Bun in Zig

Files:

  • src/bun.js/test/bun_test.zig
  • src/cli.zig
  • src/cli/test_command.zig
  • src/cli/Arguments.zig
  • src/bun.js/test/jest.zig
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/bun.js/test/bun_test.zig
  • src/cli.zig
  • src/cli/test_command.zig
  • src/cli/Arguments.zig
  • src/bun.js/test/jest.zig
src/bun.js/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)

src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy

Files:

  • src/bun.js/test/bun_test.zig
  • src/bun.js/test/jest.zig
test/**

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

Place all tests under the test/ directory

Files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
test/js/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

Place JavaScript and TypeScript tests under test/js/

Files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
test/js/bun/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

Place Bun API tests under test/js/bun/, separated by category (e.g., test/js/bun/glob/)

Files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
test/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

test/**/*.{js,ts}: Write tests in JavaScript or TypeScript using Bun’s Jest-style APIs (test, describe, expect) and run with bun test
Prefer data-driven tests (e.g., test.each) to reduce boilerplate
Use shared utilities from test/harness.ts where applicable

Files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
test/**/*.test.ts

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.ts: Name test files *.test.ts and use bun:test
Do not write flaky tests: never wait for arbitrary time; wait for conditions instead
Never hardcode port numbers in tests; use port: 0 to get a random port
When spawning Bun in tests, use bunExe() and bunEnv from harness
Prefer async/await in tests; for a single callback, use Promise.withResolvers()
Do not set explicit test timeouts; rely on Bun’s built-in timeouts
Use tempDir/tempDirWithFiles from harness for temporary files and directories in tests
For large/repetitive strings in tests, prefer Buffer.alloc(count, fill).toString() over "A".repeat(count)
Import common test utilities from harness (e.g., bunExe, bunEnv, tempDirWithFiles, tmpdirSync, platform checks, GC helpers)
In error tests, assert non-zero exit codes for failing processes and use toThrow for synchronous errors
Use describe blocks for grouping, describe.each for parameterized tests, snapshots with toMatchSnapshot, and lifecycle hooks (beforeAll, beforeEach, afterEach); track resources for cleanup in afterEach
Use using/await using with Bun resources (e.g., Bun.listen/connect/spawn/serve) to ensure cleanup in tests

Files:

  • test/js/bun/test/only-failures.test.ts
test/js/**

📄 CodeRabbit inference engine (test/CLAUDE.md)

Organize unit tests for specific features under test/js/ by module

Files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
test/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.test.{ts,tsx}: Test files must live under test/ and end with .test.ts or .test.tsx
In tests, always use port: 0; do not hardcode ports or roll your own random port
Prefer normalizeBunSnapshot for snapshotting test output instead of asserting raw strings
Do not write tests that assert absence of crashes (e.g., 'no panic' or 'no uncaught exception')
Use Bun’s Jest-compatible runner (import { test, expect } from "bun:test") for tests
Avoid shell commands like find or grep in tests; use Bun’s Glob and built-in tools instead
Prefer running tests via bun bd test and use provided harness utilities (bunEnv, bunExe, tempDir)
Use Bun.spawn with proper stdio handling and await proc.exited in process-spawning tests

Files:

  • test/js/bun/test/only-failures.test.ts
test/js/bun/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place Bun-specific API tests under test/js/bun/

Files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
🧠 Learnings (14)
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Use Bun.spawn with proper stdio handling and await proc.exited in process-spawning tests

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-09-03T17:10:13.486Z
Learnt from: CR
PR: oven-sh/bun#0
File: test/CLAUDE.md:0-0
Timestamp: 2025-09-03T17:10:13.486Z
Learning: Applies to test/**/*.test.ts : Name test files `*.test.ts` and use `bun:test`

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-09-03T17:10:13.486Z
Learnt from: CR
PR: oven-sh/bun#0
File: test/CLAUDE.md:0-0
Timestamp: 2025-09-03T17:10:13.486Z
Learning: Applies to test/**/*.test.ts : When spawning Bun in tests, use `bunExe()` and `bunEnv` from `harness`

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Use Bun’s Jest-compatible runner (import { test, expect } from "bun:test") for tests

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Prefer normalizeBunSnapshot for snapshotting test output instead of asserting raw strings

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-08-30T00:12:56.803Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-08-30T00:12:56.803Z
Learning: Applies to test/**/*.{js,ts} : Write tests in JavaScript or TypeScript using Bun’s Jest-style APIs (test, describe, expect) and run with bun test

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-08-30T00:12:56.803Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-08-30T00:12:56.803Z
Learning: Applies to test/cli/**/*.{js,ts} : When testing Bun as a CLI, use spawn with bunExe() and bunEnv from harness, and capture stdout/stderr via pipes

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Prefer running tests via bun bd test <file> and use provided harness utilities (bunEnv, bunExe, tempDir)

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-08-30T00:12:56.803Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-08-30T00:12:56.803Z
Learning: Applies to test/js/bun/**/*.{js,ts} : Place Bun API tests under test/js/bun/, separated by category (e.g., test/js/bun/glob/)

Applied to files:

  • test/js/bun/test/only-failures.test.ts
  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-09-08T00:41:12.052Z
Learnt from: CR
PR: oven-sh/bun#0
File: src/bun.js/bindings/v8/CLAUDE.md:0-0
Timestamp: 2025-09-08T00:41:12.052Z
Learning: Applies to src/bun.js/bindings/v8/test/v8/v8.test.ts : Add a corresponding test case in test/v8/v8.test.ts that invokes checkSameOutput with the new function

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/js/bun/** : Place Bun-specific API tests under test/js/bun/

Applied to files:

  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-09-03T17:10:13.486Z
Learnt from: CR
PR: oven-sh/bun#0
File: test/CLAUDE.md:0-0
Timestamp: 2025-09-03T17:10:13.486Z
Learning: Applies to test/**/*-fixture.ts : Name test fixture files that are spawned by tests with the suffix `-fixture.ts`

Applied to files:

  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-09-03T17:10:13.486Z
Learnt from: CR
PR: oven-sh/bun#0
File: test/CLAUDE.md:0-0
Timestamp: 2025-09-03T17:10:13.486Z
Learning: Applies to test/**/*.test.ts : Do not set explicit test timeouts; rely on Bun’s built-in timeouts

Applied to files:

  • test/js/bun/test/only-failures.fixture.ts
📚 Learning: 2025-09-20T03:39:41.770Z
Learnt from: pfgithub
PR: oven-sh/bun#22534
File: test/regression/issue/21830.fixture.ts:14-63
Timestamp: 2025-09-20T03:39:41.770Z
Learning: Bun's test runner supports async describe callbacks, unlike Jest/Vitest where describe callbacks must be synchronous. The syntax `describe("name", async () => { ... })` is valid in Bun.

Applied to files:

  • test/js/bun/test/only-failures.fixture.ts
🧬 Code graph analysis (1)
test/js/bun/test/only-failures.test.ts (1)
test/harness.ts (2)
  • bunExe (103-106)
  • normalizeBunSnapshot (1809-1840)
🔇 Additional comments (8)
src/bun.js/test/jest.zig (1)

18-18: LGTM! Consistent integration of only_failures flag.

The addition of reporter.reporters.only_failures to the condition follows the same pattern as the dots reporter, ensuring that file title and prefix information is properly deferred when the only-failures mode is active.

src/cli.zig (1)

357-357: LGTM! Proper field addition.

The only_failures field is correctly added to the reporters struct with an appropriate default value of false, following the same pattern as the existing dots field.

src/bun.js/test/bun_test.zig (1)

176-176: LGTM! Appropriate error output handling.

The addition of reporter.reporters.only_failures to the condition ensures that error output is formatted correctly when the only-failures mode is active, consistent with the dots reporter behavior.

src/cli/Arguments.zig (1)

464-467: LGTM! Proper flag handling.

The flag is correctly parsed and sets the appropriate option field.

test/js/bun/test/only-failures.fixture.ts (1)

1-27: LGTM! Well-designed test fixture.

The fixture provides comprehensive test coverage with a good mix of passing, failing, skipped, todo, and error cases, which is ideal for validating the --only-failures flag behavior.

test/js/bun/test/only-failures.test.ts (1)

4-57: LGTM! Comprehensive test coverage.

The test properly validates the --only-failures flag behavior using bunExe(), bunEnv, and normalizeBunSnapshot as per coding guidelines. The inline snapshot provides clear documentation of expected output.

src/cli/test_command.zig (2)

582-582: LGTM!

The field addition is straightforward and correctly defaults to false.


878-879: LGTM!

The logic correctly suppresses non-failure output when either AI agent mode or --only-failures is active. The defensive null check on buntest.reporter is appropriate.

clap.parseParam("--reporter <STR> Test output reporter format. Available: 'junit' (requires --reporter-outfile), 'dots'. Default: console output.") catch unreachable,
clap.parseParam("--reporter-outfile <STR> Output file path for the reporter format (required with --reporter).") catch unreachable,
clap.parseParam("--dots Enable dots reporter. Shorthand for --reporter=dots.") catch unreachable,
clap.parseParam("--only-failures Only display test failures. Similar to --dots but without printing dots.") catch unreachable,
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify flag interaction between --dots and --only-failures.

The description states that --only-failures is "Similar to --dots but without printing dots," suggesting these are alternative modes. However, the code doesn't prevent using both flags simultaneously.

Should these flags be mutually exclusive? If both are provided, what should the expected behavior be? Consider adding validation to ensure only one reporter mode is active at a time, or document the combined behavior if it's intentional.


🏁 Script executed:

#!/bin/bash
# Verify if there's any logic in test_command.zig that handles the interaction between dots and only_failures
rg -n -A 5 -B 5 "reporters\.(dots|only_failures)" src/cli/test_command.zig

Length of output: 3976


🏁 Script executed:

#!/bin/bash
rg -n -C3 "\"--dots" src/cli/Arguments.zig
rg -n -C3 "\"--only-failures" src/cli/Arguments.zig

Length of output: 2198


Enforce mutual exclusion between --dots and --only-failures
Use clap’s ArgGroup or add a manual check to error when both --dots and --only-failures are passed, or explicitly document that --dots takes precedence if both are provided.

🤖 Prompt for AI Agents
In src/cli/Arguments.zig around line 210, the new `--only-failures` param can be
passed together with `--dots`, but there is no mutual-exclusion enforcement; add
an ArgGroup to the clap definition that contains both `--dots` and
`--only-failures` and mark it as conflicts, or if ArgGroup isn’t
available/desired add a post-parse check that detects both flags and returns a
user-facing error (or explicitly document and implement precedence such that
`--dots` overrides `--only-failures`), ensuring the CLI fails fast with a clear
message when both are supplied.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@pfgithub pfgithub self-assigned this Oct 7, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
docs/runtime/bunfig.md (1)

263-286: Consider documenting the relationship between test.onlyFailures and test.reporter.

The documentation shows both test.onlyFailures and test.reporter.dots as separate top-level options under [test] and [test.reporter] respectively. However, from the code changes in src/bunfig.zig, it appears onlyFailures is parsed directly under the [test] object, not nested under [test.reporter]. The documentation structure is correct, but it might be helpful to clarify that:

  1. test.onlyFailures is a boolean flag that affects output behavior globally
  2. test.reporter.dots and test.reporter.junit are reporter-specific configurations

This distinction helps users understand the configuration hierarchy.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d932169 and 7940ccf.

📒 Files selected for processing (5)
  • docs/runtime/bunfig.md (1 hunks)
  • src/bun.js/test/jest.zig (1 hunks)
  • src/bunfig.zig (1 hunks)
  • src/cli/test_command.zig (4 hunks)
  • test/js/bun/test/only-failures.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
src/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/building-bun.mdc)

Implement debug logs in Zig using const log = bun.Output.scoped(.${SCOPE}, false); and invoking log("...", .{})

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: In Zig source files, place all @import statements at the bottom of the file
Use @import("bun") instead of @import("root").bun when importing Bun in Zig

Files:

  • src/bunfig.zig
  • src/cli/test_command.zig
  • src/bun.js/test/jest.zig
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/bunfig.zig
  • src/cli/test_command.zig
  • src/bun.js/test/jest.zig
test/**

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

Place all tests under the test/ directory

Files:

  • test/js/bun/test/only-failures.test.ts
test/js/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

Place JavaScript and TypeScript tests under test/js/

Files:

  • test/js/bun/test/only-failures.test.ts
test/js/bun/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

Place Bun API tests under test/js/bun/, separated by category (e.g., test/js/bun/glob/)

Files:

  • test/js/bun/test/only-failures.test.ts
test/**/*.{js,ts}

📄 CodeRabbit inference engine (.cursor/rules/writing-tests.mdc)

test/**/*.{js,ts}: Write tests in JavaScript or TypeScript using Bun’s Jest-style APIs (test, describe, expect) and run with bun test
Prefer data-driven tests (e.g., test.each) to reduce boilerplate
Use shared utilities from test/harness.ts where applicable

Files:

  • test/js/bun/test/only-failures.test.ts
test/**/*.test.ts

📄 CodeRabbit inference engine (test/CLAUDE.md)

test/**/*.test.ts: Name test files *.test.ts and use bun:test
Do not write flaky tests: never wait for arbitrary time; wait for conditions instead
Never hardcode port numbers in tests; use port: 0 to get a random port
When spawning Bun in tests, use bunExe() and bunEnv from harness
Prefer async/await in tests; for a single callback, use Promise.withResolvers()
Do not set explicit test timeouts; rely on Bun’s built-in timeouts
Use tempDir/tempDirWithFiles from harness for temporary files and directories in tests
For large/repetitive strings in tests, prefer Buffer.alloc(count, fill).toString() over "A".repeat(count)
Import common test utilities from harness (e.g., bunExe, bunEnv, tempDirWithFiles, tmpdirSync, platform checks, GC helpers)
In error tests, assert non-zero exit codes for failing processes and use toThrow for synchronous errors
Use describe blocks for grouping, describe.each for parameterized tests, snapshots with toMatchSnapshot, and lifecycle hooks (beforeAll, beforeEach, afterEach); track resources for cleanup in afterEach
Use using/await using with Bun resources (e.g., Bun.listen/connect/spawn/serve) to ensure cleanup in tests

Files:

  • test/js/bun/test/only-failures.test.ts
test/js/**

📄 CodeRabbit inference engine (test/CLAUDE.md)

Organize unit tests for specific features under test/js/ by module

Files:

  • test/js/bun/test/only-failures.test.ts
test/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.test.{ts,tsx}: Test files must live under test/ and end with .test.ts or .test.tsx
In tests, always use port: 0; do not hardcode ports or roll your own random port
Prefer normalizeBunSnapshot for snapshotting test output instead of asserting raw strings
Do not write tests that assert absence of crashes (e.g., 'no panic' or 'no uncaught exception')
Use Bun’s Jest-compatible runner (import { test, expect } from "bun:test") for tests
Avoid shell commands like find or grep in tests; use Bun’s Glob and built-in tools instead
Prefer running tests via bun bd test and use provided harness utilities (bunEnv, bunExe, tempDir)
Use Bun.spawn with proper stdio handling and await proc.exited in process-spawning tests

Files:

  • test/js/bun/test/only-failures.test.ts
test/js/bun/**

📄 CodeRabbit inference engine (CLAUDE.md)

Place Bun-specific API tests under test/js/bun/

Files:

  • test/js/bun/test/only-failures.test.ts
src/bun.js/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)

src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy

Files:

  • src/bun.js/test/jest.zig
🧠 Learnings (10)
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Use Bun.spawn with proper stdio handling and await proc.exited in process-spawning tests

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-09-03T17:10:13.486Z
Learnt from: CR
PR: oven-sh/bun#0
File: test/CLAUDE.md:0-0
Timestamp: 2025-09-03T17:10:13.486Z
Learning: Applies to test/**/*.test.ts : Name test files `*.test.ts` and use `bun:test`

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-08-30T00:12:56.803Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-08-30T00:12:56.803Z
Learning: Applies to test/**/*.{js,ts} : Write tests in JavaScript or TypeScript using Bun’s Jest-style APIs (test, describe, expect) and run with bun test

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-08-30T00:12:56.803Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-08-30T00:12:56.803Z
Learning: Applies to test/js/bun/**/*.{js,ts} : Place Bun API tests under test/js/bun/, separated by category (e.g., test/js/bun/glob/)

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-09-03T17:10:13.486Z
Learnt from: CR
PR: oven-sh/bun#0
File: test/CLAUDE.md:0-0
Timestamp: 2025-09-03T17:10:13.486Z
Learning: Applies to test/**/*.test.ts : When spawning Bun in tests, use `bunExe()` and `bunEnv` from `harness`

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Prefer running tests via bun bd test <file> and use provided harness utilities (bunEnv, bunExe, tempDir)

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Use Bun’s Jest-compatible runner (import { test, expect } from "bun:test") for tests

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/**/*.test.{ts,tsx} : Prefer normalizeBunSnapshot for snapshotting test output instead of asserting raw strings

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-08-30T00:12:56.803Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/writing-tests.mdc:0-0
Timestamp: 2025-08-30T00:12:56.803Z
Learning: Applies to test/cli/**/*.{js,ts} : When testing Bun as a CLI, use spawn with bunExe() and bunEnv from harness, and capture stdout/stderr via pipes

Applied to files:

  • test/js/bun/test/only-failures.test.ts
📚 Learning: 2025-10-04T09:51:30.294Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-04T09:51:30.294Z
Learning: Applies to test/js/bun/** : Place Bun-specific API tests under test/js/bun/

Applied to files:

  • test/js/bun/test/only-failures.test.ts
🧬 Code graph analysis (1)
test/js/bun/test/only-failures.test.ts (1)
test/harness.ts (3)
  • bunExe (101-104)
  • normalizeBunSnapshot (1807-1838)
  • tempDir (276-283)
🔇 Additional comments (10)
docs/runtime/bunfig.md (1)

252-261: LGTM! Clear and concise documentation.

The documentation for test.onlyFailures is well-structured and provides a clear example. The note about the CLI flag equivalence is helpful.

test/js/bun/test/only-failures.test.ts (3)

4-57: LGTM! Comprehensive snapshot test for single file.

The test properly:

  • Uses bunExe() and bunEnv from harness
  • Captures stdout and stderr
  • Normalizes output with normalizeBunSnapshot
  • Validates the complete output structure with an inline snapshot

The snapshot confirms that only failing tests are displayed while the summary includes all test counts.


59-79: LGTM! Good multi-file test with targeted assertions.

The test validates that --only-failures works across multiple files by:

  • Running tests from two different fixture files
  • Checking for presence of "(fail)" markers
  • Confirming absence of "(pass)" markers
  • Verifying the exit code is 1 (due to failures)

This approach is more maintainable than a full snapshot for multi-file output.


81-120: LGTM! Proper bunfig.toml integration test with resource cleanup.

The test correctly:

  • Uses using syntax with tempDir for automatic cleanup (line 82)
  • Creates a temporary directory with bunfig.toml and test file
  • Spawns bun test with the correct working directory (line 109)
  • Validates that bunfig configuration is respected

The use of normalizeBunSnapshot(stderr, dir) on line 117 properly normalizes the temporary directory path.

src/bun.js/test/jest.zig (1)

18-18: LGTM! Consistent with the new only_failures flag architecture.

The condition now checks reporter.reporters.only_failures instead of directly detecting AI agent mode. This is correct because:

  1. The only_failures flag is set based on AI agent detection in test_command.zig (lines 1367-1369)
  2. This change maintains the same behavior while centralizing the AI agent logic
  3. It makes the code more explicit about when early clearing should occur

The change aligns with the broader refactoring to use an explicit flag rather than scattered AI agent checks.

src/bunfig.zig (1)

242-245: LGTM! Follows established parsing patterns.

The parsing logic for onlyFailures:

  • Correctly checks for boolean type with try this.expect(expr, .e_boolean)
  • Sets the appropriate context field this.ctx.test_options.reporters.only_failures
  • Follows the exact same pattern as other boolean test options (e.g., coverage, smol)

The placement within the TestCommand configuration block is appropriate.

src/cli/test_command.zig (4)

582-582: LGTM! Field properly declared.

The only_failures boolean field is correctly:

  • Added to the reporters struct alongside dots and junit
  • Initialized with a default value of false
  • Placed logically with other reporter configuration

904-904: LGTM! Consistent with the only_failures flag.

The condition correctly prevents queuing of skips, todos, and failures for later repetition when either dots or only_failures mode is active. This is consistent with the printing logic above and ensures that buffered output is only accumulated in normal mode.


1365-1369: LGTM! Appropriate default behavior for AI agents.

The initialization logic:

  1. First checks the explicit CLI flag/bunfig setting (line 1365-1366)
  2. Falls back to enabling only_failures for AI agents (lines 1367-1369)

This is a sensible default that reduces verbosity in AI-assisted development contexts while still allowing users to override it via configuration.


878-880: No changes needed: dots mode takes precedence over only_failures

The code checks reporters.dots first, so when both flags are set non-failures print dots and failures print full lines. Logic correctly handles all non-failure statuses.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/cli/Arguments.zig (1)

465-468: Clarify or enforce the interaction between --dots and --only-failures.

Currently, both --dots and --only-failures can be set simultaneously without validation. When both flags are provided:

  • Passing tests print dots (via reporters.dots check on line 864 in test_command.zig)
  • Failing tests print full output (via logic on line 878-891 in test_command.zig)

However, the PR description states --only-failures is "Similar to --dots but without printing dots," which suggests they are alternative modes rather than combinable options.

Recommendation: Either:

  1. Enforce mutual exclusion (as suggested in past review comments) by checking if both flags are provided and returning an error, or
  2. Document the combined behavior explicitly if it's intentional, explaining what users should expect when both flags are used together.
#!/bin/bash
# Verify if there's any documentation or handling for simultaneous use of both flags
rg -n -C3 'dots.*only_failures|only_failures.*dots' src/
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3f0d49d and b28d83c.

📒 Files selected for processing (4)
  • docs/runtime/bunfig.md (1 hunks)
  • src/bun.js/test/jest.zig (1 hunks)
  • src/cli/Arguments.zig (2 hunks)
  • src/cli/test_command.zig (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/javascriptcore-class.mdc)

**/*.zig: Declare the extern C symbol in Zig and export a Zig-friendly alias for use
Wrap the Bun____toJS extern in a Zig method that takes a JSGlobalObject and returns JSC.JSValue

Files:

  • src/cli/Arguments.zig
  • src/bun.js/test/jest.zig
  • src/cli/test_command.zig
src/**/*.zig

📄 CodeRabbit inference engine (CLAUDE.md)

In Zig code, manage memory carefully and use defer for cleanup of allocations/resources

src/**/*.zig: Use the # prefix to declare private fields in Zig structs (e.g., struct { #foo: u32 })
Prefer decl literals when initializing values in Zig (e.g., const decl: Decl = .{ .binding = 0, .value = 0 })
Place @import directives at the bottom of Zig files
Use @import("bun") instead of @import("root").bun

When adding debug logs in Zig, create a scoped logger and log via Bun APIs: const log = bun.Output.scoped(.${SCOPE}, .hidden); then log("...", .{})

Files:

  • src/cli/Arguments.zig
  • src/bun.js/test/jest.zig
  • src/cli/test_command.zig
src/bun.js/**/*.zig

📄 CodeRabbit inference engine (.cursor/rules/zig-javascriptcore-classes.mdc)

src/bun.js/**/*.zig: In Zig binding structs, expose generated bindings via pub const js = JSC.Codegen.JS and re-export toJS/fromJS/fromJSDirect
Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions
Use parameter name globalObject (not ctx) and accept (*JSC.JSGlobalObject, *JSC.CallFrame) in binding methods/constructors
Implement getters as get(this, globalObject) returning JSC.JSValue and matching the .classes.ts interface
Provide deinit() for resource cleanup and finalize() that calls deinit(); use bun.destroy(this) or appropriate destroy pattern
Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)
For properties marked cache: true, use the generated Zig accessors (NameSetCached/GetCached) to work with GC-owned values
In finalize() for objects holding JS references, release them using .deref() before destroy

Files:

  • src/bun.js/test/jest.zig
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Format
🔇 Additional comments (5)
src/bun.js/test/jest.zig (1)

18-18: LGTM! AI agent handling properly consolidated.

The removal of Output.isAIAgent() is correct—this logic has been moved to test_command.zig (lines 1368-1370) where only_failures is now set to true for AI agents. This consolidates the AI agent handling in one place.

src/cli/test_command.zig (4)

582-582: LGTM! Field addition is correct.

The new only_failures boolean field follows the existing pattern for dots and junit reporters and is properly initialized to false.


878-879: LGTM! Conditional logic correctly implements only-failures mode.

The condition properly checks:

  1. Test result is NOT a failure: ((comptime result.basicResult()) != .fail)
  2. Reporter has only_failures enabled: buntest.reporter.?.reporters.only_failures

This correctly skips printing for non-failure tests when the flag is set, allowing only failures to be displayed.


904-904: LGTM! Buffering behavior is consistent with dots reporter.

The updated condition !this.reporters.dots and !this.reporters.only_failures correctly prevents buffering failures for later display when either flag is enabled. This is consistent because:

  • The "repeat failures" functionality (lines 1559-1569) only makes sense for the default verbose output
  • Both dots and only_failures modes print output immediately as tests complete
  • The repeat is already disabled for dots mode, so this extends the same logic to only_failures

1366-1370: LGTM! Proper initialization with AI agent fallback.

The initialization logic correctly:

  1. Checks the explicit only_failures flag from context
  2. Falls back to enabling it for AI agents if not explicitly set
  3. Maintains the existing AI agent behavior by consolidating the check here (previously scattered across multiple files)

This is a good refactoring that centralizes the AI agent handling.

Comment on lines +252 to +261
### `test.onlyFailures`

When enabled, only failed tests are displayed in the output. This helps reduce noise in large test suites by hiding passing tests. Default `false`.

```toml
[test]
onlyFailures = true
```

This is equivalent to using the `--only-failures` flag when running `bun test`.
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Document the interaction with dots reporter.

While this documentation is clear, consider adding a note about the behavior when test.onlyFailures is used alongside test.reporter.dots. Based on the code in test_command.zig, when both are enabled, dots are printed for passing tests and full output is shown for failures. This interaction should be documented to avoid user confusion.

Apply this diff to clarify the interaction:

 ### `test.onlyFailures`
 
 When enabled, only failed tests are displayed in the output. This helps reduce noise in large test suites by hiding passing tests. Default `false`.
 
 ```toml
 [test]
 onlyFailures = true

This is equivalent to using the --only-failures flag when running bun test.
+
+Note: When combined with test.reporter.dots, passing tests will display as dots while failures show full output.


<details>
<summary>🤖 Prompt for AI Agents</summary>

In docs/runtime/bunfig.md around lines 252 to 261, the docs for
test.onlyFailures lack a note about how it interacts with test.reporter.dots;
add a short sentence after the existing paragraph that states: "Note: When
combined with test.reporter.dots, passing tests will display as dots while
failures show full output." so users understand that dots are still printed for
passes and full failure output is shown.


</details>

<!-- This is an auto-generated comment by CodeRabbit -->

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.

2 participants