Testing React components, both smart and dumb, using Jest and Enzyme

Justus Romijn
Frontmen
Published in
3 min readJun 12, 2019
Command Line Interface output of (snapshot) unit tests with Jest of React components. Viewed with VS Code.

In the past couple of years I’ve been working with mainly React. I embrace unit tests for all my components, but based on the type of component and how complex the rendering is, there are different ways of asserting output. So I’ve split up my unit test approach for these well-known categories:

  • Presentational Components: Also known as “dumb” components. They are not concerned with business logic and rarely have their own state.
  • Container Components: Also known as “smart” components. They contain business logic, might maintain state of their own, and orchestrate presentation components.

Let’s start with the building blocks of most React applications, the so-called Presentational Components:

Use enzyme mount and validate output with jest snapshots.
Perform contract assertions for your props.

The dumb components main concern is the render output, so mounting and then making snapshots of the outputted html makes a lot of sense to me. The snapshot alone is not enough. We also want to make sure that we handle the input from the outside world correctly. In the example below, we check if the defaults work as expected. If properties and callbacks are provided, we test if they have the expected effects on the output or, in the case of callbacks, are called properly.

Example of a presentational / dumb component. It has no internal state, and mainly creates markup based on the properties.
Testing of presentational component using snapshots. Behaviour and use of properties are tested with regular assertions and spies (if passed callbacks are fired appropriately).

Making a snapshot for the scenario where the defaults of the component are used, as well as a snapshot for when props are provided really make it easy to cover all the branches of the code in a nice way.

Lets take a look at container components:

Use enzyme shallow rendering for your container components if you can.
Access the child components props directly to test the wiring of your parent-child relations.

Smart components are a whole different game. If you start snapshot testing your container components, and someone makes an innocent change to the output of a small presentational component (without changing the props interface), all containers using that component will have regression failures because the snapshots are invalidated. That makes your tests brittle and might lure you in a false sense of security, because it is easy to just ignore invalid snapshots by updating them with the new version (jest -u).

Instead of using snapshots, you can just access the properties of the child components directly and manipulate those, so the unit tests are only scoped to the actual logic of the container component itself. In the example below I use shallow testing, but if you have more complex nesting (often the case when using providers, graphQL queries, etc.) you can just exchange shallow for mount and it still works. Just as long as you keep away from snapshots or diving into the actual output of your presentational components.

Example of a smart component, e.g. with own state. It uses the setState hook to keep count of the amount of bashes.
Example of testing smart component using shallow rendering. By calling the onClick property of the Button component we can test our component logic without knowing how the Button actually works underneath.

I hope this gives an overview of how to keep your unit tests scoped, and your mind sane. I aim for that 100% coverage with confidence.

--

--

Justus Romijn
Frontmen

I’m a frontend developer at Frontmen, a company that focuses on frontend only. Beside my work I also enjoy tennis & table tennis, music, movies and games!