Skip to content

Conversation

pfgithub
Copy link
Collaborator

@pfgithub pfgithub commented Sep 23, 2025

Adds a simple dots reporter for bun test

image

@robobun
Copy link
Collaborator

robobun commented Sep 23, 2025

Updated 4:58 PM PT - Oct 3rd, 2025

@pfgithub, your commit c2b05c5 has 3 failures in Build #27903 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 22919

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

bun-22919 --bun

autofix-ci bot and others added 6 commits September 23, 2025 21:49
Resolved conflicts in Arguments.zig by:
- Keeping dots reporter support from pfg/dots
- Adding max-concurrency parameter from origin/main
- Updating help text to mention both junit and dots reporters
- Print newline before failure output when previous output was a dot
- Add bunfig.toml support for dots reporter via test.reporter.dots config
- Suppress failure list at end when using dots reporter (avoid redundant output)

This improves the dots reporter UX by:
1. Preventing failure details from appearing on the same line as dots
2. Allowing users to set dots as their default reporter in bunfig.toml
3. Reducing noise by not re-listing failures when using compact dots format
- Adds new CLI flag --dots to enable the dots reporter
- Works as a convenient shorthand for --reporter=dots
- Complements existing bunfig.toml dots reporter option
- Documentation is automatically included in help text

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

Co-Authored-By: Claude <noreply@anthropic.com>
@pfgithub pfgithub marked this pull request as ready for review October 3, 2025 04:37
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Walkthrough

Replace the single file-based test reporter with a structured reporters config (dots and junit); add --dots CLI flag; thread reporter state through test printing, buffering, and newline handling; add scoped output buffering; add dots-mode tests and fixtures; rename and wire BunTest root fields and pre-print hooks.

Changes

