Snapshot Testing

A snapshot assertion has no expected value written by hand: the first run records what the component rendered, and every later run compares against that record. Write toMatchInlineSnapshot() with empty parentheses, run once, and the runner rewrites the test file in place:

src/Badge.test.jsx after Vitest filled in the snapshotJSX
test('renders a warning badge', () => {
  const { container } = render(<Badge level="warning">Late</Badge>);
  expect(container.firstChild).toMatchInlineSnapshot(`
    <span
      class="badge badge-warning"
    >
      Late
    </span>
  `);
});

Now change the component — swap the class for a Bootstrap 5 2,007 utility, add a data attribute — and the mismatch is reported as a diff:

Output of 128
 FAIL  src/Badge.test.jsx > renders a warning badge: snapshot mismatched
- Expected
+ Received
  <span
-   class="badge badge-warning"
+   class="badge text-bg-warning"
+   data-level="warning"
  >
    Late
  </span>

You did not have to predict the markup, and nothing can change without somebody approving it. Press u in watch mode, or run vitest run -u, to accept the new output. toMatchSnapshot() writes to __snapshots__/Badge.test.jsx.snap instead, which suits large trees; the inline form keeps the expectation in the pull request diff. Both are committed — a snapshot nobody reviews is not a test.

The failure mode is social rather than technical. A large snapshot that breaks on every unrelated change trains the team to run -u without reading the diff, and once that habit forms the snapshot detects nothing. Keep them small — one element, not a page — and never snapshot anything unstable: a date, a random id, a generated class name. Prefer an explicit assertion whenever you can name what you mean: expect(badge).toHaveClass('text-bg-warning') says that this class matters and the rest do not. Snapshots earn their place locking down a design-system primitive and characterizing legacy code before a refactor.