Keeping UI Tests Maintainable with Jest Snapshot Testing
Snapshot tests capture a React component's rendered output and compare it against a stored snapshot, flagging unexpected changes. This post explains setup, a worked example, and how to manage brittleness.
15 Sept 2025, 22:52 UTC

The problem: silent UI drift in fast-moving React code
When a React component changes, the visual output can shift in subtle ways. A developer might tweak a CSS class, add a new prop, or refactor a helper. Without a check, the component can render differently for users. Writing full end-to-end assertions for every visual tweak is slow, and a large set of manual assertions becomes hard to maintain.
Thesis: treat rendered output as a reviewable contract
Jest snapshot testing captures a component's rendered output once and compares future renders against the stored version. Changes surface as diffs, so the team can accept intentional updates and reject regressions in code review.
How snapshots work
Calling expect(value).toMatchSnapshot() records the serialized value on first run into a .snap file under __snapshots__ next to the test file. Later runs read that file and compare. Because snapshots are plain text, Git tracks them and pull requests show the diff.
Minimal setup
Install jest and react-test-renderer for development. Configure Jest to use jsdom for DOM APIs.
module.exports = {
testEnvironment: 'jsdom'
}
Create a test file that renders the component and calls toMatchSnapshot().
Worked example with a Button component
A Button accepts label and an optional primary flag. The test renders it and snapshots the tree.
// Button.test.jsx
import React from 'react'
import renderer from 'react-test-renderer'
import Button from './Button'
test('Button renders correctly', () => {
const tree = renderer.create().toJSON()
expect(tree).toMatchSnapshot()
})
Run the test with npx jest Button.test.jsx. The first run creates the snapshot file. Subsequent runs compare the current render to the stored snapshot and fail with a diff if it changed.
When a change is intentional, update snapshots with npx jest Button.test.jsx --updateSnapshot. Review the diff in Git before committing.
Trade-offs and limitations
Snapshots can become brittle when output changes frequently due to theming, layout shifts, or data-driven content. Large diffs hide real regressions and frequent updates can mask bugs.
Keep snapshots small by splitting complex components and snapshotting sub-components separately. For noisy trees, consider shallow rendering to limit depth. Avoid snapshotting values that change on every run, such as timestamps or random IDs.
Actionable take-aways
- Use snapshots for components with stable output that change infrequently.
- Version snapshots in Git and review changes in pull requests.
- Run jest --ci in CI so the build fails if snapshots are out of date until --updateSnapshot is applied intentionally.
- Document why a snapshot was updated in the commit message.
- When a diff is large, refactor the component or reduce the rendered scope before updating.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.