# How to Write and Run Tests Using Bun's Built‑in Test Runner

> Learn to write and run tests with Bun's built-in test runner. Discover TypeScript support, snapshots, mocks, and watch mode all dependency-free with bun test.

- Repository: [Bun/bun](https://github.com/oven-sh/bun)
- Tags: how-to-guide
- Published: 2026-02-28

---

**Bun provides a Jest‑compatible test runner accessible via the `bun test` CLI command that supports TypeScript, snapshots, mocks, and watch mode without external dependencies.**

The `oven-sh/bun` repository ships a fast, integrated test framework that mirrors the Node.js `node:test` API while adding Bun‑specific optimizations. You can write tests using `.test.{ts,js,tsx,jsx,mjs,cjs}` files and execute them through the `bun` binary, leveraging the runtime's native TypeScript compilation and ESM/CJS support.

## Writing Tests with the `bun:test` API

The core test implementation lives in [`src/js/node/test.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/test.ts), which exports the global `test` object along with lifecycle hooks and snapshot utilities. This module registers tests with the internal Bun runner and exposes a `TestContext` class providing introspection methods like `ctx.signal`, `ctx.name`, and `ctx.diagnostic()`.

### Importing the Test Module

While `test` and `describe` are available globally, you should import `expect` explicitly from `bun:test` to access Jest‑compatible matchers:

```typescript
import { expect, test, describe, beforeEach, afterEach } from "bun:test";

```

### Basic Test Structure

Create a file ending with [`.test.ts`](https://github.com/oven-sh/bun/blob/main/.test.ts) (or [`.test.js`](https://github.com/oven-sh/bun/blob/main/.test.js), [`.test.tsx`](https://github.com/oven-sh/bun/blob/main/.test.tsx), etc.) and export test cases using the `test()` function:

```typescript
import { expect, test } from "bun:test";

test("adds two numbers", () => {
  expect(1 + 2).toBe(3);
});

test("async operations work", async () => {
  const result = await Promise.resolve(42);
  expect(result).toBe(42);
});

```

As implemented in [`src/js/node/test.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/test.ts), the `test` function accepts an optional options object supporting `timeout`, `skip`, `only`, and `todo` flags.

### Grouping Tests with `describe`

Organize related tests using `describe()` (aliased as `test.describe` and `test.suite` in the source):

```typescript
import { expect, test, describe, beforeEach } from "bun:test";

describe("Array utilities", () => {
  let arr: number[];

  beforeEach(() => {
    arr = [1, 2, 3];
  });

  test("pop removes last element", () => {
    const last = arr.pop();
    expect(last).toBe(3);
    expect(arr).toEqual([1, 2]);
  });

  test.todo("implement shuffle");
});

```

### Lifecycle Hooks

The API exposes `before`, `after`, `beforeEach`, and `afterEach` hooks that delegate to the underlying Bun runner:

```typescript
import { beforeAll, afterAll, beforeEach, afterEach } from "bun:test";

beforeAll(() => {
  // Runs once before all tests in the file
});

beforeEach(() => {
  // Runs before each test
});

```

## Advanced Testing Features

### Skipping and Isolating Tests

Control test execution using modifiers on the `test` function:

- **`test.skip()`** – Excludes the test from execution and prints "skipped".
- **`test.only()`** – Runs only this test and bails early (isolation mode).
- **`test.todo()`** – Marks a test as planned but not yet implemented.

```typescript
test.skip("slow integration test", async () => {
  // This test will not run
});

test.only("focus mode", () => {
  // Only this test executes
});

```

### Snapshot Testing

Bun includes built‑in snapshot support via `expect().toMatchSnapshot()`. The first run stores data in a `__snapshots__` directory, while subsequent runs compare against these stored values:

```typescript
test("output snapshot", () => {
  expect({ user: "alice", id: 123 }).toMatchSnapshot();
});

```

The `test.snapshot` export in [`src/js/node/test.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/test.ts) provides `setDefaultSnapshotSerializer` and `setResolveSnapshotPath` for customizing snapshot behavior.

### Mock Functions

Use Bun's Jest‑compatible mock API to spy on function calls:

```typescript
import { mock, test, expect } from "bun:test";

test("mock function tracking", () => {
  const fn = mock(() => "result");
  fn("arg1");
  fn("arg2");
  
  expect(fn).toHaveBeenCalledTimes(2);
  expect(fn).toHaveBeenCalledWith("arg1");
});

```

### Timeouts and Retries

Configure individual test timeouts using the options parameter or global CLI flags:

```typescript
// 5 second timeout for this specific test
test("slow operation", async () => {
  // ...
}, { timeout: 5_000 });

```

For flaky tests, use the `--retries` CLI flag to automatically re‑run failed assertions.

## Running Tests from the CLI

### Basic Commands

Execute all discovered test files (matching `*.test.*` patterns) with:

```bash
bun test

```

Run a specific file or directory:

```bash
bun test src/utils/string.test.ts
bun test src/lib/

```

### Watch Mode and Coverage

Enable file watching to automatically re‑run tests on changes:

```bash
bun test --watch

```

Generate coverage reports in LCOV format:

```bash
bun test --coverage

```

Additional useful flags include:
- `--bail` – Stop execution after the first failure.
- `--filter <pattern>` – Run only tests matching the description pattern.
- `--timeout <ms>` – Set a global timeout for all tests.

### Debugging with Source Changes

When modifying the Bun runtime source code, you must use the debug build (`bun bd`) rather than the system‑installed binary. According to [`AGENTS.md`](https://github.com/oven-sh/bun/blob/main/AGENTS.md), compile and test with:

```bash

# Build the debug binary

bun bd

# Run tests using the debug build

bun bd test

```

Running `bun test` without the debug prefix would use your globally installed Bun version, missing any local modifications to [`src/js/node/test.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/test.ts) or the runtime.

## Summary

- **Test files** use the `.test.{ts,js,tsx,jsx,mjs,cjs}` extension and are automatically discovered by `bun test`.
- **The `bun:test` module** in [`src/js/node/test.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/test.ts) provides `test`, `describe`, lifecycle hooks, and snapshot utilities with a Jest‑compatible API.
- **CLI execution** supports `--watch` for continuous testing, `--coverage` for LCOV reports, and `--bail` for early exit on failure.
- **Development workflow** requires `bun bd test` when modifying the Bun runtime source to ensure changes are compiled into the test binary.

## Frequently Asked Questions

### Does Bun's test runner require Jest to be installed?

No. Bun's test runner is implemented natively in the runtime and does not require `jest`, `vitest`, or any other external testing framework. The API is Jest‑compatible, allowing migration of existing test suites without configuration changes, but all functionality is built into the `bun` binary itself.

### How do I run a single test file or a specific test?

Run a specific file by passing its path to `bun test`: `bun test path/to/file.test.ts`. To run a specific test within a file, use `test.only()` in your source code or the `--filter` flag with a pattern matching the test description: `bun test --filter "adds two numbers"`.

### What file extensions does Bun recognize for test files?

Bun automatically discovers files ending with [`.test.ts`](https://github.com/oven-sh/bun/blob/main/.test.ts), [`.test.js`](https://github.com/oven-sh/bun/blob/main/.test.js), [`.test.tsx`](https://github.com/oven-sh/bun/blob/main/.test.tsx), [`.test.jsx`](https://github.com/oven-sh/bun/blob/main/.test.jsx), `.test.mjs`, and `.test.cjs`. You can also pass directories to `bun test`, and it will recursively search for matching test files within those paths.

### How do I debug why a test is failing in the Bun runtime source?

When working on the Bun runtime itself (modifying [`src/js/node/test.ts`](https://github.com/oven-sh/bun/blob/main/src/js/node/test.ts) or related source files), use `bun bd` to compile a debug build, then execute `bun bd test`. Using the standard `bun test` command would invoke your system‑installed Bun release, which would not include your local source modifications.