Dec 14, 2021
React ·7 min read
If you are a React developer and still not using the React Testing Library, you ought to keep reading further. Sorry, we don’t make the rules! And also, why not! It’s simple, fun, and easiest to work with. Let’s get started already!
React Testing Library (RTL) is a collection of utilities that helps in testing React Components without relying on the details of their implementation. This method makes refactoring easy and encourages us to use best practices for accessibility.
Introduction
Testing is applicable for ensuring a reliable user experience without any errors in any functionality. In other words, testing an application makes sure that whatever functions and features that you have developed works as per your expected outcomes. Having maintainable tests makes your application robust and less error-prone.
React Testing Library is a lightweight solution used to avoid considering implementation details (how is a Component developed) and rather focus on testing the functionalities of React Components for their intended purpose. It is built on the DOM testing library. Application projects created with Create React App have the inbuilt support for React Testing Library. Otherwise, one can install it via npm as:
npm install --save-dev @testing-library/react
Types of Testing in React
Clone the demo project from https://github.com/Ferin79/react-testing-library-article-demo
We will reference this simple react application for unit testing with React Testing Library in this article.
Why test with React Testing Library?
It is a simple and complete React DOM testing utility that encourages good testing practices. It provides light utility functions on the top of react-dom and react-dom/test-utils, in a way that encourages finer testing practices. React Testing Library is a tool in the Testing Frameworks category of a tech stack.
If you don’t want to use RTL, there are alternative libraries for testing like
Testing Header Component
In the react application that we have referenced, there is a Header component as shown below.
This component can be tested individually by writing the following code.
/tests/components/Header.test.jsx
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Header from "../../components/Header";
test("render title correctly", () => {
render(<Header />);
const titleElement = screen.getByText(/My Contacts/i);
expect(titleElement).toBeInTheDocument();
});
In the above code, we are first rendering the Header component on the user screen, then we are storing the title of the element in the titleElement
constant by getting the text on the screen. We can import the screen from the @testing-library/react
. Lastly, we are expecting the titleElement
to be present in the document. It is simply an assertion for testing. That is, if the text is not found in the document, then the test would fail otherwise it will pass successfully.
This is the output of the test done by the above code. The test has passed successfully because the expect
method returns true for verifying that the text titleElement
is on the screen.
Test Method: This method initiates the test in React and takes two arguments which are-
Render Method: This method renders the React component into a container that is appended to document.body
Screen Object: The screen object is imported from ‘@testing-library/react’
which has all the query methods which you can use to select elements from DOM. Some of the queries are shown in the following table-
This is the brief of single and multiple elements queries sourced from https://testing-library.com/docs/queries/about/#screen. You can use these queries with the screen
object to retrieve the document element(s) for testing purposes. For instance, the getBy
query can be used to retrieve a single node from the screen.
Expect method: This method is used to assert the selected elements. You can bind many assertion methods to expect method. We will discuss many assertion methods later on.
In the above example, we have used the toBeInTheDocument
assertion method exported by @testing-library/jest-dom
with expect
method which is used to inspect whether the selected element is present in DOM or not. This method returns a boolean, that is true or false, which assists tests to either pass or fail.
Now, let’s see the following code that fails the test.
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Header from "../../components/Header";
test("Render Title Correctly", () => {
render(<Header />);
const titleElement = screen.getByText(/Ferin Patel/i);
expect(titleElement).toBeInTheDocument();
});
The above code is the same code as the previous example that you have seen. The only difference here is in the getByText
method that is trying to find Ferin Patel instead of My Contacts in the DOM.
This test failed because we are trying to find text ‘Ferin Patel’ which is not present in Header Component.
There’s an alternative method ‘It’ to the test method.
It method: The it method is an alternative method to the test method. Likely, it also expects two parameters string and the callback function while executing.
it("Render Title Correctly by it method", () => {
render(<Header />);
const titleElement = screen.getByText(/My Contacts/i);
expect(titleElement).toBeInTheDocument();
});
Describe method: When there are a lot of tests in a single file, it becomes difficult to manage all tests. So for better management of the tests, we have the describe
method. This method helps us to organize tests. It can also be referred to as Test Suite. For instance, let’s see the following code-
import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import Header from "../../components/Header";
describe("Example of 'test' method and 'it' method", () => {
test("Render Title Correctly", () => {
render(<Header />);
const titleElement = screen.getByText(/My Contacts/i);
expect(titleElement).toBeInTheDocument();
});
it("Render Title Correctly by it method", () => {
render(<Header />);
const titleElement = screen.getByText(/My Contacts/i);
expect(titleElement).toBeInTheDocument();
});
});
More tests on Header
The following code shows the Header component in our referenced project.
/components/Header.jsx
import { Flex, Heading, Text } from "@chakra-ui/react";
import React from "react";
const Header = ({ total = 0 }) => {
return (
<Flex
w="100%"
h="10vh"
background="rgba(255,255,255,0.5)"
borderTopRadius="2xl"
px="6"
justify="center"
flexDirection="column"
>
<Heading fontSize="2xl">My Contacts</Heading>
<Text color="green.500" fontWeight="semi-bold" data-testid="total-id">
{total} {total > 1 ? "Contacts" : "Contact"}
</Text>
</Flex>
);
};
export default Header;
/tests/components/Header.test.jsx
describe("Count Tests", () => {
it("Check text is plural or not", () => {
render(<Header total={256} />);
const totalElement = screen.getByTestId("total-id");
expect(totalElement.textContent).toBe("256 Contacts");
});
it("Check text is singular or not", () => {
render(<Header total={1} />);
const totalElement = screen.getByTestId("total-id");
expect(totalElement.textContent).toBe("1 Contact");
});
});
getByText method: This method is used to retrieve elements from DOM with text. It throws an error if it doesn’t find any element or find more than 1 element.
getByTestId method: This method is used to get elements by test ID provided to elements in a React application. You need to add ‘data-testid’
props in relevant React Components.
Fire Events
‘fireEvent'
, which can be imported from ‘@testing-library/react'
, helps to fire any kind of event from the test code. Click event, Scroll event, Change event, Drag/Drop event, Touch event, and so on. https://github.com/testing-library/dom-testing-library/blob/main/src/event-map.js has a list of all the supported events.
Testing Home Page component
Now, let’s test the Home Page component in the project by writing the following code in /tests/pages/Home.test.jsx
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import "@testing-library/jest-dom";
import Home from "../../pages/Home";
describe("Example of fire Events", () => {
it("check if button is visible on screen", () => {
render(<Home />);
const buttonElement = screen.getByRole("button");
expect(buttonElement).toBeVisible();
});
it("click on button", async () => {
render(<Home />);
const buttonElement = screen.getByRole("button");
fireEvent.click(buttonElement);
await waitFor(() => {
expect(buttonElement).not.toBeVisible();
});
});
});
getByRole Method: The getByRole
method queries the DOM and looks for elements with roles. Roles are the valid HTML tags such as <button>
, Headings like <h1>
, <h2>
..., <h6>
, Anchor link <a>
, <input>
, Paragraph <p>
etc.
toBeVisible Assertion: This allows you to check if an element is currently visible to the user.
An element is visible to a user if all the following conditions are met:
Assertion Methods
toBeInTheDocument()
: This assertion method matches the expected element node in the DOM.
expect(element).toBeInTheDocument();
toBe()
: This assertion method checks if the text content of the expected element is the string given in the toBe method (hello in this case).
expect(element.textContent).toBe('hello');
toHaveLength()
: This matcher assertion verifies if the expected sequence (array) has the length specified in the toHaveLength method (that is 7 here).
expect(myArr).toHaveLength(7);
Other such methods are:
toBeDisabled()
toBeEnabled()
toBeEmpty()
toBeEmptyDOMElement()
toBeInvalid()
toBeRequired()
toBeValid()
toBeChecked()
toBePartiallyChecked()
toHaveAttribute()
toHaveClass()
toHaveFocus()
toHaveFormValues()
toHaveStyle()
toHaveTextContent()
toHaveValue()
toHaveDisplayValue()
toHaveDescription()
toContainElement()
toContainHTML()
Conclusion
So, from the recent learning about React Testing Library, it is pretty clear that React Testing Library is the relieving solution for all the tough procedures we had to go through when dealing with the component functionalities along with its implementation details. Moreover, by learning about the various methods, it seems that RTL is very simple and straightforward to use. So, with all these features and the utilities, who wouldn’t like to use the RTL! Lastly, there is a cheat sheet available for the same at https://testing-library.com/docs/react-testing-library/cheatsheet/. Enjoy coding and testing!
Follow us@ordinarycoders