Skip to main content

React Testing Tutorial – How to Test React Components

The two main tools you need to test your React components are:

  1. A test runner tool
  2. A React component testing tool

But what exactly is the difference between a test runner and a React component testing tool? Let's find out.

Test Runner vs. React Component Testing Tool: What's the Difference?

Below are the differences between a test runner and a React component testing tool.

Test runner: What does it mean?

A test runner is a tool developers use to run a test script and print the test's results on the command line (CLI).

For instance, suppose you need to run the test cases in your project's App.test.js test script. In such a case, you will use a test runner.

The test runner will execute App.test.js and print the test's results on the command line.

Typical examples of test runners are Jasmine, Mocha, Tape, and Jest.

info

See the test-driven development tutorial for a good guide on using Jest as a test runner tool for your JavaScript and React projects.

Let's now discuss what a React component testing tool is.

React component testing tool: What does it mean?

A React component testing tool provides helpful APIs for defining a component's test cases.

For instance, suppose you need to test your project's <App /> component. In such a case, you will use a React component testing tool to define the component's test cases.

In other words, a React component testing tool provides the APIs for writing your component's test cases.

Typical examples are Enzyme and the React Testing Library.

So, now that we know what a test runner and React component testing tool are, let's use a mini-project to understand how React testing works.

Project: How React Testing Works

In the following steps, we will use Jest and the React Testing Library (by Kent C. Dodds) to learn how React testing works.

info

The React official docs recommend the Jest and React Testing Library combination for testing React components.

Prerequisite

To complete this tutorial, you need to know how to use Jest. See the TDD tutorial for a good guide on Jest.

Step 1: Get the right Node and NPM version

Make sure that you have Node 10.16 (or greater) and NPM 5.6 (or greater) installed on your system.

If you prefer to use Yarn, ensure you have Yarn 0.25 (or greater).

Step 2: Create a new React app

Use NPM's create-react-app package to create a new React app called react-testing-project.

npx create-react-app react-testing-project

Alternatively, you can use Yarn to configure your project like so:

yarn create react-app react-testing-project

Step 3: Go inside the project directory

After the installation process, navigate into the project directory like so:

cd react-testing-project

Step 4: Set up your test environment

Install the following test packages:

info

If you've initialized your React project with create-react-app (step 2), you do not need to install any of the packages below. They come preinstalled and preconfigured in your package.json file.

  • jest
  • @testing-library/react
  • @testing-library/jest-dom
  • @testing-library/user-event

Now, let's discuss the purpose of each of the above test packages.

CodeSweetly ads

Master NPM Package Creation

Elevate your skills, boost your projects, and stand out in the coding world.
Learn more

jest

jest is the test runner tool we will use to run this project's test scripts and print the test results on the command line.

@testing-library/react

@testing-library/react is the React Testing Library which gives you the APIs you need to write test cases for your React components.

@testing-library/jest-dom

@testing-library/jest-dom provides some set of custom jest matchers for testing the DOM's state.

note

Jest already comes with lots of matchers, so using jest-dom is optional.

jest-dom simply extends Jest by providing matchers that make your test more declarative, clear to read, and easy to maintain.

@testing-library/user-event

@testing-library/user-event provides the userEvent API for simulating users' interaction with your app on a web page.

note

@testing-library/user-event is a better alternative to the fireEvent API.

Step 5: Clean up the src folder

Delete all files inside the project directory's src folder.

Step 6: Create your code files

Create the following files inside your project's src folder.

  • index.js
  • App.js
  • App.test.js

Step 7: Render the App component

Open your index.js file and render the App component to the DOM like so:

index.js
import React from "react";
import { createRoot } from "react-dom/client";
import App from "./App";

// Render the App component into the root DOM
createRoot(document.getElementById("root")).render(<App />);

Step 8: Write your test case

Suppose you want your App.js file to render a <h1>CodeSweetly Test</h1> element to the web page. In that case, open your test script and write a test code specifying the result you expect your <App /> component to produce.

Here's an example:

App.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import App from "./App";

test("codesweetly test heading", () => {
render(<App />);
expect(screen.getByRole("heading")).toHaveTextContent(/codesweetly test/i);
});

Here are the main things we did in the test snippet above:

  1. We imported the packages needed to write our test case.
  2. We wrote a test case specifying that we expect our <App /> component to render a heading element with a "codesweetly test" text.
note
  • test() is one of Jest's global methods. We use it to run a test case. The method accepts three arguments:
    • The name of the test ("codesweetly test heading")
    • A function containing the expectations you wish to test
    • An optional timeout argument
  • render() is one of the React Testing Library APIs. We use it to render the component we wish to test.
  • expect() is a Jest method that lets you test the output of your code.
  • screen is a React Testing Library's object containing numerous methods for finding elements on a page.
  • getByRole() is one of the React Testing Library's query methods for finding elements on a page.
  • toHaveTextContent() is one of jest-dom's custom matchers that you can use to confirm the presence of a text content in a specific node.
  • /codesweetly test/i is a regular expression syntax that we used to specify a case-insensitive search for codesweetly test.

Keep in mind that there are three alternative ways to write the above expect statement:

