Fine tuning React Jest snapshots using enzyme-to-json
When you test your React components using Jest snapshots and enzyme, enzyme-to-json is the de facto standard to serialize your snapshots (we’ve talked about it in a previous post by David Barral).
The default serializer will suit your needs 99% of the time. You can use it to test a whole application or library without ever having to resort to anything else. But the day will come when you find a particular test case for which the default serialization mechanism will not be appropriate.
For us, that day came when we had to develop and test a component to render a tree. Trees are recursive structures, so it is very natural to represent them using a recursive component. Our real scenario was much more complex than the following example, but the same problems and solutions apply.
So, you define a binary tree using a simple JS object. You also define a set of operations that your component will use to let the user interact with the tree nodes. And you define a recursive component to render the tree:
If you run the test defined above, you will end with 99 lines of snapshot:
<Tree
api={
Object {
"method1": [MockFunction],
"method2": [MockFunction],
"method3": [MockFunction],
"method4": [MockFunction],
}
}
tree={
Object {
"left": Object {
"left": Object {
"value": "a.l.l",
},
"right": Object {
"value": "a.l.r",
},
"value": "a.l",
},
"value": "a",
}
}
>
<ul>
<li>
a
</li>
<Tree
api={
Object {
"method1": [MockFunction],
"method2": [MockFunction],
"method3": [MockFunction],
"method4": [MockFunction],
}
}
tree={
Object {
"left": Object {
"value": "a.l.l",
},
"right": Object {
"value": "a.l.r",
},
"value": "a.l",
}
}
>
<ul>
<Tree
api={
Object {
"method1": [MockFunction],
"method2": [MockFunction],
"method3": [MockFunction],
"method4": [MockFunction],
}
}
tree={
Object {
"value": "a.l.r",
}
}
>
<ul>
<li>
a.l.r
</li>
...
Most of that snapshot is just the tree
and api
props being passed down to the inner components (in our real-life scenario, the snapshot was several thousand lines long!).
Now, try updating the previous code snippet to something like this (changes start at line 27):
We are using enzyme-to-json as a helper function. This lets us pass an options object to further control the way the component is serialized.
In the code snippet, we specify themap
option. It is a function which will receive each node before the serialization occurs. We can inspect and modify the node, and the value we return will be serialized.
In our case, we look for tree
and api
props and replace them with some placeholder content. This will get you a snapshot of “just” 40 lines:
<Tree
api="[the api]"
tree="[the tree]"
>
<ul>
<li>
a
</li>
<Tree
api="[the api]"
tree="[the tree]"
>
<ul>
<Tree
api="[the api]"
tree="[the tree]"
>
<ul>
<li>
a.l.r
</li>
...
Of course, this is a very risky practice and you should use it with care. We are hiding some of the information in the test, and that is wrong most of the time. But there are some cases, like the one we have discussed here, where unleashing the full power of your tools is the only way to move forward.