toMatchSnapshot() basic usage
Use the `.toMatchSnapshot()` matcher to save the output of a value and compare it against future test runs. On the first run, Bun serializes the argument and writes it to a snapshot file in a `__snapshots__` directory alongside the test file. On future runs, Bun compares the argument against the saved snapshot.
Snapshot file location and format
Bun creates a `__snapshots__` directory alongside the test file. For a test file named `snap.test.ts`, the snapshot file is `__snapshots__/snap.test.ts.snap`. The snapshot file contains exports with test names and their snapshot values, for example: `exports[`snap 1`] = `"foo"`;`
Update snapshots command
Regenerate snapshots by running `bun test --update-snapshots`. Use this when you have intentionally changed the output or added new snapshot tests.
toMatchInlineSnapshot() for inline snapshots
Use `.toMatchInlineSnapshot()` to store snapshots directly in the test file instead of a separate snapshot file. Inline snapshots are good for smaller values. On the first run, Bun automatically updates the test file to insert the snapshot value inline as an argument to the matcher.
Inline snapshot workflow
To use inline snapshots: (1) Write your test with `.toMatchInlineSnapshot()` and leave it empty, (2) Run the test once, (3) Bun automatically updates your test file with the snapshot value, (4) On subsequent runs, Bun compares the value against the inline snapshot stored in the file.
toThrowErrorMatchingSnapshot() for error snapshots
Snapshot error messages using `.toThrowErrorMatchingSnapshot()` for external snapshot files or `.toThrowErrorMatchingInlineSnapshot()` for inline snapshots. These matchers capture and compare error messages thrown by the function.
Property matchers in snapshots
Use property matchers to handle values that change between test runs, like timestamps or IDs. Pass a second argument to `.toMatchSnapshot()` with property matchers: `expect(user).toMatchSnapshot({ id: expect.any(Number), createdAt: expect.any(String) })`. The snapshot file will store `Any<Number>` and `Any<String>` for these properties instead of the actual values.
Snapshot best practices: keep snapshots small
Keep snapshots focused and small. Avoid snapshotting entire page renders or huge objects that produce thousands of lines, as they are difficult to review and maintain.
Snapshot best practices: use descriptive test names
Use clear, descriptive test names that explain what the snapshot represents. This makes it easier to understand what is being tested when reviewing snapshot changes.
Snapshot best practices: group related snapshots
Use `describe()` blocks to group related snapshots together. This keeps snapshot files organized and makes it easier to manage related tests.
Snapshot best practices: normalize dynamic data
For dynamic data like timestamps or IDs, either normalize the data before snapshotting (by replacing dynamic values with static strings) or use property matchers. This prevents snapshot failures due to data that changes on every test run.
Reviewing snapshot changes with git
Review snapshot changes using `git diff __snapshots__/`. Update snapshots if changes are intentional using `bun test --update-snapshots`, then commit the updated snapshots with `git add __snapshots__/` and `git commit`.
Snapshot failure causes and troubleshooting
When snapshots fail, common causes are: intentional changes (update with `--update-snapshots`), unintentional changes (fix the code), dynamic data (use property matchers), or environment differences (normalize the data). Diffs show the expected versus received values.
Platform differences in snapshots
Be aware of platform-specific differences in snapshots. For example, file paths differ between Windows and Unix. Normalize paths in snapshots by replacing backslashes with forward slashes using `.replace(/\\/g, "/")`.
Example: basic snapshot test
```ts
import { test, expect } from "bun:test";
test("snap", () => {
expect("foo").toMatchSnapshot();
});
```
This test snapshots the string "foo". On the first run, Bun creates a snapshot file. On subsequent runs, it compares the value against the saved snapshot.
Example: inline snapshot test
```ts
import { test, expect } from "bun:test";
test("inline snapshot", () => {
expect({ hello: "world" }).toMatchInlineSnapshot(`
{
"hello": "world",
}
`);
});
```
This test uses an inline snapshot stored directly in the test file.
Example: error snapshot test
```ts
import { test, expect } from "bun:test";
test("error snapshot", () => {
expect(() => {
throw new Error("Something went wrong");
}).toThrowErrorMatchingSnapshot();
expect(() => {
throw new Error("Another error");
}).toThrowErrorMatchingInlineSnapshot(`"Another error"`);
});
```
This test snapshots error messages from functions that throw.
Example: snapshot with property matchers
```ts
import { test, expect } from "bun:test";
test("snapshot with dynamic values", () => {
const user = {
id: Math.random(),
name: "John",
createdAt: new Date().toISOString(),
};
expect(user).toMatchSnapshot({
id: expect.any(Number),
createdAt: expect.any(String),
});
});
```
This test uses property matchers to ignore dynamic values that change on each run while still snapshotting the rest of the object.
Example: snapshot with normalized data
```ts
import { test, expect } from "bun:test";
test("API response format", () => {
const response = {
data: { id: 1, name: "Test" },
timestamp: Date.now(),
requestId: generateId(),
};
expect({
...response,
timestamp: "TIMESTAMP",
requestId: "REQUEST_ID",
}).toMatchSnapshot();
});
```
This test normalizes dynamic data by replacing changing values with static strings before snapshotting.