Cohort / File(s) Summary
CLI test options & parsing
src/cli.zig, src/cli/Arguments.zig
Replace file_reporter with reporters { dots, junit }; add --dots flag and `--reporter=dots
Test command reporter implementation
src/cli/test_command.zig
Replace file_reporter/FileReporter with reporters: struct { dots: bool, junit: ?*JunitReporter }; add last_printed_dot: bool; wire reporters.dots/reporters.junit across init/teardown and printing/newline behavior.
Jest integration & current-file printing
src/bun.js/test/jest.zig
Thread CommandLineReporter into CurrentFile.set signature and import CommandLineReporter; adapt CurrentFile.print/printIfNeeded for buffering and header output; use reporters.{junit,dots} for junit detection/line capture.
Execution & Bun test root / uncaught handling
src/bun.js/test/Execution.zig, src/bun.js/test/bun_test.zig
Add BunTestRoot.onBeforePrint() and call it from uncaught-exception paths; rename buntestbun_test_root and update usages; remove a direct printIfNeeded() call; coordinate newline/flush with reporter state.
Console hook
src/bun.js/ConsoleObject.zig
Call runner.bun_test_root.onBeforePrint() before Console printing when Jest runner exists to coordinate dot/newline state.
Config mapping
src/bunfig.zig
Update config parsing to set test_options.reporters.junit and test_options.reporters.dots (instead of file_reporter); preserve reporter_outfile handling.
Output buffering scope
src/output.zig
Add EnableBufferingScope and pub fn enableBufferingScope() to enable scoped buffered output without forcing flush on deinit.
Tests & fixtures for dots mode
test/js/bun/test/dots.fixture.ts, test/js/bun/test/dots.test.ts, test/js/bun/test/printing/dots/*
Add dots-mode fixtures (parameterized pass/skip/fail/todo) and integration tests that run fixtures with --dots, asserting normalized stdout/stderr and exit codes.
Minor test/layout changes
test/regression/issue/23183.test.ts
Reorder imports and remove an unused path.join import.

Possibly related PRs

Suggested reviewers

  • Jarred-Sumner
  • nektro

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The description does not follow the required template because it lacks the "### What does this PR do?" and "### How did you verify your code works?" section headings and omits any verification details, providing only a brief summary and a screenshot. Please update the description to include the "### What does this PR do?" heading with a summary of changes and the "### How did you verify your code works?" heading with details on testing or verification steps.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly identifies the main change by referencing the dots reporter for bun test and directly matches the focus of the changeset without extraneous detail.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pfg/dots

📜 Recent 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 6f3de66 and c2b05c5.

📒 Files selected for processing (1)
  • src/cli/test_command.zig (14 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
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("...", .{})

Files:

  • src/cli/test_command.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

**/*.zig: Format Zig files with zig-format (bun run zig-format)
In Zig, manage memory carefully with allocators and use defer for cleanup

Files:

  • src/cli/test_command.zig
🧠 Learnings (1)
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to **/*.zig : In Zig, manage memory carefully with allocators and use defer for cleanup

Applied to files:

  • src/cli/test_command.zig
🔇 Additional comments (7)
src/cli/test_command.zig (7)

574-574: LGTM!

The field additions are clean and well-structured. last_printed_dot tracks state for newline handling, and the reporters struct consolidates the dots and JUnit reporters with sensible defaults.

Also applies to: 580-583


706-846: LGTM!

The maybePrintJunitLine function correctly handles JUnit reporter output with proper null checks, suite stack management, and error handling via bun.handleOom.


903-908: LGTM!

The conditional buffering logic correctly skips collecting skips/todos/fails for later printing when in dots mode, as these are handled inline with dots.


1358-1363: LGTM!

The reporter initialization logic correctly initializes the JUnit reporter and sets the dots flag based on the test configuration.


1531-1531: LGTM!

The printing logic correctly handles dots mode by:

  1. Skipping repeated skips/todos/fails summary when in dots mode (line 1531)
  2. Using DotIndenter to conditionally add indentation based on the reporter mode (lines 1649-1695)

This creates a cleaner, more compact output in dots mode while preserving the detailed summary format in non-dots mode.

Also applies to: 1649-1695


1756-1761: LGTM!

The JUnit reporter finalization correctly closes any open test suite and writes the report to the configured output file with appropriate error handling.


862-876: .skipped_because_label no longer sets last_printed_dot
The guard at line 862 excludes .skipped_because_label before entering the dots block, and last_printed_dot is only set when a dot is actually printed (line 876).


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

📜 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 79e0aa9 and 73464b1.

📒 Files selected for processing (7)
  • src/bun.js/test/jest.zig (1 hunks)
  • src/bunfig.zig (1 hunks)
  • src/cli.zig (1 hunks)
  • src/cli/Arguments.zig (2 hunks)
  • src/cli/test_command.zig (8 hunks)
  • test/js/bun/test/dots.fixture.ts (1 hunks)
  • test/js/bun/test/dots.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("...", .{})

Files:

  • src/bun.js/test/jest.zig
  • src/bunfig.zig
  • src/cli.zig
  • src/cli/Arguments.zig
  • src/cli/test_command.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

**/*.zig: Format Zig files with zig-format (bun run zig-format)
In Zig, manage memory carefully with allocators and use defer for cleanup

Files:

  • src/bun.js/test/jest.zig
  • src/bunfig.zig
  • src/cli.zig
  • src/cli/Arguments.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
test/**

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

Place all tests under the test/ directory

Files:

  • test/js/bun/test/dots.fixture.ts
  • test/js/bun/test/dots.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/dots.fixture.ts
  • test/js/bun/test/dots.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/dots.fixture.ts
  • test/js/bun/test/dots.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/dots.fixture.ts
  • test/js/bun/test/dots.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/dots.fixture.ts
  • test/js/bun/test/dots.test.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Format JavaScript/TypeScript files with Prettier (bun run prettier)

Files:

  • test/js/bun/test/dots.fixture.ts
  • test/js/bun/test/dots.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/dots.test.ts
test/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.test.{ts,tsx}: Test files must be placed under test/ and end with .test.ts or .test.tsx
In tests, always use port: 0; do not hardcode ports or use custom random port functions
In tests, use normalizeBunSnapshot when asserting snapshots
Never write tests that merely assert absence of "panic" or "uncaught exception" in output
Avoid shell commands (e.g., find, grep) in tests; use Bun.Glob and built-ins instead
Prefer snapshot tests over exact stdout equality assertions

Files:

  • test/js/bun/test/dots.test.ts
🧠 Learnings (12)
📚 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/dots.fixture.ts
  • test/js/bun/test/dots.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/dots.fixture.ts
  • test/js/bun/test/dots.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} : Prefer data-driven tests (e.g., test.each) to reduce boilerplate

Applied to files:

  • test/js/bun/test/dots.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/dots.fixture.ts
  • test/js/bun/test/dots.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/**/*-fixture.ts : Name test fixture files that are spawned by tests with the suffix `-fixture.ts`

Applied to files:

  • test/js/bun/test/dots.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/dots.test.ts
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to test/**/*.test.{ts,tsx} : In tests, use normalizeBunSnapshot when asserting snapshots

Applied to files:

  • test/js/bun/test/dots.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/dots.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 : Import common test utilities from `harness` (e.g., `bunExe`, `bunEnv`, `tempDirWithFiles`, `tmpdirSync`, platform checks, GC helpers)

Applied to files:

  • test/js/bun/test/dots.test.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/dots.test.ts
📚 Learning: 2025-08-30T00:09:39.100Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/dev-server-tests.mdc:0-0
Timestamp: 2025-08-30T00:09:39.100Z
Learning: Applies to test/bake/bake-harness.ts : Provide and maintain shared test utilities: devTest, prodTest, devAndProductionTest, Dev, Client, and helpers in the harness

Applied to files:

  • test/js/bun/test/dots.test.ts
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to test/**/*.test.{ts,tsx} : Avoid shell commands (e.g., find, grep) in tests; use Bun.Glob and built-ins instead

Applied to files:

  • test/js/bun/test/dots.test.ts
🧬 Code graph analysis (1)
test/js/bun/test/dots.test.ts (1)
test/harness.ts (2)
  • bunExe (103-106)
  • normalizeBunSnapshot (1809-1840)
🔇 Additional comments (7)
test/js/bun/test/dots.test.ts (1)

1-54: LGTM!

The test implementation follows all coding guidelines:

  • Uses bun:test APIs with async/await
  • Spawns Bun subprocess with bunExe() and bunEnv from harness
  • Uses normalizeBunSnapshot for snapshot assertions
  • Validates the new --dots reporter flag behavior correctly
test/js/bun/test/dots.fixture.ts (1)

1-4: LGTM!

The fixture appropriately uses test.each to generate parameterized tests across different test states (passing, skipped, failing, todo), which aligns with the coding guideline to prefer data-driven tests to reduce boilerplate. The 40 total tests (10 of each type) match the expectations in dots.test.ts.

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

457-464: LGTM!

The condition correctly checks the new reporters.junit flag instead of the deprecated file_reporter enum. This aligns with the broader refactor to support multiple reporters (dots and junit) and maintains the correct behavior of capturing test line numbers only when the junit reporter is enabled.

src/cli.zig (1)

355-360: LGTM!

The structural change from a single file_reporter enum to a nested reporters struct with boolean flags (dots and junit) supports the new multiple-reporter capability. This design allows enabling both reporters simultaneously if needed in the future, while preserving the reporter_outfile field for output path configuration.

src/bunfig.zig (1)

242-255: LGTM!

The bunfig parser correctly handles the new reporters structure:

  • Sets reporters.junit = true when a junit output path is specified
  • Parses reporters.dots as a boolean flag
  • Preserves reporter_outfile for the junit XML output path
  • Includes proper type validation for the dots boolean

The changes align with the broader refactor across the codebase and maintain backward compatibility for the junit reporter configuration.

src/cli/Arguments.zig (2)

207-210: LGTM!

The help text and parameter definition correctly document both reporter options ("junit" and "dots") and provide the convenient --dots shorthand flag.


453-471: LGTM!

The argument parsing logic correctly handles the new reporters structure:

  • Enables reporters.junit when --reporter=junit is specified, with proper validation requiring --reporter-outfile
  • Enables reporters.dots when --reporter=dots is specified, without requiring an outfile
  • Handles the --dots shorthand flag as an alias for --reporter=dots
  • Updates error messages to include both supported reporter formats

The implementation is clean and maintains consistency with the broader refactor.

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: 3

📜 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 73464b1 and 790ad64.

📒 Files selected for processing (3)
  • src/cli/test_command.zig (8 hunks)
  • test/js/bun/test/dots.fixture.ts (1 hunks)
  • test/js/bun/test/dots.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/js/bun/test/dots.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
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("...", .{})

Files:

  • src/cli/test_command.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

**/*.zig: Format Zig files with zig-format (bun run zig-format)
In Zig, manage memory carefully with allocators and use defer for cleanup

Files:

  • src/cli/test_command.zig
test/**

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

Place all tests under the test/ directory

Files:

  • test/js/bun/test/dots.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/dots.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/dots.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/dots.fixture.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/dots.fixture.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Format JavaScript/TypeScript files with Prettier (bun run prettier)

Files:

  • test/js/bun/test/dots.fixture.ts
🧠 Learnings (6)
📚 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/dots.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/dots.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/dots.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/dots.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,ts} : Prefer data-driven tests (e.g., test.each) to reduce boilerplate

Applied to files:

  • test/js/bun/test/dots.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 : 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`

