new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Bun · Test runner · all subjects

test/configuration

136 notes in this subject, read out of this brain and free to use. This is page 2 of 3.

--parallel flag for test file parallelism

The --parallel flag runs test files across N worker processes (default: number of CPU cores). It implies --isolate unless --no-isolate is specified. Usage: 'bun test --parallel' for one worker per CPU core, or 'bun test --parallel=4' for exactly 4 workers.

--concurrent flag for concurrent tests within a file

The --concurrent flag or test.concurrent() lets async tests in the same file overlap while one is awaiting. This is cooperative concurrency for I/O-bound tests, not extra CPU cores. Individual tests or whole describe groups can be marked with test.concurrent(). Use test.serial to opt out of --concurrent. Default max concurrency is 20; it can be capped with --max-concurrency=N.

--shard flag for splitting suite across CI machines

The --shard=i/n flag runs the i-th of n deterministic slices of the suite. Every machine sorts discovered test files by path and takes a deterministic slice, so together the shards cover each file exactly once with no coordination. Without --timings, file i of the sorted list goes to shard (i mod n) + 1 — balanced by file count.

--isolate flag for fresh global per file

The --isolate flag runs each test file in a fresh JavaScript global object inside the same process. Between files Bun creates a new globalThis, clears the ESM and CommonJS module registries, closes servers and sockets, cancels timers, and re-runs --preload scripts in the new global. --parallel implies --isolate unless --no-isolate opts out. Transpiled source and bytecode are cached at process level and shared across globals.

Three independent parallelism knobs for bun test

bun test has three independent knobs for running multiple things at once: --parallel (test files in processes), --concurrent / test.concurrent (tests within one file), and --shard (test files across machines). They compose: a CI job can run 'bun test --shard=2/4 --parallel' and files in that shard can still contain test.concurrent tests.

Worker environment variables for --parallel

Each worker in a --parallel run gets BUN_TEST_WORKER_ID and JEST_WORKER_ID environment variables set to its 1-based index, so tests can pick a distinct database, port range, or temp directory per worker.

File distribution strategy in --parallel

Files are sorted by path and split into one contiguous chunk per worker, so files in the same directory usually land in the same process. When a worker drains its chunk it steals the back half of the largest remaining chunk. With --timings, chunks are cut by recorded duration instead of file count, each worker starts its slowest file first, and an idle worker steals the slowest not-yet-started file.

Worker lazy start with --parallel-delay

Workers start lazily in --parallel mode. The first worker starts immediately; the rest are only spawned once every running worker has been busy for a few milliseconds. The delay is controlled by --parallel-delay (default 5ms). A suite of tiny files therefore runs on a single worker with no process-spawn overhead, while the first slow file triggers full fan-out.

Flags forwarded to --parallel workers

Flags that affect how tests execute (--timeout, --preload, --define, --coverage, --update-snapshots, -t, --retry, --rerun-each, --concurrent, --randomize/--seed, and others) are forwarded to workers. --bail is handled by the coordinator at file granularity: once the failure threshold is reached no new files are started, but files already running finish.

Worker crash handling in --parallel

If a worker crashes (a native addon segfaults, or a test calls process.exit), the file it was running is reported as failed and a replacement worker picks up the remaining files. A crash from a fatal signal aborts the whole run so it can't be masked by later passing files.

When --parallel helps vs. when it doesn't

The --parallel flag pays off when the suite is dominated by test execution — I/O waits, computation, subprocesses, many files. It costs something: every file re-evaluates its imports in a fresh global and each worker is a separate process with its own JIT warm-up. For a suite of very fast files that all import the same large module graph, plain 'bun test' can be faster.

Concurrent tests share thread and global

Concurrent tests marked with test.concurrent() share a thread and a global object. This is cooperative concurrency for I/O-bound tests, not extra CPU cores. expect.assertions() and other per-test global state need care under concurrency.

concurrentTestGlob configuration option

The concurrentTestGlob option in bunfig.toml can turn on --concurrent for matching files only, providing file-level configuration of concurrent test execution.

Default isolation behavior without --isolate

Without --isolate (the default), all files share one global and one module registry. This is the fastest mode and is fine for suites whose files don't leak state into each other.

How Bun caches transpiled source with --isolate

