Skip to main content

Overview

Snapshot testing captures the rendered output of a component and saves it as a reference. Future test runs compare the current output against the saved snapshot, detecting any unexpected changes. This is particularly useful for catching unintended UI regressions.

How Snapshot Testing Works

  1. First Run: Vitest renders your component and saves the output to a __snapshots__ directory
  2. Subsequent Runs: Vitest compares new renders against the saved snapshot
  3. On Changes: If output differs, the test fails and shows you the difference
  4. Update Snapshots: If changes are intentional, update the snapshot

Creating Snapshot Tests

Here’s a real example from the codebase:
MyAwesomeApp.test.tsx
import { describe, expect, test } from "vitest";
import { render, screen } from "@testing-library/react";
import { MyAwesomeApp } from "./MyAwesomeApp";

describe("MyAwesomeApp", () => {
  test("should match snapshot", () => {
    const { container } = render(<MyAwesomeApp />);
    expect(container).toMatchSnapshot();
  });

  test("should match snapshot with screen", () => {
    render(<MyAwesomeApp />);
    expect(screen.getByTestId("div-app")).toMatchSnapshot();
  });
});

Snapshot Methods

test("should match snapshot", () => {
  const { container } = render(<MyAwesomeApp />);
  expect(container).toMatchSnapshot();
});

Generated Snapshot Files

When you run snapshot tests, Vitest creates a __snapshots__ directory containing .snap files:
MyAwesomeApp.test.tsx.snap
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`MyAwesomeApp > should match snapshot 1`] = `
<div>
  <div
    data-testid="div-app"
  >
    <h1
      data-testid="firts-namee"
    >
      angels
    </h1>
    <h3>
      mejia
    </h3>
    <p
      class="miClaseFavorita"
    >
      forrnite,gd,metro
    </p>
    <h1>
      :,vv
    </h1>
    <p
      style="background-color: red; border-radius: 10px; padding: 10px;"
    >
      {"zipCode":"ABC-123","country":"abasolo"}
    </p>
  </div>
</div>
`;
Snapshot files should be committed to version control. They serve as documentation of your component’s output and allow reviewers to see UI changes in pull requests.

Updating Snapshots

When you intentionally change a component’s output, snapshots need updating:
npm test -- -u

When to Update Snapshots

  • You intentionally changed the component’s UI
  • You added or removed elements
  • You updated text content, styles, or attributes
  • A dependency update changed rendering output
Always review snapshot diffs carefully before updating. Unexpected changes might indicate bugs rather than intended modifications.

Snapshot Testing Best Practices

1. Keep Snapshots Small and Focused

// Good: Test specific parts of the component
test("should render user profile section", () => {
  render(<App />);
  const profile = screen.getByTestId("user-profile");
  expect(profile).toMatchSnapshot();
});

// Avoid: Snapshotting entire large components
test("should render entire app", () => {
  const { container } = render(<App />);
  expect(container).toMatchSnapshot(); // Too large, hard to review
});

2. Combine with Specific Assertions

test("should render user details", () => {
  render(<MyAwesomeApp />);
  
  // Specific assertions
  const h1 = screen.getByTestId("firts-namee");
  expect(h1.innerHTML).toContain("angels");
  
  // Plus snapshot for overall structure
  expect(screen.getByTestId("div-app")).toMatchSnapshot();
});

3. Use Descriptive Test Names

Snapshot file exports use your test names, so make them clear:
// Good: Clear, descriptive name
test("should match snapshot with user data", () => {
  // ...
});

// Avoid: Vague name
test("snapshot test 1", () => {
  // ...
});

When to Use Snapshot Testing

Good Use Cases:
  • Testing component structure and layout
  • Catching unintended CSS or style changes
  • Verifying consistent rendering across refactors
  • Testing configuration objects or data structures
When to Avoid:
  • Components with dynamic data (timestamps, random IDs)
  • Large components (breaks are hard to review)
  • Testing logic or behavior (use specific assertions instead)
Snapshot testing complements but doesn’t replace traditional assertions. Use both for comprehensive test coverage: snapshots for structure, assertions for specific behavior.

Troubleshooting

Snapshot Mismatches

When a snapshot test fails:
  1. Review the diff: Vitest shows what changed
  2. Check if intentional: Did you mean to change the output?
  3. Update if correct: Run npm test -- -u to update
  4. Fix bug if incorrect: Revert your code changes

Dynamic Content

For components with timestamps or random values:
// Use snapshot matchers for dynamic values
expect(container).toMatchSnapshot({
  createdAt: expect.any(Date),
  id: expect.any(String)
});

Running Snapshot Tests

# Run all tests including snapshots
npm test

# Update snapshots after intentional changes
npm test -- -u

# Run only snapshot tests (if you name them consistently)
npm test snapshot

Next Steps

  • Review snapshot diffs in pull requests
  • Set up CI/CD to catch snapshot failures
  • Learn about inline snapshots with toMatchInlineSnapshot()
  • Explore custom snapshot serializers for cleaner output

Build docs developers (and LLMs) love