// 1. Using jest-dom's toHaveTextContent() method:
expect(screen.getByRole("heading")).toHaveTextContent(/codesweetly test/i);

// 2. Using the heading's textContent property and Jest's toMatch() method:
expect(screen.getByRole("heading").textContent).toMatch(/codesweetly test/i);

// 3. Using React Testing Library's name option and jest-dom's toBeInTheDocument() method
expect(
screen.getByRole("heading", { name: /codesweetly test/i })
).toBeInTheDocument();
tip

Add a level option to the getByRole() method to specify your heading's level.

Here's an example:

test("codesweetly test heading", () => {
render(<App />);
expect(screen.getByRole("heading", { level: 1 })).toHaveTextContent(
/codesweetly test/i
);
});

The level: 1 option specifies an <h1> heading element.

Suppose you run the test code now. The test will fail because you've not developed the component for which you created the test. So, let's do that now.

Step 9: Develop your React component

Open your App.js file and develop the component to pass the prewritten test.

Here's an example:

App.js
import React from "react";

const App = () => <h1>CodeSweetly Test</h1>;

export default App;

The App component, in the snippet above, renders a <h1> element containing a "CodeSweetly Test" text.

Step 10: Run the test

Run the prewritten test to check if your program passed or failed.

npm test App.test.js

Once you've initiated the test, Jest will print a pass or fail message on your editor's console. The message will look similar to this:

$ jest
PASS src/App.test.js
√ codesweetly test heading (59 ms)

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 3.146 s
Ran all test suites related to changed files.
note

The create-react-app configured Jest in watch mode by default. Therefore, after running npm test (or yarn test), your currently opened terminal will continue to process the test command's activities. So, you won't be able to input any command on that terminal until you stop test's execution. But you can open a new terminal window simultaneously with the one processing test.

In other words, use one terminal to run test and another to input commands.

Step 11: Run the application

Take a look at your app in the browser by running:

npm run start

Once you run the command above, your app will automatically open on your default browser.

Step 12: Refactor the test code

Suppose you wish to change the heading's text when users click a button. In that case, you can simulate users' interaction with the button to confirm that it works as intended.

Here's an example:

App.test.js
import React from "react";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "@testing-library/jest-dom";
import App from "./App";

describe("App component", () => {
test("codesweetly test heading", () => {
render(<App />);
expect(screen.getByRole("heading")).toHaveTextContent(/codesweetly test/i);
});

test("a codesweetly project heading", () => {
render(<App />);

const button = screen.getByRole("button", { name: "Update Heading" });

userEvent.click(button);

expect(screen.getByRole("heading")).toHaveTextContent(
/a codesweetly project/i
);
});
});

Here are the main things we did in the test snippet above:

  1. We imported the packages needed to write our test case.
  2. We wrote a test case specifying that we expect the <App /> component to render a heading element with a "codesweetly test" text.
  3. We wrote another test case simulating users' interaction with the app's button element. In other words, we specified that whenever a user clicks the button, we expect <App />'s heading to update to "a codesweetly project" text.
note
  • describe() is one of Jest's global methods. It is an optional code that helps organize related test cases into groups. describe() accepts two arguments:
    • A name you wish to call the test case group—for instance, "App component".
    • A function containing your test cases.
  • userEvent is the React Testing Library's package containing several methods for simulating users' interaction with an app. For instance, in the snippet above, we used userEvent's click() method to simulate a click event on the button element.
  • We rendered <App /> for each test case because React Testing Library unmounts the rendered components after each test. However, suppose you have numerous test cases for a component. In that case, use Jest's beforeEach() method to run render(<App />) before each test in your file (or describe block).

Step 13: Refactor your React component

So, now that you've refactored your test code, let's do the same for the App component.

// App.js

import React, { useState } from "react";

const App = () => {
const [heading, setHeading] = useState("CodeSweetly Test");

const handleClick = () => {
setHeading("A CodeSweetly Project");
};

return (
<>
<h1>{heading}</h1>
<button type="button" onClick={handleClick}>
Update Heading
</button>
</>
);
};

export default App;

Here are the main things we did in the snippet above:

  1. App's heading state got initialized with a "CodeSweetly Test" string.
  2. We programmed a handleClick function to update the heading state.
  3. We rendered a <h1> and <button> elements to the DOM.

Note the following:

  • <h1>'s content is the heading state's current value.
  • Whenever a user clicks the button element, the onClick() event listener will trigger the handleClick() function. And handleClick will update App's heading state to "A CodeSweetly Project". Therefore, <h1>'s content will also change to "A CodeSweetly Project".

Step 14: Rerun the test

Once you've refactored your component, rerun the test (or check the actively running test) to confirm that your app still works as expected.

Afterward, check the browser to see your recent updates.

And that's it!

Congratulations! You've successfully used Jest and the React Testing Library to test a React component.🎉

Overview

This article discussed how to test React components using two popular tools—Jest and the React Testing Library.

Useful Resources

Below are links to other valuable content on React testing.

Your support matters: Buy me a coffee to support CodeSweetly's mission of simplifying coding concepts.

Join CodeSweetly Newsletter