Nice writeup!
Aziz Punjani

Thanks for your response. I’d like to elaborate a bit about why I didn’t use snapshots to assert the render output.

The primary reason is that snapshots of render output often obscure the contract of the component under test.

This is because they capture the entirety of the render output, including both the parts that are important and the parts that are unimportant. Snapshots are not hard to update, but if you only have a snapshot test and nothing else, then when it needs to be updated, it will be hard to tell if it is “safe” to update or not. A snapshot test does not tell you your code broke, only that it changed. In order to determine if it broke, you will have to understand how the component works, but there will not be any tests documenting what its intended behavior is.

I feel that many people write a snapshot test around their component and feel that now they are safe because everything is covered. But that test is merely a canary in a coal mine; it cannot tell you why the new behavior is considered wrong.

If you instead write imperative tests, then many tests will continue to pass after the component is changed, and for the ones that broke, it will be clearer why they broke and what the component was expecting instead.

Another reason is that snapshots of full render output are brittle, because they would need to be updated whenever a child component test changes. Again, snapshots aren’t hard to update, but a brittle test is a brittle test, and considering snapshots are so easy to update en-masse, you should avoid adding noise to the signal they provide. It’s possible to make snapshots of shallow render output (using either mocks or a carefully-constructed tree), but it can be difficult to express to the system precisely how deep to render for the sake of the snapshot; the default with snapshots is to assert more rather than less. I feel like it is easier to explain exactly which pieces you care about with the imperative approach (but I would love to see tooling change that opinion).

Jest snapshots are a very powerful tool and can be very useful, but I think that they are the wrong tool for most React Components, because they gloss over the details of the component’s contract. However, here are some things that snapshots are great for:

  • Apps with complex, frequently-changing requirements, like prettier.
  • Brittle tests where you make an assertion around a large, multi-line string, like the output of a --help flag for a CLI tool.

Snapshots are an invaluable end-to-end/integration testing tool, but should be used with care in unit tests. I think of snapshots as a machete and imperative assertions as a scalpel. Sure, it takes longer to cut with a scalpel… but sometimes you need the precision.

Like what you read? Give Stephen Scott a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.