Jest Snapshot Serializers

One of the best practices for properly using snapshots is to commit them, so that others can code review the changes you’ve made to the expected output.

For this process to work smoothly your snapshots need to have a clean and highly readable output, that makes it really easy for others to see and identify the changes made.

I’ve previously touched on some best practices for doing this with react components.

But if you’re using snapshots to test something else than a react component there are also some improvements you can do to improve the readability of your snapshots.

You can adjust and format the output of a snapshot to make it more readable by using snapshot serializers (note that snapshot serializers are available in Jest 19+).

Given the following example:

var ToDos = [
{ 'Id': '1', 'Title': 'Shop groceries', 'Status': 'done' },
{ 'Id': '2', 'Title': 'Go to gym', 'Status': 'pending' },
{ 'Id': '3', 'Title': 'Kill it with fire', 'Status': 'done' },
{ 'Id': '4', 'Title': 'Take snapshots', 'Status': 'done' },
{ 'Id': '5', 'Title': 'Be awesome', 'Status': 'pending' },
];
function filterTodos(arr, key, term) {
return arr.filter(function(obj) {
return obj[key] === term
});
}
test('it returns all todos with matching Id',() =>{
expect(filterTodos(ToDos,'Id', '1')).toMatchSnapshot()
})
test('it returns all todos with matching Title',() =>{
expect(
filterTodos(ToDos,'Title', 'Shop groceries')).toMatchSnapshot()

})
test('it returns all todos with matching Status',() =>{
expect(filterTodos(ToDos,'Done', 1)).toMatchSnapshot()
})

This would output the following snapshot:

exports[`it returns all todos with matching Id 1`] = `
Array [
Object {
"Id": "1",
"Status": "done",
"Title": "Shop groceries",
},
]
`;
exports[`it returns all todos with matching Status 1`] = `
Array [
Object {
"Id": "1",
"Status": "done",
"Title": "Shop groceries",
},
Object {
"Id": "3",
"Status": "done",
"Title": "Kill it with fire",
},
Object {
"Id": "4",
"Status": "done",
"Title": "Take snapshots",
},
]
`;
exports[`it returns all todos with matching Title 1`] = `
Array [
Object {
"Id": "1",
"Status": "done",
"Title": "Shop groceries",
},
]
`;

We can then ‘prettify’ this output with a serializer:

expect.addSnapshotSerializer({
test:(val) => val.Id && val.Title && val.Status && val.expiration,
print:(val) => `ID: ${val.Id}
Title: ${val.Title}
Status: ${val.Status}
Expiration: ${val.expiration}`
})

And then your output should be:

// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`it returns all todos with matching Id: 1 1`] = `
Array [
ID: 1
Title: Shop groceries
Status: done
Expiration: 23/03/17
,
]
`;
exports[`it returns all todos with matching Status: done 1`] = `
Array [
ID: 1
Title: Shop groceries
Status: done
Expiration: 23/03/17
,
ID: 3
Title: Kill it with fire
Status: done
Expiration: 23/03/17
,
ID: 4
Title: Take snapshots
Status: done
Expiration: 23/03/17
,
]
`;
exports[`it returns all todos with matching Title: Shop groceries 1`] = `
Array [
ID: 1
Title: Shop groceries
Status: done
Expiration: 23/03/17
,
]
`;

How to create a serializer?
The ‘addSnapshotSerializer’ function gives you acces to two callbacks ‘test’ and ‘print’ which both receive each of the values returned by your test cases. 
In the ‘test’ callback you can create a condition for the use of the serializer, like the existence of a given set of values. And in the ‘print’ callbak you can format the ouput of the snapshot by using each of the values as you please.

I haven´t found much documentation on creating serializers but this seems to be a handy tool when dealing with more complex snapshots.

This a great example of usage for a snapshot serializer:

This is a test for a binary search tree algorithm that outputs and diffs the test results as an actual tree, you can check the source at: https://github.com/jiayihu/pretty-algorithms

Resources: