Chapter 2: Working with React Testing Library
By the end of this chapter, you will know how to add React Testing Library to React projects. React Testing Library is a modern tool for testing the UI output of React components from the perspective of end users. You will learn how to properly structure tests using the methods from the API. You will learn how to test presentational components. Finally, you will learn how to use the debug
method to assist in building out your tests.
In this chapter, we're going to cover the following topics:
- Adding React Testing Library to existing projects
- Structuring tests with React Testing Library
- Testing presentational components
- Using the
debug
method while writing tests
The skills you will learn in this chapter will set the foundation for more complex component scenarios in later chapters.
Technical requirements
For the examples in this chapter, you will need to have Node.js installed on your machine. We will be using the create-react-app
CLI tool for all code examples. Please familiarize yourself with the tool before starting the chapter if needed. You can find code examples for this chapter here: https://github.com/PacktPublishing/Simplify-Testing-with-React-Testing-Library/tree/master/Chapter02.
Adding React Testing Library to existing projects
To get started with React Testing Library, the first thing we need to do is install the tool into our React project. We can either install it manually or use create-react-app
, a specific React tool that automatically has React Testing Library installed for you.
Manual installation
Add React Testing Library to your project using the following command:
npm install --save-dev @testing-library/react
Once the tool is installed into your project, you can import the available API methods to use inside your test files.
Next, we will see how to start a React project with React Testing Library when it is already installed for you.
Automatic installation with create-react-app
The create-react-app
tool allows you to create a one-page React application quickly. The create-react-app
tool provides a sample application and an associated test to get you started. React Testing Library has become so popular that as of version 3.3.0, the create-react-app
team added React Testing Library as the default testing tool. The create-react-app
tool also includes the user-event
and jest-dom
utilities. We previously went over jest-dom
in Chapter 1, Exploring React Testing Library. We will cover the user-event
utility in Chapter 3, Testing Complex Components with React Testing Library.
So, if you are using at least version 3.3.0 of create-react-app
, you get a React application with React Testing Library, user-event
, and jest-dom
automatically installed and configured.
There are two ways you can run the create-react-app
tool to create a new React application. By default, both ways of running the create-react-app
tool will automatically install the latest version of create-react-app
. The first way is with npx
, which allows you to create a React project without needing to have the create-react-app
tool globally installed on your local machine:
npx create-react-app your-project-title-here --use-npm
When using the preceding command, be sure to replace your-project-title-here
with a title to describe your unique project. Also, notice the --use-npm
flag at the end of the command. By default, when you create a project using create-react-app
, it uses Yarn as the package manager for the project. We will use npm
as the package manager throughout this book. We can tell create-react-app
we want to use npm
as the package manager instead of Yarn using the --use-npm
flag.
The second way to create a React application with create-react-app
is by installing the tool globally to run on your local machine. Use the following command to install the tool globally:
npm install -g create-react-app
In the previous command, we used the -g
command to globally install the tool on our machine. Once the tool is installed on your machine, run the following command to create a project:
create-react-app your-project-title-here --use-npm
Like the command we ran in the previous example to create a project using npx
, we create a new project titled your-project-title-here
using npm
as the package manager.
Now you know how to manually install React Testing Library or have it automatically installed using create-react-app
. Next, we will learn about common React Testing Library API methods used to structure tests.
Structuring tests with React Testing Library
To structure and write our test code, we will use the Arrange-Act-Assert pattern that's typical in writing unit tests. There are a few ways to use React Testing Library API to structure tests, but we will be using React Testing Library team's recommended approach to render React elements into the Document Object Model (DOM), select resulting DOM elements, and make assertions on the expected resulting behavior.
Rendering elements
To test your React components' output, you need a way to render them into the DOM. The React Testing Library's render
method takes a passed-in component, puts it inside a div
element, and attaches it to the DOM, as we can see here:
import { render} from '@testing-library/react' import Jumbotron from './Jumbotron' it('displays the heading, () => { render(<Jumbotron />) }
In the previous code, we have a test file. First, we import the render
method from React Testing Library. Next, we import the Jumbotron component we want to test. Finally, we arrange our test code in the it
method by using the render
method to render the component to test.
It is necessary to write additional code to clean up our test in many testing frameworks. For example, if a component is rendered into the DOM for one test, it needs to be removed before the next test is executed. Removing the component from the DOM allows the following test to start from a clean slate and not be affected by code from previous tests. React Testing Library's render
method makes test cleanup easier by automatically taking care of removing components from the DOM, so there is no need to write additional code to clean up the state affected by previous tests.
Now that you know how to arrange a test by rendering a component into the DOM for testing, we will learn how to interact with the component's resulting DOM output in the next section.
Selecting elements in the component DOM output
Once we have rendered our component to test into the DOM, the next step is to select elements. We will do this by querying the output as a user would. The DOM Testing Library API has a screen
object that is included with React Testing Library, allowing you to query the DOM:
import { render, screen } from '@testing-library/react'
In the previous code, we imported screen
from React Testing Library just like we imported render
. The screen
object exposes many methods, such as getByText
or getByRole
, used to query the DOM for elements, similar to actual users that we can use in our tests. For example, we might have a component that renders the following DOM output:

Figure 2.1 – Jumbotron component
If we wanted to search the DOM for the element with the text Welcome to our site!, we could do so in two ways.
One way would be using the getByText
method:
it('displays the heading', () => { render(<Jumbotron />) screen.getByText(/welcome to our site!/i) })
The getByText
method will query the DOM, looking for an element with text matching Welcome to our site!. Notice how we use a regular expression inside the getByText
method. A user looking for the element wouldn't care if the text was in upper or lower case, so getByText
and all other screen
object methods follow the same approach.
A second way we could query the DOM for the element with the text Welcome to our site! is by using the getByRole
method:
it('displays the heading, () => { render(<Jumbotron />) screen.getByRole('heading', { name: /welcome to our site!/i }) })
The getByRole
method allows you to query the DOM in ways similar to how anyone, including those using screen readers, would search. A screen reader would look for an element with the role heading
and the text welcome to our site!
. There are many other methods available on the screen
object to query elements based on how you decide to find them. The DOM Testing Library team recommends using the getByRole
method to select elements as much as possible in the documentation.
Also, because our test code essentially says, search for a heading element with the text 'welcome to our site!'
, it is more explicit than the previous example, where we used getByText
to search for any element that has the text 'welcome to our site!'
.
In the Enhancing jest assertions with jest-dom section of Chapter 1, Exploring React Testing Library, we learned that the methods of jest-dom
provide context-specific error messages.
The methods on the screen
object provide the same benefits. For example, if you attempt to use getByRole
to select an element that is not present in the DOM, the method will stop test execution and provide the following error message:
Unable to find an accessible element with the role "heading" and name `/fake/i`
In the previous code, the error message explicitly tells you that the query method did not find the element. Also, the error message helps by logging elements that are selectable based on the rendered DOM:
heading: Name "Logo": <h3 class="navbar-brand mb-0" style="font-size: 1.5rem;" /> Name "Welcome to our site!": <h1 />
In the preceding code, the logged elements help by providing a visual representation of the DOM to understand better why the element you searched for was not found. Now you know how to select elements using React Testing Library.
We will learn more advanced ways of interacting with components, such as clicking or entering text, in Chapter 3, Testing Complex Components with React Testing Library.
Next, we will learn how to assert the expected output of components.
Asserting expected behavior
The last step in the test structure is to make assertions on behavior. In the Enhancing jest assertions with jest-dom section of Chapter 1, Exploring React Testing Library, we learned how to install and use the jest-dom
tool to make assertions. Building on our test where we searched for the heading element with the text welcome to our site!
, we can use the toBeInTheDocument
method from jest-dom
to verify whether the element is in the DOM:
it('displays the heading', () => { render(<Jumbotron />) expect( screen.getByRole('heading', { name: /welcome to our site!/i }) ).toBeInTheDocument() })
If the element is not found, we will receive error messages and visual feedback to help determine the source of the problem logged to the console, similar to what we saw in the Interacting with the component DOM output section. If we get the expected behavior, then we will receive feedback in the console that our test passed, as shown in the following screenshot:

Figure 2.2 – Jumbotron component test results
In the previous screenshot, the results indicate that the displays the heading test passes. Now you know how to make assertions on the output of components with React Testing Library. The skills learned in this section have set the foundational skills needed in the next section, where we start testing presentational components.
Testing presentational components
In this section, we will use our knowledge of installing and structuring tests with React Testing Library to test presentational components. Presentational components are components that do not manage state. Typically, you use presentational components to display data passed down from parent components as props or to display hardcoded data directly in the component itself.
Creating snapshot tests
Snapshot tests are provided by Jest and are great to use when you simply want to make sure the HTML output of a component does not change unexpectedly. Suppose a developer does change the component's HTML structure, for example, by adding another paragraph element with static text. In that case, the snapshot test will fail and provide a visual of the changes so you can respond accordingly. The following is an example of a presentational component that renders hardcoded data related to travel services to the DOM:
const Travel = () => { return ( <div className="card text-center m-1" style={{ width: '18rem' }}> <i className="material-icons" style={{ fontSize: '4rem' }}> airplanemode_active </i> <h4>Travel Anywhere</h4>
The component displays an airplane icon in the previous code snippet in an <i>
element and a heading inside an <h4>
element:
<p className="p-1"> Our premium package allows you to take exotic trips anywhere at the cheapest prices! </p> </div> ) } export default Travel
In the last piece of the component, the preceding code snippet displays text inside a paragraph element. The resulting DOM output looks like the following:

Figure 2.3 – Travel component
Since the component simply displays a few lines of static hardcoded text, it makes it a good candidate for a snapshot test. In the following example, we use snapshot testing to test the Travel
component:
import { render } from '@testing-library/react' import Travel from './Travel' it('displays the header and paragraph text', () => { const { container } = render(<Travel />)
First, in our test file we import the render
method from React Testing Library. Next, we import the Travel
component. Then, we use object destructuring to get container
off the rendered component. container
represents the resulting HTML output of the component. Finally, we use the toMatchInlineSnapshot
method from Jest to capture the resulting HTML output.
The following is a portion of the snapshot for the Travel
component output we saw at the beginning of this section:
expect(container).toMatchInlineSnapshot(` <div> <div class="card text-center m-1" style="width: 18rem;" > <i class="material-icons" style="font-size: 4rem;" > airplanemode_active </i>
Now, if in the future a developer changes the output of the Travel
component, the test will fail and inform us of the unexpected changes. For example, a developer may change the heading from Travel Anywhere
to Go Anywhere
:

Figure 2.4 – Failed travel snapshot test
The preceding screenshot shows that the test failed and shows us which lines changed. Travel Anywhere
is the text the snapshot is expected to receive that differed from the received text, Go Anywhere. Also, the line number, 8, and position in the line, 11, where the difference was found are also pointed out. If the change was intentional, we can update our snapshot with the new change. Run the following command to update the snapshot:
npm test -- -u
If your tests are currently running in watch mode, simply press the U key on your keyboard to update the snapshot. If the change was not intentional, we can simply change the text back to the original value inside the component file.
Now that you know how to create snapshot tests for presentational components, we will now learn how to verify properties passed into presentational components.
Testing expected properties
Presentational components can have data passed into them as props
, instead of hardcoded data directly in the component. The following is an example of a presentational component that expects an array of objects for employees to display in a table:
const Table = props => { return ( <table className="table table-striped"> <thead className="thead-dark"> <tr> <th scope="col">Name</th> <th scope="col">Department</th> <th scope="col">Title</th> </tr> </thead>
In the preceding code snippet, the component has a table with the headings Name
, Department
, and Title
for each employee. The following is the table body:
<tbody> {props.employees.map(employee => { return ( <tr key={employee.id}> <td>{employee.name}</td> <td>{employee.department}</td> <td>{employee.title}</td> </tr> ) })} </tbody> </table> ) } export default Table
In the preceding code snippet, we iterate over the employees
array from the props
object inside the table body. We create a table row for each employee, access the employee's name, department, and title, and render the data into a table cell element.
The following is an example of the resulting DOM output:

Figure 2.5 – Table component
The Table
component displays rows of employees that match the expected shape of an array of objects with Name, Department, and Title properties. We can test that the component properly accepts and displays the rows of employee data in the DOM:
import { render, screen } from '@testing-library/react' import fakeEmployees from './mocks/employees' import Table from './Table' it('renders with expected values', () => { render(<Table employees={fakeEmployees} />)
First, we import the render
method and screen
object from React Testing Library. Next, we pass in a fake array of employee objects called fakeEmployees
, created for testing purposes, and the Table
component. The fakeEmployees
data looks like the following:
const fakeEmployees = [ { id: 1, name: 'John Smith', department: 'Sales', title: 'Senior Sales Agent' }, { id: 2, name: 'Sarah Jenkins', department: 'Engineering', title: 'Senior Full-Stack Engineer' }, { id: 3, name: 'Tim Reynolds', department: 'Design', title: 'Designer' } ]
Finally, we create the main test code to verify the fakeEmployee
data is present in the DOM:
it('renders with expected values', () => { render(<Table employees={fakeEmployees} />) expect(screen.getByRole('cell', { name: /john smith/i })).toBeInTheDocument() expect(screen.getByRole('cell', { name: /engineering/i })).toBeInTheDocument() expect(screen.getByRole('cell', { name: /designer/i })).toBeInTheDocument() })
For the preceding code snippet's assertions, we verified that at least one piece of each object was present in the DOM. You could also verify that every piece of data is present in the DOM if that aligns with your testing objectives. Be sure to verify that your code tests what you expect it is testing. For example, try making the test fail by using the screen
object to query the DOM for employee data that should not be present. If the test fails, you can be more confident that the code tests what you expect.
Although most of the time we want to avoid implementation details and write our tests from the perspective of the user, there may be times where testing specific details is important to our testing goals. For example, if it might be important to you to verify that the striped color theme is present in the rendered version of the table component. The toHaveAttribute
assertion method of Jest-dom
can be used in this situation:
it('has the correct class', () => { render(<Table employees={fakeEmployees} />) expect(screen.getByRole('table')).toHaveAttribute( 'class', 'table table-striped' ) })
In the preceding code snippet, we created a test to verify that the table component has the correct class attribute. First, we render the Table
component with employees. Next, we select the table
element using the getByRole
method off the screen
object. Finally, we assert that the component has a class
attribute with the value table table-striped
. By using toHaveAttribute
, we can assert the value of component attributes when needed.
Now you know how to test presentational components that accept props
as data.
In the next section, we will learn how to use the debug
method to analyze the current state of component output as we build out our tests.
Using the debug method
The debug
method, accessible from the screen
object, is a helpful tool in React Testing Library's API that allows you to see the current HTML output of components as you build out your tests. In this section, we will learn how to display the resulting DOM output of an entire component or specific elements.
Debugging the entire component DOM
You can use the debug
method to log the entire DOM output of a component when you run your test:
it('displays the header and paragraph text', () => { render(<Travel />) screen.debug() })
In the preceding code, we first rendered the Travel
component into the DOM. Next, we invoked the debug
method. When we run our test, the following will be logged to the console:

Figure 2.6 – Travel DOM debug
In the previous screenshot, the entire DOM output of the Travel
component is logged to the screen. Logging the whole output can help you build out your test, especially when interacting with one element in the DOM affects elements elsewhere in the current DOM. Now you know how to log the output of the entire component DOM to the screen. Next, we will learn how to log specific elements of the DOM to the screen.
Debugging specific component elements
You can use the debug
method to log specific elements of the resulting component DOM to the screen:
it('displays the header and paragraph text', () => { render(<Travel />) const header = screen.getByRole('heading', { name: /travel anywhere/i }) screen.debug(header) })
In the previous code, first, we rendered the Travel
component into the DOM. Next, we used the getByRole
method to query the DOM for a heading with the name travel anywhere
and saved it to a variable named header
. Next, we invoked the debug
method and passed in the header
variable to the method. When we run our test, the following will be logged to the console:

Figure 2.7 – Travel element debug
When you pass in a specific DOM node found by using one of the available query methods, the debug
method only logs the HTML for the particular node. Logging the output for single elements can help you only focus on specific parts of the component. Be sure to remove any debug
method code from your tests before making commits because you only need it while building out the test.
Now you know how to use the debug
method to render the resulting DOM output of your components. The debug
method is a great visual tool to have while writing new tests and also when troubleshooting failing tests.
Summary
In this chapter, you have learned how to install React Testing Library into your React projects. You now understand how to use the API methods to structure your tests. You know how to test presentational components, which serves as foundational knowledge to build on in the following chapters. Finally, you learned how to debug the HTML output of components as you build out your tests.
In the next chapter, we will learn how to test code with more complexity. We will also learn how to use the Test-Driven Development (TDD) approach to drive test creation.
Questions
- What method is used to place React components into the DOM?
- Name the object that has methods attached to query the DOM for elements.
- What types of components are good candidates for snapshot tests?
- What method is used for logging the DOM output of components?
- Create and test a presentational component that accepts an array of objects as props.