Skip to main content
Snapshot testing captures the output of your code and saves it to a file. Future test runs compare against the saved snapshot, making it easy to catch unexpected changes.

Basic usage

Use toMatchSnapshot() to create a snapshot:
import { test, expect } from "bun:test";

test("component renders correctly", () => {
  const html = renderComponent({ name: "Alice", age: 30 });
  expect(html).toMatchSnapshot();
});
The first time this test runs, Bun creates a snapshot file:
__snapshots__/
  my-test.test.ts.snap
The snapshot file contains:
// Bun Snapshot v1, https://bun.sh/docs/test/snapshots

exports[`component renders correctly 1`] = `
<div>
  <h1>Alice</h1>
  <p>Age: 30</p>
</div>
`;

Inline snapshots

Inline snapshots write the expected value directly into your test file:
import { test, expect } from "bun:test";

test("inline snapshot", () => {
  const data = { name: "Alice", age: 30 };
  expect(data).toMatchInlineSnapshot();
});
After the first run, Bun updates your test file:
test("inline snapshot", () => {
  const data = { name: "Alice", age: 30 };
  expect(data).toMatchInlineSnapshot(`
{
  "name": "Alice",
  "age": 30,
}
`);
});

Named snapshots

Provide a name to identify the snapshot:
import { test, expect } from "bun:test";

test("renders different states", () => {
  expect(render({ loading: true })).toMatchSnapshot("loading state");
  expect(render({ error: true })).toMatchSnapshot("error state");
  expect(render({ data: [] })).toMatchSnapshot("empty state");
});

Updating snapshots

When your output changes intentionally, update snapshots:
$ bun test --update-snapshots
Or use the shorthand:
$ bun test -u
This updates all snapshots to match the current output.

Property matchers

Use property matchers to ignore dynamic values:
import { test, expect } from "bun:test";

test("user object", () => {
  const user = {
    id: Math.random(), // Changes every time
    name: "Alice",
    createdAt: new Date()
  };
  
  expect(user).toMatchSnapshot({
    id: expect.any(Number),
    createdAt: expect.any(Date)
  });
});
The snapshot will be:
exports[`user object 1`] = `
{
  "id": Any<Number>,
  "name": "Alice",
  "createdAt": Any<Date>,
}
`;

Snapshot testing best practices

Keep snapshots small

Snapshot large outputs can make it hard to review changes:
// ❌ Bad: Snapshots entire page
test("renders page", () => {
  const html = renderPage();
  expect(html).toMatchSnapshot();
});

// ✅ Good: Snapshots specific component
test("renders header", () => {
  const html = renderHeader();
  expect(html).toMatchSnapshot();
});

Use inline snapshots for small values

Inline snapshots make tests more readable:
import { test, expect } from "bun:test";

test("formats date", () => {
  expect(formatDate(new Date("2024-01-01"))).toMatchInlineSnapshot(`"January 1, 2024"`);
});

Review snapshot changes carefully

When updating snapshots, review the changes to ensure they’re intentional:
# View diff before updating
$ bun test

# If changes are correct
$ bun test --update-snapshots

Don’t snapshot implementation details

Snapshot user-facing output, not internal state:
// ❌ Bad: Snapshots internal state
test("state machine", () => {
  const machine = createMachine();
  machine.transition("NEXT");
  expect(machine._internalState).toMatchSnapshot();
});

// ✅ Good: Snapshots public API
test("state machine", () => {
  const machine = createMachine();
  machine.transition("NEXT");
  expect(machine.currentState).toBe("active");
});

Snapshot file location

Snapshots are stored in __snapshots__ directories:
test/
├── __snapshots__/
│   ├── component.test.ts.snap
│   └── utils.test.ts.snap
├── component.test.ts
└── utils.test.ts

CI environments

In CI, Bun prevents creating new snapshots:
$ CI=true bun test
# Error: New snapshot created in CI environment
To update snapshots in CI:
$ CI=true bun test --update-snapshots

Snapshot serialization

Bun uses the same serialization as Jest:
  • Objects are pretty-printed with sorted keys
  • Strings preserve whitespace and escaping
  • React elements are serialized to readable JSX
  • Custom serializers can be added

Custom serializers

Add custom serializers for specific types:
import { expect } from "bun:test";

expect.addSnapshotSerializer({
  test: (val) => val instanceof URL,
  serialize: (val) => `URL<${val.href}>`
});

test("url snapshot", () => {
  const url = new URL("https://example.com/path");
  expect(url).toMatchInlineSnapshot(`URL<https://example.com/path>`);
});

Interactive snapshot updates

When running tests interactively, Bun prompts you to update snapshots:
 FAIL  test/component.test.ts
  ✖ component renders correctly
    
    Received: "<div>New HTML</div>"
    
    › Press u to update snapshots
    › Press s to skip
Press u to update the snapshot or s to skip.

Build docs developers (and LLMs) love