
Snapshot testing is immensely popular for testing React apps or other component-based UIs. However, itās not exactly drama-freeāāāmany people looooove snapshots for their ease of use and ability to quickly bootstrap a testing portfolio, while others feel that the long-term effects of snapshots might be more harmful than they are helpful.
At the end of the day, snapshot testing is simply another tool in our tool belt. And while many people may be divided on how and when to use snapshot testing, itās good to know that it exists and that itās available when we need it.
Iāll be honest about my position on snapshotsāāāI tend to be in the camp thatās less enthusiastic about them. However, I recently came across a situation with some legacy code where it felt like snapshot tests were a perfect match. Using snapshots as a refactoring tool helped me successfully tackle and refactor some tricky code written long before I joined my company.
If youāre not familiar with snapshot tests, weāll do a little refresher. In a snapshot test, a āpictureā of your codeās output is taken the first time the test runs. This āpictureā gets saved to a text file in your codebase and all subsequent test runs use this picture as a referenceāāāif your codeās output produces an identical snapshot, the test passes. However, if the output is different from the saved snapshot the test fails.
Hereās an example of what a snapshot test looks like in Jest:
import renderer from "react-test-renderer";
function Test({ message }) {
return {message};
}
test("renders", () => {
const wrapper = renderer.create(<Test message="test" />);
expect(wrapper.toJSON()).toMatchSnapshot();
});
After this test runs for the first time it will create a snapshot file that future test runs will use as a reference. The snapshot file would look something like this:
// Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders 1`] = ` <div> test </div> `;
I hadnāt heard about snapshot testing until I started using JestāāāIām not sure if the Jest team invented snapshot testing but they certainly popularized it! At first glance, snapshots are super convenientāāāinstead of writing your own assertions you can just generate tests to see if your code is broken. Why waste time when the computer can automate our problems away? Jest even makes it super easy to automatically fix your snapshots. This means that even if youāve got a failing test youāre a single keypress away from fixing all of your tests.
At first glance, snapshot testing sounds like a dream come trueāāāall I have to do is write one snippet of code to generate snapshots and Iāll have these super-detailed tests āfor freeā? Take my money already!
However, over the past few years that Iāve been working with snapshot testing, Iāve found that snapshots introduce a number of pain points that make them difficult to maintain. And Iām not the only one! For example, this company decided to ditch snapshots and wrote about it. Or consider this tweet:
I š’d snapshot testing yesterday. Someone DM’d (not @’d!) me a question so here’s my response to why. I’ll blog soon https://t.co/Bxo4mS2BWr pic.twitter.com/6dmaRpHG2N
ā Justin Searls (@searls) October 15, 2017
Thatās not to say snapshot testing is all bad! After all, every tool has trade-offs, and itās worth acknowledging the weaknesses of a tool when weāre evaluating using it. Here are a few reasons why Iām not the biggest fan of having snapshots in my testing suites.
Snapshots are often used to test component trees or large objects. However, since the snapshot takes a picture of every single detail in the component/object, even the slightest change (like fixing a typo in a CSS class) will fail the snapshot test. As a result, you end up with tests that break even when the code still works. These false negatives create a lot of noise and erode your confidence in your testing suite.
You might be thinking, āIsnāt this a good thing?ā After all, being a single keypress away from a passing test suite sounds like a dream come true. However, because the tests are so easy to create/update, what tends to happen is that developers care less about the snapshot tests.
In my experience, developers will often simply press the button to update the snapshots without looking to see what changed or if the code is broken. While it is possible to treat your snapshots with the same importance as your code (and recommended in the Jest docs), it requires a ton of diligence. More often, my experience has been seeing engineers blindly update the snapshots and move on with their day (Iāve done it myself many times in the past š±).
Itās easy to generate a ton of test coverage using snapshots. If your team has a coverage threshold that all code has to meet, snapshots make hitting your coverage numbers a breeze. However, test coverage alone is not a sufficient metric to use to evaluate the quality of your test suite. While test coverage is a valuable tool for seeing gaps in your testing suite, it doesnāt tell you about things like whether your tests are brittle, whether your code stands up to edge cases, or whether the tests accurately test the business requirements.
While Iām not a fan of having snapshots as ālong-term residentsā of my testing suites, Iāve actually come across a few use cases where they truly shine. For example, refactoring legacy code.
Rarely do we start a job and get thrown into greenfield projectsāāāwe get codebases that have existed for years. And when we do, those projects can quickly go from a blank slate to nightmare codebase if weāre not careful. At some point in your career, youāre going to have to work on ālegacy codeā that you didnāt write. And many times those codebases donāt have any tests.
When you start adding features to this legacy code, and youāre faced with a dilemma. You might need to refactor the code to fit new business requirements, but you donāt want to run the risk of breaking something. In order to refactor safely, you need some type of tests in place.
The thing is, taking a pause to write tests for legacy code can sometimes feel like a luxury you donāt have. After all, youāve got deadlines to hit, and you finally figured out where you need to modify this legacy code. If you take too long of a break you might lose that context that youāve built up!
Snapshots can actually be super useful to us in this scenario. Hereās a snapshot testing workflow Iāve found super helpful when working with legacy code.
Read through the legacy code and try to get a picture of all of the various inputs that it could possibly have. However, you donāt need to figure out the outputs! For each input variant, create a snapshot test. This helps you figure out what outputs are actually produced by the code youāre working with.
Since youāve got this massive safety net of snapshot tests to fall back on, start refactoring. Remember that this method of refactoring with snapshots is only good if you do not change the output at all. So if youāre working with a React component and you change the rendered output your snapshots will fail. This isnāt the end of the world, just make sure to check why the snapshots failed and if the change was actually intended.
Once youāre done refactoring, you can safely replace these snapshots without fear of forgetting how you wanted to refactor the legacy code. However, for the reasons discussed above, you might not want those snapshots to be long-term residents of your testing suite. Now that the code isnāt changing, you can safely start refactoring your tests. To make your tests more resilient long-term, you might want to consider taking each snapshot test and replacing it with a more focused assertion. For example, we could replace the snapshot test from before with this test using react-testing-library and jest-dom.
import { render } from "react-testing-library";
import "jest-dom/extend-expect";
function Test({ message }) {
return {message};
}
test("renders", () => {
const { getByText } = render(<Test message="test" />);
expect(getByText("test")).toBeInTheDocument();
});
Granted, this isnāt an incredibly complex testāāāthe component doesnāt have any logic to refactor! These more focused assertions will stand the test of time (pun intended š) better as the component changes with future requirements.
Throughout my (short) career Iāve seen lots of code written without tests by people that have long left the company. Itās no secret that tricky, dense, difficult-to-read code has a negative effect on team morale and that, over time, code should be lovingly refactored to fit new requirements.
However, mocking or complaining about tricky legacy code shouldnāt be our default responseāāāinstead, we should try to always leave the code in better shape than when we found it.
This is easier said than done, especially when weāre trying to meet a tight deadline or if weāre afraid to touch the code lest we break something. This method of using Jest snapshots has been incredibly useful for me and I hope that you will find it useful too!
Thanks for reading! If you enjoyed this post, make sure to follow me on TwitterāāāI make sure to post links to any new articles as I write them. If youāve had some snapshot test success stories, donāt hesitate to reach out!
Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not
server-side
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
// Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>

Learn how to use browser AI APIs for summarization, translation, and language detection with practical examples and implementation tips.

Build a live task board with Topcoat and Rust, using reactive signals, server-rendered search, and WebSocket updates.

Learn how to build and install three Claude Code mods to monitor usage, protect secrets, and track changes.

I tested Jev against popular LLMs to compare speed, cost, and accuracy on real bank support messages.
Would you be interested in joining LogRocket's developer community?
Join LogRocketās Content Advisory Board. Youāll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now