With react-test-renderer, we also get the component instance on the created component. With this instance we can both setState and run methods on our component. We can also take several snapshots in each test, so in my example a snapshot after each action, to make sure that the UI is correct during each stage of the test. Also note that all snapshots ends with a digit and that digit will increase for each toMatchSnapshot() we run in the test.

Updating snapshots

Since our UI will change from time to time, we will need to update the snapshots. Jest has easy commands for this. To update all your snapshots, run:

jest --updateSnapshot

But if you don’t run your tests often, there can sometimes be a lot of failing snapshot tests if we changed the UI in several places. In these cases it will be hard to get an overview of which snapshots that should be updated and where the UI has changed unexpectedly.

For these cases, when you run Jest in watch mode, you can run the interactive command. This lets you update one snapshot at the time and gives you full control over which snapshots that should be updated.

Concerns of snapshot testing

I personally like snapshot testing, however its very easy to create a snapshot test without gaining any test quality. So below is a list of main concerns I’ve found about snapshot testing.

Snapshot tests are hard to understand

One concern is that snapshots can become very large, especially if we have a large component tree. When snapshots become large they are hard to understand, difficult to read and maintain. They also become fragile and will easily break. Snapshots become large mainly for two reasons: the components template is large or that the whole component tree is in the snapshot.

Snapshot tests don’t encode the developers intention

Good tests encode the developers intention. By looking at a test, you as a developer should understand what the test does and how the code works. Snapshots fail to express the authors intent of what the test does and how the code works.

Snapshot files aren’t code reviewed

Generated files are usually not reviewed before committing them. Leading to having false snapshots and when they later fail, the developer will just update them instead of putting time into figuring out why the snapshot test fail.

Key pieces to make snapshot testing work

As I said I think snapshot testing solves how to test templates. If we don’t use snapshot testing, the other alternative would be query selectors and I think snapshot testing is much more efficient. Here are my key pieces to make full use of snapshot testing.

Unit test with snapshots

Sometimes when we create our snapshots we don’t mock the child components, making our test more of a integration test than a unit test. I agree that if we create the whole component tree, the snapshots could become very large and hard to read and maintain.

That is why I think snapshot testing is better suited for unit testing. We only test the component under test and mock the other components in the component tree. This will make our snapshots smaller, more readable and easier to maintain. This of course given that our template in itself is not large.

Mock child components

So mocking is key part to isolate the component under test. Mocking the other components in the component tree can be done either with Jest mocks or with a shallow renderer. If we want to use Jests mock function, we create the whole component tree and then mock our child components with:

jest.mock('./AddTodo')

This will make AddTodo disappear completely from the JSON output of the component tree. If you want to show the AddTodo component tag in the snapshot, we can write:

jest.mock('./AddTodo', () => 'AddTodo')

If we want to use the shallow renderer included in react test renderer:

import ShallowRenderer from 'react-test-renderer/shallow';

...

const renderer = new ShallowRenderer();

const component = renderer.render(<App />);

This shallow renderer doesn’t give access to the component instance to my knowledge. So depending on your use case, either use the shallow renderer or mocking child components for your test.

Snapshots are code

A key part about snapshots is understanding that they are the return value of the template. This return value is code, it should be thought of as code and be reviewed just as much as any other code or test. If we check the Jest documentation for snapshot testing, the first point of best practices is that snapshots are code. So if we don’t review snapshots, then they probably won’t be very helpful either. So make sure to treat your snapshots as code and code review them as such.

Keep components small and snapshots small

Any unit that is large will be hard test and the same applies for templates. We need to keep our templates small to be able to unit testing them in the same way as all other units we test. That a snapshot is large, is not the fault of the snapshot, it is the fault of the template. If we get a big snapshot, then the template is probably hard to understand as well.

Also if we have mocked away all our child components in the component tree and we still have a large snapshot. Then try to think of ways to make the template smaller, by for example refactoring our component to make it easier to test. If we can’t test that our templates work and that they work over time, then they probably will break at some point.

Important to be specific about snapshot testing

Each test should have one clear purpose and one path trough that function. This also applies to snapshot testing, we should have one setup of our component and one snapshot per test. To describe each tests purpose our test description is very important. We need to be very specific about what we want to test, in the same way as we do with other unit tests. We also need to maintain our test description to make sure they are up to date with the test. Given that we have a specific test description together with a proper setup of the component before the snapshot is taken, I believe that we can make each snapshot with a clear purpose and that the developer intent is clearly expressed.

Conclusion

I think snapshot tests are great to test the UI logic of our web applications. With my provided key pieces I think that snapshot testing can give great testing value to our frontend applications. So when snapshot testing, make sure you:

Remember that snapshots are code and should be handled with love and care as much as any piece of code

Do unit testing and thereby mocking away under components that aren’t under test

Keep templates small

Keep snapshots small

Each snapshot has clear purpose which is properly described in the test description

Thank you for reading my post!!

Please clap or comment!!