In this post we will look into how to write tests for react application using Jest
Jest is open source testing framework built on top of JavaScript. It was majorly designed to work with React based web applications. However it can also be used on applications using Node, Angular, Vue etc.
We will be writing tests on todolist, a React application that I have created in my previous post
Step 1: Installing dependencies
If you have created your application using create-react-app you can skip this step
Install Jest using npm:
npm install --save-dev jest @types/jest
Now install the react testing library
npm install --save-dev @testing-library/react
We will also be using jest-dom library which provides a set of custom matchers on DOM
npm install --save-dev @testing-library/jest-dom
Add npm script to run tests in package.json
{
"scripts": {
...,
"tests": "react-scripts test"
}
...,
"devDependencies": {
"@testing-library/jest-dom": "^5.12.0",
"@testing-library/react": "^11.2.6",
"@types/jest": "^26.0.23",
"jest": "^26.6.3"
}
}
Step 2: Writing Tests
Running npm start
on todolist should open a window as shown below
As you can see we have 4 static labels on the screen.
-
Task: and Priority: on the top row (read the
:
) - Header row with Task and Priority columns
Create a file App.test.tsx
if it does not exist already.
Import render and screen from react-testing-library
import { render, screen } from "@testing-library/react"
As the name suggests render can be used to render any react component where as screen can be used to query for HTML elements.
React Testing Library docs provide a cheat sheet with a table of queries that can be used.
For this article we will use getByText
. This function returns the element that matches the string and throws an error if nothing matches.
1. Checking for Task
Label
test("Renders Task Label", () => {
render(<App />);
const linkElement = screen.getByText("Task:");
expect(linkElement).toBeInTheDocument();
});
This test checks if there is *exactly one * element with text Task:
in the rendered App.
2. Checking for Priority
Label
test("Renders Priority Label", () => {
render(<App />);
const linkElement = screen.getByText("Priority:");
expect(linkElement).toBeInTheDocument();
});
This test checks if there is *exactly one * element with text Priority:
in the rendered App.
3. Checking for Task
header column
test("Renders Table Header - Task Column", () => {
render(<App />);
const linkElement = screen.getByText("Task");
expect(linkElement).toBeInTheDocument();
});
This test checks if there is *exactly one * element with text Task
in the rendered App.
4. Checking for Priority
header column
test("Renders Table Header - Priority Column", () => {
render(<App />);
const linkElement = screen.getByText("Priority");
expect(linkElement).toBeInTheDocument();
});
This test checks if there is *exactly one * element with text Priority
in the rendered App.
5. Checking for First Row in the Table, Task Column
test("Renders Table - First Row Task", () => {
render(<App />);
const linkElement = screen.getByText("Pick up Milk");
expect(linkElement).toBeInTheDocument();
});
This test checks if there is *exactly one * element with text Pick up Milk
in the rendered App.
6. Checking for First Row in the Table, Priority Column
test("Renders Table - First Row Priority", () => {
render(<App />);
const linkElement = screen.getByText("1");
expect(linkElement).toBeInTheDocument();
});
This test checks if there is *exactly one * element with text 1
in the rendered App.
You can run the above tests by
npm test
Please refer to this commit for code.
Optional Section: Testing individual Components
In the above section we have only written tests for the App component. However we can extend similar tests to other components as well.
In this segment we will add tests to AddItem and ToDoList components.
1. Checking Input Form in AddItem
Import render, screen methods from react-testing-libary and AddItem component
import { render, screen } from "@testing-library/react";
import AddItem from "../src/AddItem";
Our AddItem component takes a function addItem
to save/store the submitted item. Let's mock it for testing purposes.
const empty = () => "";
Test whether the form is rendered correctly.
test("Renders Input Form", () => {
render(<AddItem addItem={empty} />);
const taskElement = screen.getByText("Task:");
expect(taskElement).toBeInTheDocument();
const priorityElement = screen.getByText("Priority:");
expect(priorityElement).toBeInTheDocument();
});
In this test, we check if we have elements Task:
and Priority:
in the rendered component
2. Checking Table in ToDoList
Import render, screen methods from react-testing-libary and ToDoList component
import { render, screen } from "@testing-library/react";
import ToDoList from "../src/ToDoList";
Since our ToDoList takes an array of items as props. We will split our tests into two scenarios
- Empty Array
- Non empty array
2.1 Checking Table with no items
The ToDoList component should render an div with text Empty List
when there are no items.
test("Renders Empty List div", () => {
render(<ToDoList items={[]} />);
const linkElement = screen.getByText("Empty List");
expect(linkElement).toBeInTheDocument();
});
This test should pass ✅ only if there is one element with text Empty List
.
2.2 Checking Table with items
The ToDoList component should render items in a tabular format if props has any items.
In this test we pass an item with task write test
and priority 1
.
test("Renders Table with dummy data", () => {
const items = [{ task: "write test", priority: 1 }];
render(<ToDoList items={items} />);
const taskHeaderElement = screen.getByText("Task");
expect(taskHeaderElement).toBeInTheDocument();
const priorityHeaderElement = screen.getByText("Priority");
expect(priorityHeaderElement).toBeInTheDocument();
const taskElement = screen.getByText("write test");
expect(taskElement).toBeInTheDocument();
const priorityElement = screen.getByText("1");
expect(priorityElement).toBeInTheDocument();
});
We check if the table has following
- Task Header Column
- Priority Header Column
- Task Column with value
write test
- Priority Column with value
1
In all the scenarios there should be exactly one matching element. Else the test should fail ❌
Thanks for reading through the entire article. Please reach out with questions, comments and/or feedback.
Top comments (2)
forgot to remove ' in "npm install --save-dev @testing-library/jest-dom`"
Thanks Bartosz. (Haven't been active for a while here)