Revisiting React Testing in 2019
Seems that today, everyone is using a different React testing library and even when they are using the same one, their philosophy varies widely.

The example from this article is available for download.
The Libraries
In reading an article, Testing Apollo’s Query Component, I was reminded that there are currently (going into 2019) several popular and competing React testing libraries.
note: This is distinct from the underlying JavaScript testing framework; Jest is a popular option; used in the article (and here).
This guide will explain step-by-step how to test react-apollo code. The following examples use the Jest testing framework, but most concepts should be reusable with other libraries. These examples aim to use as simple of a toolset as possible, so React’s test renderer will be used in place of React-specific tools like Enzyme and react-testing-library.
— Jake Dawkins — Testing Apollo’s Query Component
In particular there is:
Enzyme: Enzyme is a JavaScript testing utility for React that makes it easier to assert, manipulate, and traverse your React components’ output.
ReactTestUtil: ReactTestUtils makes it easy to test React components in the testing framework of your choice.
react-testing-library: The react-testing-library is a very light-weight solution for testing React components. It provides light utility functions on top of react-dom and react-dom/test-utils, in a way that encourages better testing practices.
Test Render: This package provides a React renderer that can be used to render React components to pure JavaScript objects, without depending on the DOM or a native mobile environment.
To make things even more confusing, two of the libraries (ReactTestUtils and Test Render) are maintained by the React team and the other two are recommended by them.
Airbnb has released a testing utility called Enzyme, which makes it easy to assert, manipulate, and traverse your React Components’ output. If you’re deciding on a unit testing utility to use together with Jest, or any other test runner, it’s worth checking out: http://airbnb.io/enzyme/
Alternatively, there is another testing utility called react-testing-library designed to enable and encourage writing tests that use your components as the end users use them. It also works with any test runner: https://git.io/react-testing-library
— React Team — Test Utilities
note: One particularly interesting feature of Test Render is that renders React components to pure JavaScript object; making it the only popular React testing library suitable for testing React Native.
A Philosophy
Testing React applications is complicated and there are lot of opinions on how it should be done. In this regard, I have come to follow a JavaScript / React testing evangelist: Kent Dodds. The gist of his ideas can be summarized through a number of quotes.
Write tests. Not too many. Mostly integration.
— Kent Dodds — Write tests. Not too many. Mostly integration
The more your tests resemble the way your software is used, the more confidence they can give you.
— Kent Dodds — react-testing-library
The reason this kind of test fails those considerations is because it’s testing irrelevant implementation details. The user doesn’t care one bit what things are called.
— Kent Dodds — Why I Never Use Shallow Rendering
An Example
The final example in Kent Dodds article, Why I Never Use Shallow Rendering, illustrates many of his ideas at work. Let us walk through building it; calling ideas out as we go.
At the same time, we will make two significant deviations from his example:
- We will write the example using TypeScript; TypeScript’s static typing provides a solid base for our testing strategy (see Kent Dodd’s Testing Trophy)
- We will use Test Render instead of react-testing-library; Test Render is maintained by the React team and works on both React DOM and React Native applications
The example will consist of testing a component (and its children) that renders a Toggle button and Hello World text. The component is to take a boolean property, initialShow:
- If initialShow is true, the Hello World text is to be initially visible; clicking the Toggle button will fade the text out until it is invisible
- If initialShow is false, the Hello World text is to be initially invisible; clicking the Toggle button will fade the text in until it is visible

We begin by scaffolding a TypeScript React project as described in the article Hello Create React App (CRA) — TypeScript.
We then create two components and their associated styles:
- src/components/HiddenText/index.tsx: Stateful container component; principally consisting of boolean state show and method toggle to toggle it
- src/components/HiddenText/HiddenText.css: Defines two classes; hidden-message-enter (styling for Hello Text when initially visible) and hidden-message-exit (styling for Hello Text when initially invisible)
- src/components/HiddenText/Fade.tsx: Stateless presentational component performing the fade animation using the CSSTransition component from the react-transition-group library
- src/components/HiddenText/Fade.css: Defines classes supporting the fade animation
We come to our first idea at work, instead of writing two separate unit tests, one for each component, we will write a series of integration test for the whole feature.
From the description of the feature above, we essentially need to test:
- Showing at mount with initialShow true
- Hidden at mount with initialShow false
- Hidden after button click with initialShow true
- Showing after button click with initialShow false
For testing the mounting behavior we do not want to test against the show state, an internal implementation detail, but rather the outward expression of visibility, in this case the use of the CSS classes hidden-message-enter and hidden-message-exit).
There are two arguments for testing using the presence of CSS classes:
- While an implementation detail, using class names shields us from having to test against the more implementation intensive styling they define
- Test Render works from a React-centric perspective; class names are used in the React className property; the styling they define, however, are completely opaque to React
note: Using CSS modules, as I do, requires some special mocking to use this approach.
To ensure the animation is properly initialized when the component is mounted, we will inspect the in property for third-party component CSSTransition. While testing against the CSSTransition component is an implementation detail, it shields us from having to test against the more implementation intensive classes that it uses.
With this approach in mind, we create two of the tests in src/components/HiddenText/HiddenText.test.tsx:
We next need to test the effect of clicking the button. Using the philosophy of testing using user facing features instead of implementation details, we trigger the function supplied to the button’s onClick property rather than the classes’ toggle method directly; a subtle but important difference.
Observations:
- Because React’s setState method is asynchronous, we introduce a delay to ensure that changes take effect after clicking the button and before continuing the test; at the same time, the tests worked without the delay (left delay in at 0 to play it safe)
- Also, it turns out the CSSTransition component in the react-transition-group library directly manipulates the DOM. Because Test Render does not use the DOM (emulated or not), we need to mock the CSSTransition component
Wrap Up
If you are still uncertain or unconvinced of this approach to testing, I would recommend that you read several of Kent Dodds’ articles, e.g.:
Hope you found this article helpful.