Snapshot Testing: The Easiest way to test your code haven’t changed since last time

Mikael Araya
Mar 4, 2020 · 7 min read

Software testing is one of the important requirements when developing great quality software. testing gives us software developers the peace of mind of knowing all of the application features work as expected before delivering it to the client or after making a change to it.

During the year’s various types and levels of testing have been suggested to help guarantee applications work as expected. such as:

Approaches

  • box testing
  • White-box testing
  • black-box testing
  • visual testing
  • grey-box testing
  • etc…

Levels

  • Snapshot testing
  • Unit testing
  • Integration testing
  • System testing
  • Operational acceptance testing
  • end-to-end testing
  • etc…

In this article, our main focus is going to be the implementation of snapshot testing, but there are plenty of materials out there that describe each method in great detail, for starters you can use Wikipedia

Prerequisites

You don’t need any experience or knowledge of the tools mentioned to understand what snapshot testing is since I’ll try to show the output of each executed code alongside it. But if you want to follow along make sure you have the following tools and all their dependencies are installed on your workstation.

all of the code in this article are developed and tested on ubuntu 19.04 so make sure to add all the required dependency if you are using different operating system

  • ReactJs — basic knowledge of React or any similar framework will be helpful to understand the content more.
  • Jestjsjest is the tool we will be using to write the snapshot test.

Snapshot Testing

Snapshot testing is one of the testing methodologies that help us ensure our code hasn’t changed or in the case it has changed lets us confirm if the change was intentional or not before it’s too late.

It can achieve this by saving/taking a snapshot of the rendered output the first time we run the test and comparing that output with tests we run after that and throw an error if the code has changed.

snapshot files should be included inside our repository and tracked with version control alongside the codebase to be effective.

Jest is a javascript framework that provides us with the capability to run snapshot testing on our codebase. even though we can use jest snapshot testing with any framework or even plain HTML/CSS applications we are going to use Reactjs for demonstration because React comes with support for jest out of the box.

Configuration of Jest snapshot testing on ReactJS

If you are just interested to see what snapshot testing is and don’t intend to know the configuration detail you can skip to the next section.

Since react comes with jest out of the box there is not much of configuration we have to do to get up and running. with that said this are the required configuration to setup snapshot testing on ReactJs application.

  • Enter the react application directory or create a new one using create-react-app
create-react-app snap-shot-demo && cd snap-shot-demo
  • Add react-test-renderer to your application devDependency inside package.json by running the following code inside a terminal window.
npm install --save-dev react-test-renderer

This package makes it easy to grab a snapshot of the “DOM tree” rendered by a React DOM or React Native component without using a browser or jsdom.

  • update package.json script section by adding jest as follows
...
"scripts": {
...
"test": "jest",
...
},
...
  • because jest doesn’t understand JSX we need some way to convert JSX to javascript. we will use babel for this purpose.

If you are using ReactJS version greater than 16 it’s your lucky day because it comes with babel out of the box. but if you are using a version less than 16 you need to add the following devDependencies as well inside your project package.json.

npm install --save-dev babel-jest @babel/core @babel/preset-env
or
yarn add --dev babel-jest @babel/core @babel/preset-env
  • Next, add ababel.config.js file with the following content.
module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react']
};

for more information refere to the official jest configuration and babeljs documentation.

The above configuration will work just fine, that is until your component has a direct CSS import like the following

import "./EventItem.css"

on such cases jest will fail to compile the code because it needs to transform the CSS file to javascript syntax.

For this purpose, you have to add another devDependency topackage.json.what worked for me is jest-transform-css but there is plenty to choose from.

jest-transform-css is intended to be used in an jsdom environment. When any component imports CSS in the test environment, then the loaded CSS will get added to jsdom using style-inject.This means the full styles are added to jsdom

npm install --save-dev jest-transform-css
or
yarn add --dev jest-transform-css

next, update the transform section of jest.config.js that is found on the root directory of the project. if it doesn’t exists create it by running jest --init

transform: {
'^.+\\.js$': 'babel-jest',
'.+\\.(css|styl|less|sass|scss)$': 'jest-transform-css'
}

we are telling jest to use jest-transform-css whenever it encounters CSS, styl, LESS, SASS, SCSS files.

That’s it you have a project set up and ready for snapshot testing. proceed to the next section to see it in action.

The final package.json file script and devDependency sections should look similar to this

...
"scripts": {
...
"start": "react-scripts start",
"build": "react-scripts build",
"test": "jest",
"eject": "react-scripts eject"
...
},
...
"devDependencies": {
...
"jest-transform-css": "^2.0.0",
"react-test-renderer": "^16.13.0"
...
}
...

Getting started

If you want to run the code in your workspace you can clone this repository.

make sure you have created-react-app and jest installed globally on your work station.

npm install -g create-react-app
npm install -g jest

Snapshot testing works by saving the rendered output of a component at any given moment and comparing that output on the next runs. eg. we could have a react component that renders a list of events.

as you can see we have a component that accepts event objects withname, startDate & description and renders the output. we can take snapshot of this components first rendered output using jest as follows.

the code above uses react-test-renderer package to take a snapshot of our component. It takes the following steps when executed

image source
  • renders the EventItem component using jsdom
  • checks if there exists a snapshot of the component already
  • if snapshot doesn’t exist i.e. it is the first time that's being executed it will create a new snapshot
  • if a snapshot already exists it will compare it with the currently rendered component and fails if they don’t match or pass if they match

The first time we run npm run test jest will save the snapshot of the rendered component inside the same directory as the test under a directory named __snapshots__ and file name that has a format of [test-file-name].snap eg. event-item.test.js.snap

// Jest Snapshot v1, https://goo.gl/fbAQLPexports[`EventList Component should render correctly 1`] = `
<div
className="container"
>
<p>
</p>
<span
className="start-date"
>
</span>
<p>
</p>
</div>
`;

if for any reason the snapshot file and the rendered output don’t match the next time we run the test it will fail. for example, if I removed the className attribute from the span component and run the test, the test will fail with the following output

As you can see from the output there is a difference between the previous snapshot and thereceived or current rendered out.

But what if the change was intentional and you wanted to update the snapshot? well, there is a command we can use for that. you can run the following code and jest will update the snapshot record with the newly rendered output

npm run test -- -u
or
jest --updateSnapshot

the above command tells jest to update the snapshot file with the current rendered output and use that for future comparison

Conclusion

Snapshot testing is a good addition to our testing arsenal. it will minimize most of the boilerplate code we would have to write to test the application is rendered properly. but by no means, it is a replacement or substitutes to the existing tests such as unit test, integration test, etc... they all serve a different purpose.

To get the benefits of snapshot testing we should track each snapshot with version control so that the whole team is aware of the changes made and can be used for code review purposes.

Finally, I don’t recommend taking a snapshot of the whole application instead we should take a snapshot of the sections we want to make sure are rendered correctly. we can use the file size increase for this argument but that will take us no far because the snapshot file size of the jest framework is 30kb but instead the smaller the size the easier it will be later for code review. This comes down to personal preference.

Reference

Mikael Araya blog

Few code samples testing new tools and technologies