The Test Command (bun test) is the CLI entry point for running Bun's Jest/Vitest-compatible test framework. It is designed as a high-performance, all-in-one runner that handles test discovery, transpilation (via Bun's native transpiler), execution, and reporting. This document details the CLI interface, the orchestration of test files, and the reporter integration.
For internal test execution flow and lifecycle hooks, see 6.1 For assertion logic, see 6.2
The bun test command is handled by Bun's CLI dispatcher. It supports running tests across JavaScript, TypeScript, and JSX files without external configuration.
Test file discovery is performed by the Scanner struct defined in src/runtime/cli/test/Scanner.rs19-37 The scanner performs a depth-first traversal of directories and collects paths matching recognized test file suffixes (.test.js, .test.ts, .spec.tsx, etc.).
Scanner fields of note:
| Field | Type | Purpose |
|---|---|---|
exclusion_names | &[&[u8]] | Directory names to exclude (e.g., node_modules) |
filter_names | &[&[u8]] | Filename patterns to include; empty means include all matching suffixes |
path_ignore_patterns | &[&[u8]] | Glob patterns matched against the path relative to project root |
test_files | Vec<Interned> | Accumulated paths of discovered test files |
src/runtime/cli/test/Scanner.rs80-99
Discovery Logic:
*.test.{js,ts,jsx,tsx} and *.spec.{js,ts,jsx,tsx} test/cli/test/bun-test.test.ts18-43Scanner::scan returns ScanError::DoesNotExist and the command exits with code 1 src/runtime/cli/test/Scanner.rs50-65| Input Scenario | Resulting Behavior |
|---|---|
bun test | Runs all matching test files in the current working directory recursively. |
bun test ./bar | Runs all test files within the ./bar directory test/cli/test/bun-test.test.ts135-140 |
bun test my-file.ts | Executes the specific file regardless of naming convention test/cli/test/bun-test.test.ts55-60 |
bun test -t "pattern" | Runs only tests whose names match the regex pattern test/cli/test/bun-test.test.ts1144-1160 |
Sources: src/runtime/cli/test/Scanner.rs19-99 test/cli/test/bun-test.test.ts1-140
The test command is orchestrated through a set of structures in the Rust runtime that manage discovery, execution, and reporting.
Primary command entry point and structural relationships:
Sources: src/runtime/cli/test_command.rs1-30 src/runtime/cli/test/Scanner.rs19-37 src/runtime/cli/test/parallel/runner.rs72-95
| Structure | File | Role |
|---|---|---|
TestCommand | test_command.rs | Top-level command handler; owns file list and reporter |
Scanner | Scanner.rs | Discovers test files via filesystem traversal |
CommandLineReporter | test_command.rs | Formats and streams test output to stderr |
JunitReporter | test_command.rs | Builds JUnit XML document incrementally |
Metrics | test_command.rs | Tracks per-suite counts: test_cases, assertions, failures, skipped, elapsed_time |
run_as_coordinator | parallel/runner.rs | Spawns worker subprocesses for --parallel mode |
IsolatedModuleCache | IsolatedModuleCache.h | Per-VM cache for transpiled modules under --isolate |
The JunitReporter struct src/runtime/cli/test_command.rs221-234 tracks offsets into an incrementally written XML buffer so it can backfill aggregate counts after the entire run without reparsing.
The Metrics struct src/runtime/cli/test_command.rs248-255 accumulates per-suite statistics that are rolled up into the JunitReporter::total_metrics field at the end of each file.
Sources: src/runtime/cli/test_command.rs220-265 src/jsc/bindings/IsolatedModuleCache.h24-47
Bun's test runner can be configured via CLI flags to control execution behavior and reporting.
| Flag | Default | Description |
|---|---|---|
--bail[=N] | 1 | Stop the test run after N failures. Without a value, defaults to 1 test/cli/test/bun-test.test.ts299-358 |
--timeout <ms> | 5000 | Set per-test timeout in milliseconds test/cli/test/bun-test.test.ts360-405 |
-t <regex> | — | Filter tests by name using a regex pattern applied to the full test name test/cli/test/bun-test.test.ts1144-1160 |
--rerun-each <N> | — | Re-run each test file N times to catch flakiness test/cli/test/bun-test.test.ts466-491 |
--todo | off | Execute tests marked with test.todo() that have a body test/cli/test/bun-test.test.ts204-227 |
--only | off | Only run tests/blocks marked with test.only(). Redundant outside CI (see CI Restrictions below). |
--update-snapshots | off | Overwrite existing snapshot files with current values. |
--coverage | off | Collect and print code coverage after the run. |
--coverage-reporter | — | Select coverage output format: text or lcov. |
--isolate | off | Run each test file in an isolated module cache src/jsc/bindings/IsolatedModuleCache.h15-19 |
--randomize | off | Shuffle test file order for execution src/runtime/cli/test/parallel/runner.rs163-165 |
--parallel | off | Run test files across multiple worker subprocesses. |
--bail Validation--bail requires a positive integer. Passing 0, a negative number, or a non-numeric string will print an error and exit:
error: --bail expects a number greater than 0
Sources: test/cli/test/bun-test.test.ts299-405
Bun supports multiple reporting formats to accommodate both local development and CI/CD pipelines.
fmt_status_text_line function src/runtime/cli/test_command.rs177-200 selects between emoji (✓, ✗, », ✎) and plain-text ((pass), (fail), (skip), (todo)) variants based on Output::enable_ansi_colors_stderr().JunitReporter src/runtime/cli/test_command.rs221-234 The reporter writes directly into a Vec<u8> buffer, recording placeholder offsets for aggregate counts that are backfilled after the run. Properties such as the CI job URL and commit SHA are written as <properties> on each <testsuite> element.genhtml or uploaded to coverage services.Mapping from test execution events to output paths:
| Result | Emoji mode | Plain text mode |
|---|---|---|
| Pass | ✓ | (pass) |
| Fail | ✗ | (fail) |
| Skip | » | (skip) |
| Todo | ✎ | (todo) |
| Pending | … | (pending) |
Sources: src/runtime/cli/test_command.rs177-212 src/runtime/cli/test_command.rs221-265
The test command monitors for both assertion failures and unhandled exceptions.
expect() matchers. These are captured and reported at the end of the test case test/js/bun/test/test-test.test.ts231-240beforeEach or beforeAll hook throws, the subsequent tests in that scope are skipped to prevent cascading errors test/js/bun/test/test-test.test.ts12-530: All tests passed.1: One or more tests failed, or a fatal error occurred (e.g., non-existent file path) test/cli/test/bun-test.test.ts8-17Async Exception Handling: Bun captures async exceptions (e.g., from an EventEmitter or unhandled promise rejection) and associates them with the currently running test test/js/bun/test/test-test.test.ts231-240
Sources: test/js/bun/test/test-test.test.ts12-53 test/cli/test/bun-test.test.ts8-17 test/js/bun/test/jest-hooks.test.ts100-135
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.