To keep the cost of --isolate low, transpiled source and bytecode are cached at the process level and shared across globals: the second file to import a module skips reading, transpiling and parsing it and goes straight to evaluation. Only the module's top-level code runs again.

Timings file format for --timings

The timings file format is plain JSON with a version field and a files object containing file paths as keys and wall-clock milliseconds for the whole file as values, listed slowest first. Example: {"version": 1, "files": {"test/integration/build.test.ts": 41234, "test/db/migrate.test.ts": 9876}}. Paths are relative to the project root.

Default concurrent test limit

The default maximum number of concurrent tests running at once is 20, and can be capped with --max-concurrency=N.

Concurrent test example

Example of concurrent tests: test.concurrent("GET /users", async () => { const res = await fetch(`${baseUrl}/users`); expect(res.status).toBe(200); }); These async tests overlap while one is awaiting. test.serial marks individual tests to run after the concurrent group, alone.

How Bun approaches parallelism compared to Jest and Vitest

Bun offers performance advantages through multiple parallelism knobs (--parallel, --concurrent, --shard) that can be combined. With a fresh global per file, Bun shares transpiled source and bytecode across globals so nothing is re-parsed, but module evaluation and JIT warm-up still repeat. In benchmarks, 'bun test --parallel --no-isolate' is fastest (0.75s for 2000 files), followed by single-process 'bun test' (2.4s), then 'bun test --parallel' (6.8s), outperforming comparable Vitest and Jest configurations.

JUnit reporter configuration in bunfig.toml

The JUnit reporter can be configured in bunfig.toml under [test.reporter] section with the key `junit = "path/to/junit.xml"` to specify the output path for the JUnit XML report.

bun test --conditions flag for package.json conditions

The --conditions flag sets package.json conditions for module resolution. Example: bun test --conditions development

Hot reloading with --hot flag

The --hot flag is similar to --watch but more aggressive about preserving state between runs. For most tests, --watch is recommended as it provides better isolation between runs.

bun test --prefer-offline and --frozen-lockfile flags

The --prefer-offline and --frozen-lockfile flags affect any network requests or auto-installs during test execution.

Watch mode with --watch flag

The --watch flag enables watch mode, where the test runner watches for file changes and re-runs tests.

Global test functions available without import

The following are available globally in test files without importing: test, describe, it (alias for test), beforeAll, beforeEach, afterAll, afterEach, expect, jest, and vi.

bun test exit codes

bun test uses standard exit codes: 0 means all tests passed with no unhandled errors, and 1 means test failures or unhandled errors occurred.

Signal handling for test runner

The test runner handles common signals: SIGTERM gracefully stops test execution, and SIGKILL immediately stops test execution.

GitHub Actions and CI environment detection

Bun automatically detects certain environments: when process.env.GITHUB_ACTIONS is set, Bun automatically emits GitHub Actions annotations. When process.env.CI is set, certain behaviors may be adjusted for CI environments.

Tests run in single process by default

The test runner runs all tests in a single process by default, providing faster startup with no need to spawn multiple processes, efficient resource usage through shared memory, and simple debugging. However, tests share global state (requiring cleanup with lifecycle hooks), one test crash can affect others, and there is no true parallelization of individual tests.

NODE_ENV defaults to 'test' in bun test

bun test sets $NODE_ENV to 'test' unless it is already set in the environment or in .env files. This can be overridden by explicitly setting NODE_ENV when running bun test.

bun test --env-file flag for environment variables

The --env-file flag loads environment variables for tests. Example: bun test --env-file .env.test

Default test timeout is 5000ms

Each test has a default timeout of 5000ms (5 seconds). Tests that exceed this timeout fail.

Global timeout flag for tests

Change the timeout globally for all tests using the --timeout flag with bun test, specifying the timeout in milliseconds. Example: bun test --timeout 10000 sets a 10 second timeout.

Per-test timeout as third argument

Set a per-test timeout by passing a number as the third argument to the test function. Example: test('name', () => {}, 1000) sets a 1 second timeout for that test.

Disable timeout with 0 or Infinity

Pass 0 or Infinity as the timeout value to a test to disable the timeout and allow it to run indefinitely.

Unhandled errors cause non-zero exit code

