How to write effective snapshot tests

Disclaimer: The opinions expressed in this article are my own, and do not reflect my employer’s opinions or anyone else’s.

Snapshot tests are not the savior to our test coverage needs we expect them to be. In fact, they can be quite the opposite. In this article we’ll discuss what a snapshot test is and how to use them more effectively in your code.

What is a snapshot test?

A typical snapshot test case renders a UI component, takes a snapshot, then compares it to a reference snapshot file stored alongside the test. The test will fail if the two snapshots do not match: either the change is unexpected, or the reference snapshot needs to be updated to the new version of the UI component.

source: https://jestjs.io/docs/snapshot-testing

This is fine when testing static pages or small components, but modern single page applications are full of dynamic, constantly changing views that are dependent on the data passed to them.

Any component larger than a single element such as button span or div is most likely going to have changing content. Since we’re not typically testing functionality with our style, layout, and text content, there’s little value added by adding a snapshot test.

It might even be a hinderance.

Snapshot tests can decrease developer productivity

Let’s say we have a Button component and we’re importing it to a Checkout page:

In this example, Button already has a snapshot test. But now we create a Checkout page that imports this Button. And because our coworkers won’t approve the pull request without some testing, we add a snapshot test because it’s easy and instills a sense of security. This is where the trouble starts.

Fast forward a few weeks and we’ve snapshotted 30 pages in our codebase that import Button and we need to make a change to Button. So we make our change and update the local snapshot test for Button but when we go to push our changes… suddenly all 30 of those pages need to have their snapshot tests updated also. A tedious and pointless task.

So how do we fix this?

Use intention when writing unit tests

In the aforementioned Button example, we can run npm run test —- -u to update the snapshot for us, but all we’ve done is add yet another useless task for developers to do before committing their code. We’ve lost the intention in our unit testing which is to make sure our code does mission critical stuff despite our constant iterations and improvements. Rather than snapshotting the whole component, we should capture the mission critical stuff to the Checkout page, such as the items list. Here’s a better way to test the same code:

A granular approach to unit testing is less likely to require maintenance as developers iterate and add to existing features. It also means when tests fail, it’s because the core intent of the component has changed. Now we have to think about how our tests should change and not just run a command to update them.

When should I use a snapshot test?

There are two instances where I have found snapshot tests to be extremely effective:

  1. When testing small, static, components, we can use DOM/React queries to generate inline snapshots to verify we’re satisfying mission critical render logic in our component. This is how most testing libraries suggest using snapshots, instead of capturing entire pages or large features.
  2. When creating reusable code, such as a component library, a snapshot test can help developers rely on simpler components to look the same way no matter where they’re used.

When should I NOT use a snapshot test?

  1. When testing large components or entire webpages with the exception of long standing static pages, such as documentation.
  2. When testing functionality. Instead try using assertions whenever possible.

A final though on preventing regressions

A common argument for adding snapshot tests is preventing regressions. Most modern codebases already use automation testing, such as Cypress or Capybara, and have QA on staff whose entire job is to run test suites that ensure we haven’t caused unforeseen regressions. A pdiff tool can be extremely useful when trying to prevent regressions also. Unit testing with snapshots is not meant to replace any of these incredible tools or processes already at our disposal.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store