Applied to files:

  • test/js/bun/test/dots.fixture.ts

Comment on lines 1309 to 1314
var reporter = try ctx.allocator.create(CommandLineReporter);
defer {
if (reporter.file_reporter) |*file_reporter| {
switch (file_reporter.*) {
.junit => |junit_reporter| {
junit_reporter.deinit();
},
}
if (reporter.reporters.junit) |file_reporter| {
file_reporter.deinit();
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Destroy the allocated JUnit reporter after deinit.

JunitReporter.init() allocates the struct via bun.TrivialNew, so calling deinit() alone leaks that allocation. Add the corresponding bun.default_allocator.destroy(...) (and clear the optional) in the defer block to release the memory.

         defer {
             if (reporter.reporters.junit) |file_reporter| {
                 file_reporter.deinit();
+                bun.default_allocator.destroy(file_reporter);
+                reporter.reporters.junit = null;
             }
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var reporter = try ctx.allocator.create(CommandLineReporter);
defer {
if (reporter.file_reporter) |*file_reporter| {
switch (file_reporter.*) {
.junit => |junit_reporter| {
junit_reporter.deinit();
},
}
if (reporter.reporters.junit) |file_reporter| {
file_reporter.deinit();
}
}
var reporter = try ctx.allocator.create(CommandLineReporter);
defer {
if (reporter.reporters.junit) |file_reporter| {
file_reporter.deinit();
bun.default_allocator.destroy(file_reporter);
reporter.reporters.junit = null;
}
}
🤖 Prompt for AI Agents
In src/cli/test_command.zig around lines 1309 to 1314, the defer only calls
deinit() on the JUnit reporter but does not free the allocation made by
JunitReporter.init(), leaking memory; after calling file_reporter.deinit() call
bun.default_allocator.destroy(file_reporter) (or the appropriate destroy for the
allocator used) and clear the optional (set reporter.reporters.junit to
null/none) in the defer so the allocated struct is released and the optional is
cleared.

Comment on lines +1 to +7
test.each(Array.from({ length: 10 }, () => 0))("passing filterin", () => {});
test.skip.each(Array.from({ length: 10 }, () => 0))("skipped filterin", () => {});
test.failing("failing filterin", () => {});
test("passing filterout", () => {});
test.failing("failing filterin", () => {});
test.failing("failing filterin", () => {});
test.todo.each(Array.from({ length: 10 }, () => 0))("todo filterin", () => {});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify that the test API is properly imported.

The file uses test, test.each, test.skip, test.failing, and test.todo without an explicit import statement. Ensure that Bun's test runner automatically provides these APIs in fixture files, or add the required import.

Run the following script to check if other fixture files in the test suite include explicit imports:


🏁 Script executed:

#!/bin/bash
# Description: Check if other test fixture files include explicit imports for the test API.

# Search for fixture files and check their imports
fd -e ts -e js 'fixture' test/js/bun/test/ --exec head -5

Length of output: 5653


Add missing Bun test import
At the top of test/js/bun/test/dots.fixture.ts add:

import { test } from "bun:test";
🤖 Prompt for AI Agents
In test/js/bun/test/dots.fixture.ts lines 1 to 7, the file uses Bun test helpers
like test, test.each, test.skip, test.failing and test.todo but does not import
them; add the missing import statement at the top: import { test } from
"bun:test"; so the test symbol is defined for all uses in the file.

Comment on lines +3 to +6
test.failing("failing filterin", () => {});
test("passing filterout", () => {});
test.failing("failing filterin", () => {});
test.failing("failing filterin", () => {});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Eliminate duplicate test names.

Three tests share the identical name "failing filterin" (lines 3, 5, and 6). Duplicate test names can cause confusion in test output and may lead to issues with test identification and reporting.

Apply this diff to make the test names unique:

-test.failing("failing filterin", () => {});
+test.failing("failing filterin 1", () => {});
 test("passing filterout", () => {});
-test.failing("failing filterin", () => {});
-test.failing("failing filterin", () => {});
+test.failing("failing filterin 2", () => {});
+test.failing("failing filterin 3", () => {});
🤖 Prompt for AI Agents
In test/js/bun/test/dots.fixture.ts around lines 3 to 6, three tests share the
identical name "failing filterin"; rename the duplicate test titles so each is
unique (for example "failing filterin 1", "failing filterin 2", "failing
filterin 3" or more descriptive variants) and update any references if they are
used elsewhere, ensuring no two test() or test.failing() calls use the same
string.

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

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

1309-1314: ** Memory leak: destroy the allocated JUnit reporter after deinit.**

JunitReporter.init() at line 1343 allocates the struct via bun.TrivialNew(JunitReporter), which uses bun.default_allocator.create(). The defer block at lines 1311-1313 only calls deinit() but does not destroy the allocation, causing a memory leak.

Apply this diff to fix the leak:

         defer {
             if (reporter.reporters.junit) |file_reporter| {
                 file_reporter.deinit();
+                bun.default_allocator.destroy(file_reporter);
+                reporter.reporters.junit = null;
             }
         }

This matches the pattern used in JunitReporter where allocations made with TrivialNew must be explicitly destroyed.

🧹 Nitpick comments (1)
src/cli/test_command.zig (1)

715-828: Verify suite hierarchy logic and guard against infinite loops.

The nested suite management for JUnit reporting is complex. Here are specific concerns:

  1. Lines 758-765: The while (current_suite_depth > needed_suites.items.len) loop closes suites but has a break condition that could leave current_suite_depth out of sync if the guard at line 759 fails unexpectedly.

  2. Lines 785-793: Similar pattern in the suite closing loop - ensure suites_to_close counter correctly prevents infinite loops.

  3. Lines 802-806: The while (describe_suite_index < needed_suites.items.len) loop appears safe as it always increments the index.

  4. Lines 724-727: The nested while loop condition while (junit.suite_stack.items.len > 0 and !junit.suite_stack.items[junit.suite_stack.items.len - 1].is_file_suite) could infinite loop if endTestSuite() fails to remove items from the stack.

The logic appears sound for the happy path, but defensive checks could help prevent infinite loops in edge cases.

Consider adding iteration limits or assertions to guard against infinite loops:

             while (current_suite_depth > needed_suites.items.len) {
                 if (junit.suite_stack.items.len > 0 and !junit.suite_stack.items[junit.suite_stack.items.len - 1].is_file_suite) {
                     bun.handleOom(junit.endTestSuite());
                     current_suite_depth -= 1;
                 } else {
+                    bun.debugAssert(current_suite_depth <= needed_suites.items.len); // Should have exited the loop
                     break;
                 }
             }

Similarly for the other loops that modify suite state.

📜 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 790ad64 and 24b76fc.

📒 Files selected for processing (5)
  • src/bun.js/test/Execution.zig (1 hunks)
  • src/bun.js/test/jest.zig (4 hunks)
  • src/cli/test_command.zig (13 hunks)
  • src/output.zig (1 hunks)
  • test/js/bun/test/dots.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("...", .{})

Files:

  • src/output.zig
  • src/bun.js/test/Execution.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

**/*.zig: Format Zig files with zig-format (bun run zig-format)
In Zig, manage memory carefully with allocators and use defer for cleanup

Files:

  • src/output.zig
  • src/bun.js/test/Execution.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/dots.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/dots.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/dots.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/dots.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/dots.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/dots.test.ts
test/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

test/**/*.test.{ts,tsx}: Test files must be placed under test/ and end with .test.ts or .test.tsx
In tests, always use port: 0; do not hardcode ports or use custom random port functions
In tests, use normalizeBunSnapshot when asserting snapshots
Never write tests that merely assert absence of "panic" or "uncaught exception" in output
Avoid shell commands (e.g., find, grep) in tests; use Bun.Glob and built-ins instead
Prefer snapshot tests over exact stdout equality assertions

Files:

  • test/js/bun/test/dots.test.ts
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Format JavaScript/TypeScript files with Prettier (bun run prettier)

Files:

  • test/js/bun/test/dots.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/Execution.zig
  • src/bun.js/test/jest.zig
🧠 Learnings (14)
📚 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/dots.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/dots.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/dots.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/dots.test.ts
  • src/bun.js/test/Execution.zig
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to test/**/*.test.{ts,tsx} : In tests, use normalizeBunSnapshot when asserting snapshots

Applied to files:

  • test/js/bun/test/dots.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/dots.test.ts
  • src/bun.js/test/Execution.zig
📚 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 : Import common test utilities from `harness` (e.g., `bunExe`, `bunEnv`, `tempDirWithFiles`, `tmpdirSync`, platform checks, GC helpers)

Applied to files:

  • test/js/bun/test/dots.test.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/dots.test.ts
📚 Learning: 2025-08-30T00:09:39.100Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/dev-server-tests.mdc:0-0
Timestamp: 2025-08-30T00:09:39.100Z
Learning: Applies to test/bake/bake-harness.ts : Provide and maintain shared test utilities: devTest, prodTest, devAndProductionTest, Dev, Client, and helpers in the harness

Applied to files:

  • test/js/bun/test/dots.test.ts
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to test/**/*.test.{ts,tsx} : Avoid shell commands (e.g., find, grep) in tests; use Bun.Glob and built-ins instead

Applied to files:

  • test/js/bun/test/dots.test.ts
📚 Learning: 2025-08-30T00:13:36.815Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-08-30T00:13:36.815Z
Learning: Applies to src/bun.js/**/*.zig : Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions

Applied to files:

  • src/bun.js/test/Execution.zig
📚 Learning: 2025-08-30T00:13:36.815Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-08-30T00:13:36.815Z
Learning: Applies to src/bun.js/**/*.zig : Access JS call data via CallFrame (argument(i), argumentCount(), thisValue()) and throw errors with globalObject.throw(...)

Applied to files:

  • src/bun.js/test/Execution.zig
📚 Learning: 2025-09-24T05:48:59.872Z
Learnt from: nektro
PR: oven-sh/bun#22806
File: scripts/runner.node.mjs:687-689
Timestamp: 2025-09-24T05:48:59.872Z
Learning: In the Bun codebase, the `startGroup` utility function in scripts/runner.node.mjs automatically closes any previously open group when called, so `startGroup("End")` correctly closes the final test group and keeps subsequent output ungrouped.

Applied to files:

  • src/bun.js/test/Execution.zig
📚 Learning: 2025-09-08T04:44:59.101Z
Learnt from: CR
PR: oven-sh/bun#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T04:44:59.101Z
Learning: Applies to **/*.zig : In Zig, manage memory carefully with allocators and use defer for cleanup

Applied to files:

  • src/cli/test_command.zig
🧬 Code graph analysis (1)
test/js/bun/test/dots.test.ts (1)
test/harness.ts (2)
  • bunExe (103-106)
  • normalizeBunSnapshot (1809-1840)
⏰ 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 (14)
src/output.zig (2)

524-536: LGTM! Well-designed RAII-style scope guard.

The EnableBufferingScope struct correctly implements a scope-based buffering control mechanism that:

  • Captures the previous enable_buffering state on initialization
  • Restores it on deinitialization
  • Explicitly documents that deinit() does not flush (intentional design choice appropriate for test reporters)

The implementation is thread-safe since enable_buffering is threadlocal (line 429).


538-540: LGTM! Clean factory function for scope guard.

The enableBufferingScope() function provides a clean public API for scoped buffering control. This complements the existing enableBuffering() function (line 520) by offering automatic state restoration via RAII.

Typical usage pattern:

const scope = Output.enableBufferingScope();
defer scope.deinit();
// ... buffered operations ...
// state automatically restored on scope exit
src/cli/test_command.zig (5)

579-588: LGTM! Clean structure for the new reporters.

The addition of last_printed_dot for state tracking and the nested reporters struct grouping dots and junit flags is a clear improvement over the previous single file_reporter field. The default values are appropriate.


1342-1347: LGTM! Reporter initialization is clean.

The initialization correctly checks the test options and sets up the reporters. The dots reporter is just a boolean flag with no memory allocation, while the JUnit reporter is properly instantiated (though needs the destroy fix noted in the previous comment).


1633-1677: Smart indentation for dots mode summary.

The DotIndenter struct and its usage elegantly handle the formatting difference between dots mode (where a newline separates dots from summary) and normal mode (where a space prefixes summary lines).

The logic is correct:

  • When in dots mode AND the last output was a dot: skip indent space, print newline (lines 1644-1646)
  • Otherwise: indent with space

This ensures the summary always has proper spacing regardless of what was printed before it.

One minor suggestion for clarity:

-                const indenter = DotIndenter{ .indent = !(ctx.test_options.reporters.dots and reporter.last_printed_dot) };
+                const should_prepend_newline = ctx.test_options.reporters.dots and reporter.last_printed_dot;
+                const indenter = DotIndenter{ .indent = !should_prepend_newline };

This makes the condition more readable.


1740-1745: Final JUnit write is correct, but relies on the destroy fix.

The final JUnit reporter cleanup correctly:

  1. Closes any open test suite
  2. Writes the report to the configured output file

However, note that this block doesn't destroy the JUnit reporter allocation. That's expected to happen in the defer block at lines 1311-1313 (which needs the destroy() fix noted earlier).

The separation of concerns is appropriate:

  • Lines 1740-1745: Normal completion path - write the report
  • Lines 1311-1313: Cleanup path (both success and error) - destroy the reporter

Just ensure the destroy fix is applied to prevent the memory leak.


845-892: last_printed_dot behavior for skipped_by_label is correct. The code bypasses dot printing and state updates for .skipped_because_label, so last_printed_dot remains accurate and no extra newline issues occur.

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

596-596: LGTM! Correctly passes BunTest context to printIfNeeded.

The updated call to runner.current_file.printIfNeeded(this.bunTest()) correctly provides the BunTest context, which is needed for the new reporter-driven newline logic in dots mode. This aligns with the signature change in src/bun.js/test/jest.zig where printIfNeeded now accepts a bun_test_ parameter.

test/js/bun/test/dots.test.ts (1)

1-42: Well-structured dots reporter test.

The test correctly:

  1. Spawns a Bun test process with --dots flag and a name filter
  2. Captures stdout/stderr via pipes (as per test guidelines)
  3. Uses bunExe(), bunEnv, and normalizeBunSnapshot() from harness
  4. Asserts the full output including exit code, dots, and summary stats

The snapshot expectations appear reasonable:

  • Line 23: .................... shows 20 dots for passing/skipped tests
  • Lines 24-30: Three failing test messages (expected for .failing() tests that passed)
  • Lines 32-36: Summary stats (10 pass, 10 skip, 10 todo, 3 fail across 33 tests)

Minor observation: The filter -t "filterin" on line 6 appears to be matching test names containing "filterin" (likely "filtering" or similar). Ensure the dots.fixture.ts file contains tests with this substring to validate the filter is working as intended.

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

10-30: LGTM! Updated set signature for reporter context.

The updated CurrentFile.set function now accepts a reporter: *CommandLineReporter parameter (line 16), which is needed to check last_printed_dot state for newline decisions. The call to shouldPrependExtraNewline(reporter) at line 29 correctly determines whether an extra newline is needed before printing the filename.

The logic is sound:

  • If AI agent mode: store title/prefix for later printing (lines 18-26)
  • Otherwise: print immediately with reporter-aware newline handling (lines 28-29)

69-80: LGTM! Updated printIfNeeded signature.

The updated printIfNeeded function now accepts bun_test_: *const bun_test.BunTest (line 69), which allows it to access the reporter for state-aware newline decisions. The logic correctly:

  1. Returns early if filename already printed (line 70)
  2. Sets the flag (line 71)
  3. Calls print with reporter-aware newline decision (lines 73-79)

The conditional at line 78 correctly handles both cases:

  • If reporter exists: call shouldPrependExtraNewline(reporter)
  • Otherwise: use false (no extra newline)

489-496: LGTM! Updated JUnit line number capture.

The change from checking runner.test_options.file_reporter == .junit to runner.test_options.reporters.junit (line 491) correctly aligns with the new nested reporters structure. The logic is unchanged: line numbers are only captured when JUnit reporting is enabled.


529-529: LGTM! Added CommandLineReporter import.

The new import of CommandLineReporter from ../../cli/test_command.zig is necessary for the type annotations in the updated CurrentFile functions. This creates a dependency from jest.zig to test_command.zig, which is appropriate given that jest.zig needs to interact with the command-line reporter for dots mode functionality.


37-67: Clarify header newline and simplify flag reset in shouldPrependExtraNewline

  • Optional refactor for shouldPrependExtraNewline:
fn shouldPrependExtraNewline(reporter: *CommandLineReporter) bool {
-    if (reporter.last_printed_dot) {
-        reporter.last_printed_dot = false;
-        return true;
-    }
-    return false;
+    const result = reporter.last_printed_dot;
+    reporter.last_printed_dot = false;
+    return result;
}
  • Confirm whether the unconditional Output.prettyError("<r>\n") is intentional. Please share sample output (first ~20 lines) for:
    • Normal mode: bun test /tmp/test_format.test.ts
    • Dots mode: bun test /tmp/test_format.test.ts --dots

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)
src/bun.js/test/bun_test.zig (1)

717-723: Consider removing redundant flush.

The flush at line 721 appears redundant since line 731 already flushes output after error handling completes. You can remove the bun.Output.flush() call at line 721 to avoid the unnecessary double flush.

Apply this diff:

         } else if (this.reporter) |reporter| {
             if (reporter.last_printed_dot and reporter.reporters.dots) {
                 bun.Output.prettyError("<r>\n", .{});
                 reporter.last_printed_dot = false;
-                bun.Output.flush();
             }
         }
📜 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 fee9dba and 69f870b.

📒 Files selected for processing (1)
  • src/bun.js/test/bun_test.zig (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
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("...", .{})

Files:

  • src/bun.js/test/bun_test.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

**/*.zig: Format Zig files with zig-format (bun run zig-format)
In Zig, manage memory carefully with allocators and use defer for cleanup

Files:

  • src/bun.js/test/bun_test.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
🧠 Learnings (1)
📚 Learning: 2025-08-30T00:13:36.815Z
Learnt from: CR
PR: oven-sh/bun#0
File: .cursor/rules/zig-javascriptcore-classes.mdc:0-0
Timestamp: 2025-08-30T00:13:36.815Z
Learning: Applies to src/bun.js/**/*.zig : Constructors and prototype methods should return bun.JSError!JSC.JSValue to integrate Zig error handling with JS exceptions

Applied to files:

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

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.

3 participants