React Testing using Vitest and React Testing Libraries (Part III)

Sujan
by Sujan 

This is part two of our blog series on react testing. Read the first part here, and the second part here. In the third part of this series, I will showcase a mock HTTP request, and also provide some helpful tips.

Mocking HTTP Request

A front-end unit and integration test should not be dependent on the API, only end-to-end tests are dependent on API. As unit tests are run frequently it may not be feasible to hit the server several  times while testing. Also, in some cases APIs may not be available at the time of testing, and some APIs may even charge you for every hit count. The test should not fail when  APIs are unavailable and the frontend test should be independent from the backend. 

In these cases, we mock the HTTP requests in our test. For this, we use a library called mock service worker. It is an API mocking library that uses service worker API to intercept actual requests.

Component to call an API of (users)

import { useState, useEffect } from "react";
import axios from "axios";

const Users = () => {
  const [users, setUsers] = useState<string[]>([]);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    axios("<https://jsonplaceholder.typicode.com/users>")
      .then((res) => {
        return res.data;
      })
      .then((data) => setUsers(data.map((user: { name: string }) => user.name)))
      .catch((err) => setError("Error"));
  }, []);

  return (
    <div>
      <h1> Users </h1>

      {error && <p> {error} </p>}

      <ul>
        {users.map((user) => (
          <li key={user}> {user} </li>
        ))}
      </ul>
    </div>
  );
};

export default Users;

Here in the above user component, we display the list of users which are returned by jsonplaceholder API. Here the API returns a list of 10 users for the above request. Before we write the test code we must first initialize the mocker for the API, as we won’t be testing into the actual API.

Setup MSW

yarn add msw --dev
touch src/mocks/handlers.ts
// src/mocks/handlers.ts

import { rest } from "msw";

export const handlers = [
	
//adding API endpoint, with mock response
  rest.get("<https://jsonplaceholder.typicode.com/users>", (req, res, ctx) => {
    return res(
      ctx.status(200),
			// list only three users
			// Usually this would be the copy of an actual response
      ctx.json([
        { name: "Bruce Wayne" },
        { name: "Clark Kent" },
        { name: "Diana Prince" },
      ])
    );
  }),
];
// src/mocks/server.ts

import { setupServer } from "msw/node";
import { handlers } from "./handlers";

// This configures a request mocking server with the given request handlers.
export const server = setupServer(...handlers);

Here we add the MSW library to our project, after that we need to create a handler file inside the mock folder. In the handler file we write the code to intercept API response [More Info Here]. Now we need to set up the server for MSW, here we initialize the handlers into the setupServer  function provided by MSW. Our MSW has been set up , and now every time we call for an API while testing, It would be  intercepted by MSW. Thus now we don’t have to be dependent  on the backend  server for running our tests and writing out the test for API tests.

Test Code

import { render, screen } from "@testing-library/react";
import Users from "./Users";
import { server } from "../../mocks/server";
import { rest } from "msw";

describe("#Users", () => {
	// Test 1
  test("render a list of users", async () => {
    render(<Users />);
    const list = await screen.findAllByRole("listitem");
    expect(list).toHaveLength(3);
  });

	// Test 2
  test("Should render error message", async () => {
    // sabotage the server
    server.use(
      rest.get(
        "<https://jsonplaceholder.typicode.com/users>",
        (req, res, ctx) => {
          return res(ctx.status(500));
        }
      )
    );

    render(<Users />);

    const error = await screen.findByText("Error");

    expect(error).toBeInTheDocument();
  });
});

Explanation

Test 1, tests the number of items in the list in the User component. Here  we assert the list should have a list of 3 items, since we have only returned three users from our interception.

Test 2, is for testing the failure case. Here  before rendering the User component we have first sabotaged the server so that it throws an error of status code 500. Then we check for the error message in the UI, if the error message is found in the document, the test 2 passes.

Conclusion

Although, testing is regarded as a QAs job, it is equally a responsibility of developers too. Developers must test their codes on multiple levels, starting with the writing of the first unit test.

In the three part series, I tried to explain react testing with Vitest and react testing library.  Here’s a summary of what things were covered:

  • Introduction of the libraries
  • Setting up your first test
  • Writing your first test (with code explanation)
  • What to test?
  • User interaction
  • Testing hooks
  • Mocking HTTP request
  • Very useful tips

…………

Final Words

Gurzu is a full-cycle Software development company. Since 2014, we have built softwares for many startups and enterprises from all around the world using Agile methodology. Our team of experienced developers, designers, test automation engineers can help to develop your next product.

Read more about our services here. Have a tech idea you want to turn into reality? Book a free consulting call.

References

https://www.youtube.com/watch?v=T2sv8jXoP4s&list=PLC3y8-rFHvwirqe1KHFCHJ0RqNuN61SJd&index=1