4.1.1: Frontend React Testing

Learning Objectives

  1. Understand that we can test React Components on our Frontend Application

  2. Gain some insight in how to use React Testing Library to test our code

  3. Implement programatic tests on a React Component

Introduction

React Testing Library is the suggested testing library for testing React Applications and Components. It contains a set of utilities and API's that enable developers to write tests which simulate user behaviour and interaction with their React Components. Developers can then assert and check if the expected behaviour is executed.

Lets try to develop a high-level understanding of how React Testing Library operates:

  1. Rendering the Component:

    1. Firstly we will need to render the Component that we want to test using React Testing Library's render() method. The render() method creates a virtual dom and mounts the component in memory, it will then return the object that contains references to the rendered element.

  2. Finding Elements:

    1. After you have rendered the component you are able to use the getBy*() or queryBy*() methods that can be extracted from the React Testing Library. These methods help developers to find specific elements rendered on the Component, they search for Component elements by targeting attributes such as text content or other characteristics.

  3. Simulate User Interactions:

    1. Once you have successfully selected your elements that your user will interact with you are able to simulate user interactions by calling the fireEvent() method, which comes from React Testing Library. We are able to trigger all types of events such as clicks, form submissions and key presses.

  4. Assert Results:

    1. To actually check if your components are working in the correct manner, we are able to utilise the expect() function from Vitest in this case. With this function we can make assertions concerning the behaviour of the tested Component. We are able to check if the specific element is present, if an event has occurred or if a components state has been updated.

We are able to leverage React Testing Library such that we can test out Components as a user would interact with our application.

Setup

Fork and clone Rocket's testing-react repo to follow along. We have implemented some simple tests within a React environment. Once you have cloned the repository onto your local machine install all of the dependencies with the command

npm install

Following this you will be able to run React tests by running the command below within the root of the project directory.

npm test

Testing React Components

React applications created with the create-react-app contain a basic test that validates the boiler plate code that is provided, it just ensure that the App component loads an contains some text, learn react. We have left this test inside Rocket's testing-react repo.

When developing Frontend applications it is useful to test your component to ensure that your application is rendering the appropriate components, to test if data API's are called onload, or event to check if buttons are firing off the correct functions. To do all of this we can use React Testing Library, it provides a set of utilities that enable developers to test React Components. With this library we are able to simulate how users interact with the application meaning, we are able to write tests that follow user behaviour. These tests ensure that our Components are working as expected within our application.

Here's an example of how to test a button click and the actions that occur after:

Button.test.js
import { describe, expect, test } from "vitest";
import { screen, render, fireEvent } from "@testing-library/react";
import Button from "../Components/Button";

describe("Button", async () => {
  test("should call onClick when clicked", async () => {
    render(<Button />);

    const button = screen.getByText("Click me");

    expect(screen.getByText("Please click")).toBeInTheDocument();

    await fireEvent.click(button);

    expect(screen.queryByText("Please click above")).not.toBeInTheDocument();

    expect(screen.getByText("Clicked = 1")).toBeInTheDocument();
  });
});

In the example above we are testing the Button Component that has an onClick property. The test makes use of the render method from React Testing Library, it is used to render the Component. We then select the button with the getByText utility function. We are able to check if the correct text is showing on load, by checking if "Please click above" is being rendered. We then use the fireEvent.click() method from React Testing Library to simulate a clickEvent, on our rendered Component. This allows us to check the outcome of the click event, in this case, the removal of the string 'Please click above' that is replaced with "Clicked = 1" which is the current count.

It should be noted that if your Button Component triggers an action after the click, like calling an API, we are able to apply additional assertions to test that the additional triggers were fired off as expected. You can see how we can achieve this below.

ButtonComplex.test.js
import { describe, expect, test, vi } from "vitest";
import { render, fireEvent, screen } from "@testing-library/react";
import Button from "../Components/ComplexButton";
import axios from "axios";

vi.mock("axios");

describe("Button", () => {

  test("should call onClick and fetch data when clicked", async () => {
  
    render(<Button />);
    
    const button = screen.getByText("Click me");
    
    fireEvent.click(button);
    
    expect(axios.get).toHaveBeenCalledTimes(1);
    
    expect(axios.get).toBeCalledWith(
      "https://pokeapi.co/api/v2/pokemon/geodude"
    );
  });
});

In the above example we are testing if Button Component fire's off an API call. To test if our code is actually calling an API we have to import the axios library and mock it using the vi.mock() function. Next we render out our Button Component, we use the getByText method to find the Button so that we can fire off a click event, using fireEvent.click(). We can then assert that the mocked axios.get() has been called using Jest's toHaveBeenCalledTimes moreover we can test that it has been invoked along with its expected argument.

When we want to test if an API has been called following a click event witin React Testing Library, we will need to mock the API library, in the case above axios. We can then assert that the method has been called with the correct arguments and is actually invoked. This approach means that you can test the functionality of the component without making the API call during tests.

Additional Help

If you would like to explore React Testing Library some more, checkout this video series!

Last updated