Effortless React Component testing with jest-snapper

If you’re not familiar with snapshot testing in a unit testing concept, it’s not a very hard concept to grasp at all. You just…

  1. Run a piece of code that will produce the same output - given the same input.
  2. Record its’ output somewhere - possibly check in into your source control.
  3. Run it again with your tests later.
  4. Compare the output with what you saved previously.

Snapshot testing shines in functional programming - because we try to use functions as means of slicing and dicing our problems. These functions - in order to be good functions - produce the same output given the same inputs.

When observing how React works, this is directly applicable to a React Component. You supply a bunch of input parameter (props) and you get an output which can be serialized. This is the basis of snapshot testing with jest.

A snapshot test with jest may look like:

// https://facebook.github.io/jest/docs/en/snapshot-testing.html
import React from 'react';
import Link from '../Link.react';
import renderer from 'react-test-renderer';

it('renders correctly', () => {
  const tree = renderer.create(
    <Link page="http://www.facebook.com">Facebook</Link>
  ).toJSON();
  expect(tree).toMatchSnapshot();
});

Functional/Stateless React components, unlike other functions, have one big difference. They may have PropTypes, which basically tells us exactly what they expect as input Parameters. The above Link component’s propTypes may look like:

Link.propTypes = {
  page: PropTypes.string,
  children: PropTypes.string
};

:bulb: What if we can auto-generate the above test with mock props by inspecting the propTypes?

Introducing jest-snapper

This is why I came up with jest-snapper. It will derive mock props by introspecting propTypes of a Component and it will generate a snapshot test which runs on the jest snapshot testing infrastructure.

So, the test above which takes ~8 lines of code to write, can be written with 3 lines of code:

import snaptest from 'jest-snapper';
import Link from '../Link.react';

snaptest('renders correctly', Link);

But what if I have specific props that I need to test with?

You can supply your specific props work as overrides. The props you provide will be merged with the generated props.

import snaptest from 'jest-snapper';
import Link from '../Link.react';

snaptest('renders correctly', Link, {
  props: { page: 'my-specific-page' }
});

But I need to assert with state.

No worries. Just supply your state. Before asserting the serialized object, jest-snapper will do a setState with your supplied state object.

import snaptest from 'jest-snapper';
import StatefulLink from '../StatefulLink.react';

snaptest('renders correctly on state change', StatefulLink, {
  props: { page: 'my-specific-page' },
  state: { active: true },
});

But is generating mock props and testing on things give any real value?

Well, I may be biased, but yes. In snapshot testing React Components, you’re mainly asserting the structure of the generated DOM, and how your props affect the said DOM. In that case, generating mock props has the value of saving valuable dev time spent on writing tests with props manually.

As with anything, you as a developer should be able to make a call on which tests you do yield a value - and which tests can be bypassed with a /* ignore */. jest-snapper was written to solve one problem - and that was to spend less time writing the tests that you as a developer would decide as worth writing.

Happy testing!

Written on September 2, 2017