bun test: run tests with Bun's built-in test runner
- tool
- Bun
- versions
- Bun 1.x
- os
- any
bun test runs every test file in the project with Bun's built-in runner: files named *.test.{js,jsx,ts,tsx}, *_test.*, *.spec.* or *_spec.*. Tests import test, expect, describe and the hooks from bun:test, an API compatible with Jest. TypeScript works without configuration. The command exits 0 when every test passes and 1 when any test fails.
Example
cat > math.ts <<'EOF'
export const add = (a: number, b: number) => a + b;
EOF
cat > math.test.ts <<'EOF'
import { describe, expect, test } from "bun:test";
import { add } from "./math";
describe("add", () => {
test("adds two numbers", () => {
expect(add(1, 2)).toBe(3);
});
test("is wrong on purpose", () => {
expect(add(2, 2)).toBe(5);
});
});
EOF
npx --yes bun@1 test 2>&1 | grep -E "^\((pass|fail)\)|^ *[0-9]+ (pass|fail)$|^Expected|^Received" | sed -E 's/ \[[0-9.]+m?s\]$//'
exit "${PIPESTATUS[0]}"Output · exit 1
(pass) add > adds two numbers Expected: 5 Received: 4 (fail) add > is wrong on purpose 1 pass 1 fail
The full output also shows the failing line with a caret under the assertion. In CI, the non-zero exit code fails the job.
Common options
| Command | Effect |
|---|---|
| bun test math | Run only test files whose path contains "math" |
| bun test -t "adds two" | Run only tests whose name matches the pattern (--test-name-pattern) |
| bun test --watch | Re-run on file changes |
| bun test --coverage | Print a coverage table (--coverage-reporter=lcov writes lcov.info) |
| bun test --bail | Stop after the first failure |
| bun test --timeout 10000 | Per-test timeout in milliseconds (default 5000) |
| bun test --update-snapshots | Rewrite toMatchSnapshot() snapshots |
| bun test --rerun-each 10 | Run each test 10 times to find flaky tests |
bun test is a built-in command: if package.json has a "test" script (for example one that runs Vitest), bun test still starts Bun's runner. Use bun run test to run the script.
Writing tests
The API mirrors Jest, imported from bun:test instead of being global:
| API | Use |
|---|---|
| test / it, describe | Define tests and group them |
| beforeAll, beforeEach, afterEach, afterAll | Set up and tear down state around tests |
| test.skip, test.todo | Skip a test, or mark one as planned; run todo tests with --todo |
| expect(x).toBe / toEqual / toThrow | Assertions with Jest-compatible matchers |
| mock(fn) or jest.fn(fn) | Create a mock function and assert on its calls with toHaveBeenCalled |
| expect(x).toMatchSnapshot() | Snapshot testing; snapshots are stored next to the test file |
Behaviour to know
- One process by default. Bun loads every test file in a single process with shared globals, which is fast but means a test that changes global state can affect another file.
--parallelruns files in separate worker processes, one per CPU core by default. - Concurrency is opt-in. Tests inside a file run one after the other;
--concurrentruns async tests in parallel (20 at a time by default, change with--max-concurrency). - CI integration. Inside GitHub Actions,
bun testdetects the environment and emits annotations for failures;--reporter=junitwrites an XML report for other systems. - Types are not checked by default. Like
bun run, the runner strips TypeScript types. Recent Bun versions type-check the tests in the same step withbun test --check; otherwise runtsc --noEmitseparately.
FAQ
Can bun test run my existing Jest tests?
Often, yes: bun:test provides describe, test, expect, lifecycle hooks, snapshots and mocks with Jest-style names, and jest.fn() works as an alias of mock(). Bun aims for Jest compatibility but has not implemented everything, so run the suite and check the failures.
Why does bun test ignore my Vitest config?
bun test is Bun's own runner and does not read vitest.config or jest.config files. To keep using Vitest, run it through your package.json script with bun run test.
How do I get a JUnit report for CI?
Use bun test --reporter=junit --reporter-outfile=./bun.xml. Bun still prints the normal output and writes the XML file for GitLab, Jenkins and similar tools.