Snapshot testing

If you are a front-end developer, you use React and want to be sure that components written in your project work as they should work, you more likely know about snapshot testing of React components.

Snapshot tests are provided by Jest and they are a very useful tool whenever you want to make sure your UI does not change unexpectedly.

How it works:

You create a test where a component renders with some of the props. It looks like this:

import React from 'react';

import renderer from 'react-test-renderer';



import Button from 'components/button';



test('Button', () => {

const tree = renderer.create(

<Button

text="Click me"

/>

); expect(tree).toMatchSnapshot();

});

The first time this test is run, Jest creates a snapshot file that contains a stringified JSX-markup of the component. On subsequent test runs Jest will simply compare the rendered output with the previous snapshot. If they match, the test will pass. If they don’t match, either the test runner found a bug in your code that should be fixed, or the implementation has changed and the snapshot needs to be updated.

You can read more detailed description in the official documentation, but this is the main points.

The problem

The problem is that you have to manually fill the props up for different cases of a component which you want to test. As many props the component has as more test cases (read as sets of prop’s values) you have to care about. Most of the time you fill these values up just randomly.

Let’s suggest, we have the Button component with 3 of props: text, className, isDisabled. This is how a test file could look like:

test('Button Case #1', () => {

const tree = renderer.create(

<Button

text="Click me"

className=""

isDisabled={false}

/>

); expect(tree).toMatchSnapshot();

}); test('Button Case #2', () => {

const tree = renderer.create(

<Button

text="Click me"

className="buttonClassName"

isDisabled={false}

/>

); expect(tree).toMatchSnapshot();

}); test('Button Case #3', () => {

const tree = renderer.create(

<Button

text=""

className=""

isDisabled={true}

/>

); expect(tree).toMatchSnapshot();

}); // and so on...

To write this file is boring enough. And here’s just 3 of the cases, when the count of them could be 3³=27.

Isn’t this wasting of time to make it manually? Could it be automated and how?

Using TypeScript with React

TypeScript is a language that lets you use types in your code and could be compiled to plain JavaScript. The TypeScript compiler checks any type’s errors in the code and lets you know if anything is wrong.

You can use it with React as well. You can set types for the props of a React component. It could look like this for the Button component we discussed above:

interface IButtonProps {

text: string;

className?: string;

isDisabled?: boolean;

}

But wait… If we have types for props, values for every of the props are in strongly limited set. So, that means they could be randomized automatically! Bingo! 🎉

Automatic generation of snapshot tests

If we can randomize values for the props, we can create a test file full of test cases automatically.

This is what the Snappify library was created for. It takes your React components written with TypeScript and generates files with the tests for them.

You only have to run them! ✨

How Snappify works

Intall Snappify globally:

npm install -g snappify

Run Snappify inside of a project folder with a configured glob pattern of the React components files and a name of a root folder for generated tests:

snappify components/**/*.tsx --testsRoot=tests

It will create a directory called tests inside the current folder.

Inside that directory, it will generate the files with snapshot-based tests for every of the components from the files that matched to components/**/*.tsx pattern.

The count of generated test cases

If a component has many props, it is possible to generate for it pretty many test cases. Many tests cases are difficult to control. Hardly you want to have a hundred cases in a single test file.

Snappify cares about this as well. It generates up to 10 test cases only for a component.

The props values for test cases be generated with uniformly distributed sets of random values based on the types of the props. That means you get the count of test cases that you can take control of, but they are still cover the details of your components as wide as it possible in this situation.

Summing up ⬇️

Snappify source code is on GitHub: https://github.com/denisraslov/snappify.

If you have problems or suggestions, please open an issue or send me a PR and let me know what you think.