React Testing Library Part 1

React Testing Library (RTL) is a UI-layer testing framework that helps us ensure that React components are rendering and behaving as expected.

The main advantages of RTL over other UI-layer testing frameworks are:

  • It is built explicitly for testing React components.
  • It allows us to test our components in a way that mimics real user interactions such as event clicks/hover etc.

The logic behind this is that a user will not care about the implementation details of a React component such as the component’s state, the props passed to it, etc. The user will only care about whether or not they are able to use the app.

//Component to be tested TodoList.js

const TodoList = () => {
  return (
    <div>
      <h1>Todo List</h1>
      <ul>
        <li>
          <label htmlFor="item1">Read all the Sunday newspapers</label>
          <input type="checkbox" id="item1" />
        </li>
        <li>
          <label htmlFor="item2">Mow the lawn</label>
          <input type="checkbox" id="item2" />
        </li>
        <li>
          <label htmlFor="item3">Wash the car</label>
          <input type="checkbox" id="item3" />
        </li>
      </ul>
    </div>
  );
};

export default TodoList;

 

The React Testing Library exposes two essential values render() and screen().

Render - This function is used to virtually render components by taking JSX as an argument.

Screen - This is a special object that represents the browser window.

 

//Component test file TodoList.test.js

import { render, screen } from "@testing-library/react";
// import todo component to be tested
import TodoList from "./components/TodoList";
// simulate user events such as click and hover
import userEvent from "@testing-library/user-event";
// import Jest library for assertions
import "@testing-library/jest-dom";

test("should mark the first checkbox as checked", () => {
  // virtually render the Todo list
  render(<TodoList />);

  // grab the todo item
  const todoItem = screen.getByLabelText("Read all the Sunday newspapers");

  // simulate a "click" on the todo completed checkbox
  userEvent.click(todoItem);

  // assert that the todo item checkbox was checked
  expect(todoItem).toBeChecked();
});

 

Queries - getByText(), getByRole()

The Screen object exposes a number of useful query methods. getByText and getByRole are two such methods.

import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";

const Button = () => {
  return (
    <button type="submit" disabled>
      Submit
    </button>
  );
};

test('A "Submit" button is rendered', () => {
  // Render the Button component
  render(<Button />);

  // Extract the <button>Submit</button> node
  const button = screen.getByText("Submit");

  // simple test example for brevity
  expect(button).toBeInDocument();
});

// Alternative button node query

test("extracts the button DOM node", () => {
  // Render the Button component
  render(<Button />);

  // Extract the <button>Submit</button> node
  const button = screen.getByRole("button");

  // simple test example for brevity
  expect(button).toBeInDocument();
});

 

The ability to query DOM nodes allows us to be able to test them with Jest assertions

 

import { render } from "@testing-library/react";
import "@testing-library/jest-dom";

const Button = () => {
  return (
    <button type="submit" disabled>
      Submit
    </button>
  );
};

test("should show the button as disabled", () => {
  // render Button component
  render(<Button />);

  // Extract <button>Submit</button> Node
  const button = screen.getByRole("button");

  // Assert button is disabled
  expect(button).toBeDisabled();
});

 

Part 2 - Asynchronous testing

In the 2nd part of this RTL series, we will focus on asynchronous testing and how to handle when nodes are added and removed from the DOM.

RTL part 2 - Asynchronous testing with React testing library »

Mikey Anson

💻 Software engineer. React enthusiast. Elm and Elixir curious 💻