Snapshot Testing With Jest — Beyond React components

Luis Vieira
Jul 25, 2017 · 3 min read

Snapshots are a great new way of testing UI components but their applicability can go beyond that, and they can be really useful in other contexts too.

In reality with Jest snapshots it’s possible to test and assert the output of any serializable value.

Let’s assume the following scenario: we have a list of todos (Array<Obj>) and somewhere in our app we want to be able to filter them by one of it’s attributes. Let’s write a function and some tests for it:

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')).toBe(
{ 'Id': '1', 'Title': 'Shop groceries', 'Status': 'done' }
)
})
test('it returns all todos with matching Title',() =>{
expect(filterTodos(ToDos,'Title', 'Shop groceries')).toBe(
{ 'Id': '1', 'Title': 'Shop groceries', 'Status': 'done' }
)
})
test('it returns all todos with matching Status',() =>{
expect(filterTodos(ToDos,'Done', 1)).toBe(
{ 'Id': '1', 'Title': 'Shop groceries', 'Status': 'done' },
{ 'Id': '3', 'Title': 'Kill it with fire', 'Status': 'done' },
{ 'Id': '4', 'Title': 'Take snapshots', 'Status': 'done' }
)
})

Normally when testing a functionality like this, we need a mocked list of todos and then we need to manually assert the expected return value.

Everything is working great but, if in the future we need to change our data we need to manually update each test.

Let’s say that we’re given a new requirement stating that all todos should have an expiration key with an expiration date.
We would then have to manually update our array and the return value of each test case. This can be cumbersome specially in a large app with more complex features.

With snapshots we could replicate the same testing scenario as such:

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, 'Status', 'done')).toMatchSnapshot()
})

This should give you the following snapshot:

// Jest Snapshot v1, https://goo.gl/fbAQLPexports[`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",
},
]
`;

Then an update to the todos array would cause the tests to fail and produce the following output:

If this new output is expected we can replicate this through all the test cases simply by running the ```$ jest — updateSnapshots command, there’s no need to go through each test and update it’s return value.

This is why snapshots are really useful for apps with complex and frequently changing requirements and a really great tool for testing, it’s applicability can go far beyond react components.

Resources:

HackerNoon.com

#BlackLivesMatter

Sign up for Get Better Tech Emails via HackerNoon.com

By HackerNoon.com

how hackers start their afternoons. the real shit is on hackernoon.com. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

HackerNoon.com

Elijah McClain, George Floyd, Eric Garner, Breonna Taylor, Ahmaud Arbery, Michael Brown, Oscar Grant, Atatiana Jefferson, Tamir Rice, Bettie Jones, Botham Jean

Luis Vieira

Written by

A frontend developer that can handle its dose of UX and design.

HackerNoon.com

Elijah McClain, George Floyd, Eric Garner, Breonna Taylor, Ahmaud Arbery, Michael Brown, Oscar Grant, Atatiana Jefferson, Tamir Rice, Bettie Jones, Botham Jean

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

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