React Snapshot Testing

Matthew Garica

Snapshot testing is particularly useful in testing React components. Let’s see how it’s done.

react-test-renderer

You need to render your React components before you serialize them. Be sure to install react-test-renderer so you can do so.

yarn add --dev react-test-renderer

Creating a Snapshot for a Component

Let’s say you have a component that pages a person when you click a button

// Pager.js
import React from 'react';

export default function Pager({ name }) {
  const onClickCallback = () => alert(`Paging ${name}!`);
  return (
    <div>
      <h1>{name}</h1>
      <button onClick={onClickCallback}>Page</button>
    </div>
  );
}

Your test should look something like

// Pager.test.js
import React from 'react';
import renderer from 'react-test-renderer';

import Pager from './Pager';

it('looks okay.', () => {
  const name = 'John';
  // Render the component with the props.
  const tree = renderer.create(<Pager name={name}/>)
  // Convert it to JSON.
    .toJSON();
  // And compare it to the snapshot.
  expect(tree).toMatchSnapshot();
});

The snapshot goes to the __snapshots__ folder and all subsequent test runs will compare to that. From there you can edit Pager as you please; so long as the same props give the same result, the snapshot will match. But that’s also a problem.

Snapshots Are Not a Magic Bullet

It’s important to note that, while objects are serializable, functions (and therefore callbacks) are not. If you open up Pager.test.js.snap, you’ll see that onClickCallback is being represented as [Function].

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`properly writes name. 1`] = `
<div>
  <h1>
    John
  </h1>
  <button
    onClick={[Function]}
  >
    Page
  </button>
</div>
`;

If Pager is rewritten so that onClickCallback does something else, the snapshot will still pass.

export default function Pager({ name }) {
  // Not what you want it to do, but it will still pass.
  const onClickCallback = () => alert(`Paging {name}!`);
  return (
    <div>
      <h1>{name}</h1>
      <button onClick={onClickCallback}>Page</button>
    </div>
  );
}
✖ Clear

🕵 Search Results

🔎 Searching...