bun test tracks unhandled promise rejections and errors that occur between tests. If any occur, the final exit code is non-zero, even if all tests pass. This catches errors in asynchronous code that might otherwise go unnoticed.

bun test memory flag --smol

The --smol flag reduces memory usage for the test runner VM.

bun test debugging flags --inspect and --inspect-brk

The --inspect flag attaches the debugger to the test runner process. The --inspect-brk flag does the same but breaks at startup.

bun test --preload flag for setup scripts

The --preload flag runs scripts before test files, which is useful for global setup and mocks. Example: bun test --preload ./setup.ts

bun test --define flag for compile-time constants

The --define flag sets compile-time constants. Example: bun test --define "process.env.API_URL='http://localhost:3000'"

bun test --tsconfig-override flag

The --tsconfig-override flag allows using a different tsconfig file. Example: bun test --tsconfig-override ./test-tsconfig.json

bun test --loader flag for file extension mapping

The --loader flag maps file extensions to built-in loaders. Example: bun test --loader .svg:text

Verify at least one assertion with expect.hasAssertions()

Use expect.hasAssertions() to verify that at least one assertion is called during a test. This is especially useful in async tests to ensure assertions run.

Verify exact assertion count with expect.assertions(count)

Use expect.assertions(count) to verify that a specific number of assertions are called during a test. This helps ensure all assertions run, especially in complex async code.

Type testing with expectTypeOf

Bun includes expectTypeOf for testing TypeScript types, compatible with Vitest. These are no-ops at runtime; run TypeScript separately with 'bunx tsc --noEmit' to verify type checks.

Basic matchers in Bun

Bun implements: .not, .toBe(), .toEqual(), .toBeNull(), .toBeUndefined(), .toBeNaN(), .toBeDefined(), .toBeFalsy(), .toBeTruthy(), .toStrictEqual().

String and array matchers in Bun

Bun implements: .toContain(), .toHaveLength(), .toMatch(), .toContainEqual(), .stringContaining(), .stringMatching(), .arrayContaining().

Object matchers in Bun

Bun implements: .toHaveProperty(), .toMatchObject(), .toContainAllKeys(), .toContainValue(), .toContainValues(), .toContainAllValues(), .toContainAnyValues(), .objectContaining().

Number matchers in Bun

Bun implements: .toBeCloseTo(), .closeTo(), .toBeGreaterThan(), .toBeGreaterThanOrEqual(), .toBeLessThan(), .toBeLessThanOrEqual().

Function and class matchers in Bun

Bun implements: .toThrow(), .toBeInstanceOf().

Promise matchers in Bun

Bun implements: .resolves(), .rejects().

Mock function matchers in Bun

Bun implements: .toHaveBeenCalled(), .toHaveBeenCalledTimes(), .toHaveBeenCalledWith(), .toHaveBeenLastCalledWith(), .toHaveBeenNthCalledWith(), .toHaveReturned(), .toHaveReturnedTimes(), .toHaveReturnedWith(), .toHaveLastReturnedWith(), .toHaveNthReturnedWith().

Utility matchers in Bun

Bun implements: .extend, .anything(), .any(), .assertions(), .hasAssertions().

Snapshot matchers in Bun

Bun implements: .toMatchSnapshot(), .toMatchInlineSnapshot(), .toThrowErrorMatchingSnapshot(), .toThrowErrorMatchingInlineSnapshot().

addSnapshotSerializer not yet implemented

.addSnapshotSerializer() is not yet implemented in Bun.

Bun aims for complete Jest compatibility

Long term, Bun aims for complete Jest compatibility. Currently, a limited set of expect matchers is supported. See the tracking issue at github.com/oven-sh/bun/issues/1825 for full compatibility status.

Import test utilities from bun:test

Test utilities are imported from the built-in 'bun:test' module, including test, expect, describe, beforeEach, afterEach, and other test functions.

Basic test structure

A basic test is defined by calling test() with a test name string and a callback function. The callback receives the test context and should contain expect() assertions.

Group tests with describe blocks

Group related tests using describe(). Multiple test() calls can be nested within a describe() to organize tests into suites.

Per-test timeout in milliseconds

Pass a number as the third argument to test() to specify a per-test timeout in milliseconds. Example: test('wat', async () => { ... }, 500) sets a 500ms timeout.

Give your agent this brain