Skip to content

Testing React Components

JC Quirin edited this page Mar 8, 2021 · 6 revisions

Writing tests for React components is more complicated. We need to ensure that, given a particular set of props, the component renders consistently and accessibly. We need to ensure that user interaction results in the intended changes, either internal to the component or by triggering the expected callbacks.

The React docs give a good overview of basic principles and best practices.

Recommended Tools


Snapshot Testing

A good rule of thumb is to add an automated snapshot test for every possible different rendering scenario for a component.

This can be done with a few lines of code:

it('renders correctly', () => {
  const { container } = render(<MyComponent />);

  expect(container).toMatchSnapshot();
});

Accessibility Testing

Much like with snapshots, it is a good rule to add an automated a11y test for every possible different rendering scenario for a component. This can be done fairly simply with this sort of structure:

import { axe } from 'jest-axe';

it('passes a11y', async () => {
  const { container } = render(<MyComponent />);

  const results = await axe(container);

  expect(results).toHaveNoViolations();
});


React Testing Library vs Enzyme

Historically, the Enzyme library from Airbnb was the utility often used for testing React components. It provides ways to render just a portion of your component tree, select one or more elements, and act upon them. We have a number of tests in our Caseflow code base that use Enzyme. If you see any references to mount or shallow, that's a good sign these tests utilize Enzyme.

In more recent times, the official recommendation of the React team is to utilize React Testing Library for testing React components. The primary reason is a difference in philosophy between the two libraries.

While Enzyme focuses on testing the implementation of components (e.g. selecting elements by their id or type, for instance), React Testing Library guides one to test components in ways that mimic how a user might interact with them. So for instance, instead of selecting an element by its HTML tag, you might select it by its accessibility role.

Example:

// Enzyme
test('has correct welcome text', () => {
  const wrapper = shallow(<Welcome firstName="John" lastName="Doe" />)
  expect(wrapper.find('h1').text()).to.equal('Welcome, John Doe')
})

// React Testing Library
test('has correct welcome text', () => {
  render(<Welcome firstName="John" lastName="Doe" />)
  expect(screen.getByRole('heading')).toHaveTextContent('Welcome, John Doe')
})

This ultimately encourages writing tests that ensure that the user experience is covered (even for users using screen reader), but the exact under-the-hood implementations aren't what is important (and in fact can be changed without changing the user experience or breaking your tests).

Refactoring Jest tests written with Enzyme to use React Testing Library

< JS Testing Overview

Clone this wiki locally