DEV Community

Aditya Chukka
Aditya Chukka

Posted on • Updated on

Testing React app with Jest

Alt Text

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
Enter fullscreen mode Exit fullscreen mode

Now install the react testing library

npm install --save-dev @testing-library/react
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Writing Tests

Running npm start on todolist should open a window as shown below

3_app_with_todo_list

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"
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

Our AddItem component takes a function addItem to save/store the submitted item. Let's mock it for testing purposes.

const empty = () => "";
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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();
});
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
barlew profile image
Bartosz Lewandowski

forgot to remove ' in "npm install --save-dev @testing-library/jest-dom`"

Collapse
 
achukka profile image
Aditya Chukka

Thanks Bartosz. (Haven't been active for a while here)