Fix: Jest Snapshot Outdated — 1 snapshot obsolete
Quick Answer
How to fix Jest snapshot failures — updating outdated snapshots, removing obsolete ones, fixing inline snapshots, preventing brittle snapshot tests, and managing snapshots in CI.
The Error
Jest fails with a snapshot mismatch:
● MyComponent › renders correctly
1 snapshot failed.
Snapshot name: `MyComponent renders correctly 1`
- Snapshot - 3
+ Received + 3
<div
className="container"
- style="color: red;"
+ style="color: blue;"
>
- <h1>Old Title</h1>
+ <h1>New Title</h1>
</div>Or obsolete snapshots after deleting tests:
› 1 snapshot obsolete.
• MyComponent renders the old variant 1
Snapshot Summary
› 1 snapshot obsolete from 1 test suite. Re-run Jest with `--updateSnapshot` to remove it.Or in watch mode:
Snapshot Summary
› 3 snapshots failed from 2 test suites. Inspect your code changes or re-run jest with `-u` to update them.Why This Happens
Jest snapshot tests compare the current output of a component or function against a previously saved .snap file. A mismatch occurs when:
- Intentional code change — you updated a component’s markup, styles, or output, and the snapshot reflects the old version. The snapshot needs to be updated to match the new correct output.
- Unintentional regression — a code change accidentally broke something. The snapshot is correctly catching the regression.
- Obsolete snapshot — a test was renamed, moved, or deleted, but the old snapshot entry remains in the
.snapfile. - Dynamic content in snapshot — timestamps, random IDs, or other dynamic values differ on each run, causing snapshots to always fail.
- Environment differences — snapshot generated on one OS or Node version differs slightly from the current environment (rare, usually affects date formatting or whitespace).
Before blindly running --updateSnapshot, determine whether the change is intentional or a bug.
Fix 1: Update Outdated Snapshots (Intentional Changes)
When you’ve intentionally changed a component and the snapshot is just stale:
# Update all failing snapshots
jest --updateSnapshot
# Or the short form
jest -u
# Update snapshots for a specific test file
jest MyComponent.test.tsx --updateSnapshot
# Update in watch mode — press 'u' when prompted
jest --watch
# Then press 'u' to update all failing snapshots
# Or press 'i' to update them one by one interactivelyAfter updating, review the changes in the .snap file with git diff before committing:
git diff src/__snapshots__/This confirms the snapshot changes are exactly what you intended — not an accidental regression.
Common Mistake: Running
jest -uto “fix” CI failures without reviewing what changed. Snapshot tests only catch regressions if you read the diff before accepting it. An unreviewedjest -ucommit is an untested change.
Fix 2: Remove Obsolete Snapshots
Obsolete snapshots are entries in .snap files that no longer correspond to any test. They accumulate when tests are renamed or deleted:
# Remove obsolete snapshots only (doesn't update failing ones)
jest --updateSnapshot
# Or explicitly
jest --ci && jest -u # Will only remove obsolete, update changedManually clean up a .snap file if --updateSnapshot doesn’t help:
// src/__snapshots__/MyComponent.test.tsx.snap
// Delete entries that no longer have corresponding testsIn watch mode, press u to update all snapshots including removing obsolete ones.
Fix 3: Fix Dynamic Values in Snapshots
Snapshots with dynamic content (timestamps, random IDs, generated hashes) fail on every run:
// BAD — snapshot contains the current date, fails tomorrow
test('renders invoice', () => {
const invoice = <Invoice date={new Date()} id={Math.random()} />;
expect(invoice).toMatchSnapshot();
// Snapshot: date="2026-03-19T10:23:45.123Z" id="0.8472651..."
// Tomorrow: date="2026-03-20T..." ← FAILS
});Fix — mock or freeze dynamic values:
// Mock Date to return a fixed value
jest.useFakeTimers();
jest.setSystemTime(new Date('2026-01-01'));
test('renders invoice', () => {
const invoice = <Invoice date={new Date()} id="fixed-test-id" />;
expect(invoice).toMatchSnapshot();
});
afterEach(() => {
jest.useRealTimers();
});Use expect.any() matchers in snapshots for fields that legitimately vary:
test('creates user', () => {
const user = createUser({ name: 'Alice' });
expect(user).toMatchSnapshot({
id: expect.any(String), // Matches any string — ID is dynamic
createdAt: expect.any(Date), // Matches any date
name: 'Alice', // Exact match for stable fields
});
});Use toMatchInlineSnapshot for small outputs — inline snapshots live in the test file and are easier to review:
test('formats price', () => {
expect(formatPrice(9.99)).toMatchInlineSnapshot(`"$9.99"`);
// Jest writes the snapshot directly into the test file on first run
});Fix 4: Use More Specific Assertions Instead of Full Snapshots
Snapshot tests that capture entire component trees are brittle — any trivial change (adding a CSS class, changing a div to a section) breaks them. Use targeted assertions for stable properties:
// BAD — entire component snapshot breaks on any markup change
test('shows username', () => {
render(<UserCard user={{ name: 'Alice', role: 'admin' }} />);
expect(screen.getByRole('article')).toMatchSnapshot();
});
// BETTER — assert on specific behavior, not the full DOM
test('shows username', () => {
render(<UserCard user={{ name: 'Alice', role: 'admin' }} />);
expect(screen.getByText('Alice')).toBeInTheDocument();
expect(screen.getByText('admin')).toBeInTheDocument();
});
// GOOD USE OF SNAPSHOTS — for complex computed output
test('serializes config object', () => {
const config = buildConfig({ env: 'production', debug: false });
expect(config).toMatchSnapshot();
// Snapshot captures the exact config structure — intentional
});Snapshots are most valuable for:
- Complex data transformation output (serializers, formatters)
- CLI output text
- API response shapes (with dynamic fields masked)
- Error message formats
Snapshots are least valuable for:
- Simple component rendering (use
@testing-library/reactqueries instead) - Anything with dynamic content you don’t control
Fix 5: Fix Snapshot Location and Naming
Snapshots are stored in __snapshots__/ directories next to the test files. If tests are moved without moving the snapshots, obsolete entries accumulate:
src/
components/
Button.test.tsx ← test file
__snapshots__/
Button.test.tsx.snap ← auto-generated snapshot fileIf you rename a test file, Jest creates a new snapshot file and the old one becomes orphaned:
# Find orphaned snapshot files
find . -name "*.snap" -not -path "*/node_modules/*"
# Then check if corresponding test files existName snapshots descriptively to make diffs readable:
// Jest uses the test description as the snapshot name
test('renders button in primary variant', () => {
// Snapshot name: "renders button in primary variant 1"
expect(render(<Button variant="primary">Click</Button>).asFragment())
.toMatchSnapshot('primary button'); // Custom name
});Fix 6: Handle Snapshots in CI
In CI, never auto-update snapshots — fail explicitly so the developer must review the change:
# CI script — fail if any snapshot is outdated or obsolete
jest --ci
# --ci flag:
# - Fails if snapshots need updating (doesn't auto-update)
# - Fails if there are obsolete snapshots
# - Disables interactive mode# GitHub Actions example
- name: Run tests
run: jest --ci --coverageIf CI fails on snapshots, the fix is to update them locally and commit the updated .snap files:
# Locally
jest -u # Update all
git add src/__snapshots__/
git commit -m "Update snapshots for Button refactor"Pro Tip: Add
.snapfiles to your PR review checklist. Snapshot diffs often reveal unintended changes — a snapshot growing by 20 lines might mean a component is now rendering unexpected content.
Fix 7: Regenerate All Snapshots from Scratch
If snapshots are severely out of date across many files, regenerate them all:
# Delete all snapshot files
find . -name "*.snap" -not -path "*/node_modules/*" -delete
# Run tests — all snapshots fail because no .snap files exist
# Jest creates fresh snapshots automatically
jest -uReview the newly created snapshots carefully with git diff before committing.
Still Not Working?
Check for non-deterministic rendering. If a snapshot fails inconsistently, the component output varies between renders. Common causes:
- Async data loading without proper mocking
- CSS-in-JS libraries that generate class names with counters
- Third-party components with internal state
Serialize custom objects. If your snapshot shows [Object] instead of the actual content, Jest doesn’t know how to serialize it. Add a custom serializer:
// jest.config.js
module.exports = {
snapshotSerializers: ['enzyme-to-json/serializer'],
// Or for custom types:
// snapshotSerializers: ['./src/test/myCustomSerializer'],
};Reset snapshot counters. Each toMatchSnapshot() call in a test gets a numbered name (snapshot 1, snapshot 2). If you add a snapshot call before existing ones, all subsequent numbers shift and every snapshot fails. Use explicit names:
// Without name — fragile, renumbers on insertion
expect(a).toMatchSnapshot(); // "renders correctly 1"
expect(b).toMatchSnapshot(); // "renders correctly 2"
// With name — stable
expect(a).toMatchSnapshot('initial state');
expect(b).toMatchSnapshot('after click');For related testing issues, see Fix: Jest Test Timeout and Fix: Jest Mock Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Jest Setup File Not Working — setupFilesAfterFramework Not Running or Globals Not Applied
How to fix Jest setup file issues — setupFilesAfterFramework vs setupFiles, global mocks not applying, @testing-library/jest-dom matchers, module mocking in setup, and TypeScript setup files.
Fix: Jest Async Test Timeout — Exceeded 5000ms or Test Never Resolves
How to fix Jest async test timeouts — missing await, unresolved Promises, done callback misuse, global timeout configuration, fake timers, and async setup/teardown issues.
Fix: Jest Coverage Not Collected — Files Missing from Coverage Report
How to fix Jest coverage not collecting all files — collectCoverageFrom config, coverage thresholds, Istanbul ignore comments, ts-jest setup, and Babel transform issues.
Fix: Jest Fake Timers Not Working — setTimeout and setInterval Not Advancing
How to fix Jest fake timers not working — useFakeTimers setup, runAllTimers vs advanceTimersByTime, async timers, React testing with act(), and common timer test mistakes.