React Testing Library Overview

Lauren Cunningham
JavaScript in Plain English
5 min readJun 11, 2021

--

A simple-to-use Enzyme alternative

photo credit: academy.hsoub.com

Intro to RTL

The React Testing Library was created by the software testing guru, Kent C. Dodds. The goal was to provide a replacement for the popular JavaScript testing library, Enzyme that is more lightweight and eliminates the possibility of ‘damaging testbases’.

Kent is an advocate for good testing practices. He has written many blog posts on the topic that are publicly available and highly recommended. He explains the importance of writing tests that are maintainable meaning that they will still pass if the code being tested is refactored. The functionality is what we should be testing — not implementation.

The Setup

To be clear, React Testing Library doesn’t remove the need for Jest. It’s not a test runner, so you’ll still want to use Jest just like you would with Enzyme. There’s nothing wrong with utilizing Enzyme. It’s just a personal preference. As I mentioned before, RTL gives us the same ability to test our React components while cutting out some lesser-used methods. If you’re new to testing in React, feel free to check out my Intro to React Component Testing which covers the basics of Enzyme and Jest usage.

If you use create-react-app to build the skeleton of your application, the React Testing Library (and Jest) is already included in your dependencies. Otherwise, you can add it from your command line.

npm i --save-dev @testing-library/react

The test files must be named with .test.js at the end in order to recognized as a test when we run ‘npm test’. This single command will run all the test suites that are available.

The tests themselves still utilize the typical ‘describe’, ‘test’, and ‘expect’ blocks, but there are some built-in functions in RTL that help us mock the application’s intended use and user interactions.

Render, Screen and Debug

The render, screen, and debug are commonly used and can be accessed by importing them at the top of your file like so:

import {render, screen, debug}

Render mocks the rendering of the component that is passed in as an argument. This must be done before we can test anything within that component. After it has been rendered, we can tack on some querying methods to the screen keyword which will perform a search on the currently rendered elements.

We can also use the debug method on the screen keyword. This will expose all of the currently rendered HTML elements in your terminal so that you can see exactly what the page looks like during testing when we have performed a mock rendering. It’s best practice to add screen.debug() to the end of your test when you’re writing them to make sure you know what is and is not available to select from the screen.

Select / Query for Elements

Before testing whether or not specific elements are being rendered correctly, we need to find those elements. Querying is easy with RTL’s built-in getBy, queryBy, and findBy methods. After using the render method, we can use the screen.debug() code snippet to view what HTML is appearing and determine the best method for selecting what we need.

The getBy method is suitable for things that we expect to be rendered with the component passed to the render method. For example, if you expect the app component to have a dropdown menu right away, you could run a test like this:

describe('App', () => {  test('renders drop down menu options', () => {    render(<App />);    const dropdown = screen.getByRole('combobox');    expect(dropdown).toBeInTheDocument();  });})

There are many variations of getBy that are suggested via autocomplete in your code editor. Some of the most commonly used variations are getByText and getByRole. If you’re not sure of the role for the element you’re looking for, simply pass in an empty string as an argument and you’ll see a list of all the roles available in the currently rendered HTML.

In the event that you’re needing to test that some element is not on the screen, you’ll want to use the queryBy method which includes much of the same variations, and add .toBeNull() at the end of your expect block. Take this test from the React Testing Library for example.

describe('App', () => {test('renders App component', async () => {render(<App />);expect(screen.queryByText(/Signed in as/)).toBeNull();screen.debug();expect(await screen.findByText(/Signed in as/)).toBeInTheDocument();screen.debug();});});

You can see that the async and await keywords are used because we’re testing if the text ‘signed in as’ is showing up after a user has logged in. The findByText method is used to check if the selected element is in the document after the asynchronous function has finished executing.

Event Mocking

The fireEvent function is used when you want to fake an action taking place. It can be used to change values on form fields or clicking of buttons. However, it’s recommended to use the userEvent function when mocking user interactions.

Here’s an example of a test that checks to see if an order is cleared when the ‘start over’ button is clicked.

describe('App', () => { test('clears the current order when start over is clicked', () => {   render(<App />);   fireEvent.change(screen.getByRole('combobox'), {     target: {value: 'dinner'}    })   const addButtons = screen.getAllByRole('button')   fireEvent.click(addButtons[0])   const startOverButton = screen.getByText(/Start Over/)   expect(startOverButton).toBeInTheDocument()   fireEvent.click(startOverButton)   expect(screen.queryByText(/current order/)).toBeNull()  });})

We first render the app component, change the selected value in the dropdown menu to ‘dinner’ to display menu options. Then we check to see if the ‘start over’ button is rendered. Finally, we fake a clicking action on the button and test whether the current order is cleared.

In Closing…

I hope this article has given you a better understanding of best testing practices and introduced some additional tools that you can use for future projects. There’s a ton of documentation, tutorials, and blogs regarding use cases for the React Testing Library. If you typically use Enzyme, I encourage you to check out the resources below and try something different. You’ll be glad you did!

--

--