Testing React Components with React Testing Library and Jest
We all know React as one of the most popular frontend JavaScript libraries out there currently. React helps you build modular UI that you can easily reuse. Redux is a state management library that helps you maintain state across your React app.
If you’re working on a React app in a company setting, you’re gonna want to make sure you write tests to ensure quality of code. Jest is a test framework which goes very well with React so that’s what we’re gonna use when discussing tools to test React components.
While Jest is great, we’re gonna need some more assistance to help us test our React components. Jest provides snapshot testing which is good for testing that your UI does not change unexpectedly. However, this of course cannot catch all cases.
At at previous company, we brought in this library called Enzyme which was originally created by Airbnb. Enzyme is basically a JavaScript Testing Utility for React that makes it easier to test React component’s output.
I’m seeing a huge growth in popularity of a tool called React Testing Library. From what I’ve read so far, it seems like the biggest difference between Enzyme and React Testing Library is that React Testing Library allows you to write tests as the users would use your application whereas Enzyme allows you to test the internals of your React components.
Now that React officially recommendings using React Testing Library in your own documentation, it’s a good time to take a deeper look at React Testing Library.
React Testing Library as really 2 core API:
- Queries
- User Actions
Queries
You have three main types of queries:
getBy
… returns the matching node and throws an error if no elements match or more than 1 match is found.queryBy
…returns the first mating node for a query, and returns null if no elements match.findBy
… returns a promise which revolves when an element is found which matches the given query.
queryBy...
is useful for asserting that an element is not present.
findBy...
is used for testing asynchronous actions.
For all three types we also have the multiple variant:
getAllBy
… returns an array of all matching nodes for a query and throws an error if no elements match.queryAllBy
… returns an array of all matching nodes for a query, and returns an empty array if no elements match.findAllBy
… returns a promise which resolves to an array of elements when any element are found which match the given query.
User Actions
By default, React Testing Library provides an API called fireEvent but it is pretty low level.
// <button>Submit</button>
fireEvent(
getByText(container, 'Submit'),
new MouseEvent('click', () => {
bubbles: true,
cancelable: true,
})
)
Because fireEvent is pretty low level and not that easy to use, user-event is the recommended companion library for React Testing Library. user-event provides API with higher level abstraction.
create-react-app has this built in along with react-testing-library
import React from 'react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
test('click', () => {
render(
<div>
<label htmlFor='checkbox'>Check</label>
<input id='checkbox' type='checkbox' />
</div>
);
userEvent.click(screen.getByText('Check'));
expect(screen.getByLabelText('Check')).toBeChecked();
});
As you can see, the code that initates the click event is now very intuitive and simple to use. We use the userEvent.click
method and pass in the actual element as the target for our click event.
Summary
React Testing Library is a great way to test your React components in a way that users interact with them. Instead of knowing to know the inner workings of a React component like with Enzyme, you only need to know how to interact with a React component as a user with React Testing Library.