Test React Custom Hooks with Jest and Testing Library

Test React Custom Hooks with Jest and Testing Library

  • Post Author:

Prerequisite Installation

Assume that we already installed Jest, Testing Library and SWR.

Custom Hook

If you don’t know what is the custom hooks we recommend you to read the official document about custom hooks.

Before we write the test we should have a custom hook first.

We create a custom hook useIndex to fetch the data from API as follow:

import useSWR from 'swr';

const fetcher = (url) => fetch(url).then((res) => res.json());

export const useIndex = () => {
  const { data, error } = useSWR(
    'https://api.github.com/repos/vercel/swr',
    fetcher
  );

  return {
    data,
    error,
  };
};

Then we use useIndex as follow:

import React from 'react';

import { useIndex } from './hook';

export default function Index() {
  const { data, error } = useIndex();

  if (error) return 'An error has occurred.';

  if (!data) return 'Loading...';

  return (
    <>
      <h1>{data.name}</h1>
      <strong>{data.subscribers_count}</strong>{' '}
      <strong>{data.stargazers_count}</strong>{' '}
      <strong>{data.forks_count}</strong>
    </>
  );
}

Test Custom Hook

Beforehand

There are one property and one function we need to know in Jest:

  • jest.mock – used to spied on the behavior of a function.
  • mockImplementation – used as the implementation of the mock.

There is one function we need to know in Testing Library:

  • render – used to render the component virtually.

Case 1

The first case is that we want to check “Loading…” is displayed when undefined data is returned from the API.

import '@testing-library/jest-dom';
import '@testing-library/jest-dom/extend-expect';

import { jest, test } from '@jest/globals';
import { render } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';

import { useIndex } from './hook';
import IndexPage from './index';

jest.mock('./hook', () => ({
  useIndex: jest.fn(() => ({
    data: {},
    error: undefined,
  })),
}));

test('Assert "Loading..." is displayed when undefined data is returned from the API', () => {
  (useIndex as any).mockImplementation(() => ({
    data: undefined,
    error: undefined,
  }));

  const { getByText } = render(
    <BrowserRouter>
      <Page />
    </BrowserRouter>,
  );

  expect(getByText('Loading...')).toBeInTheDocument();
});

Case 2

The second case is that we want to check “An error has occurred.” is displayed when an error is returned from the API.

import '@testing-library/jest-dom';
import '@testing-library/jest-dom/extend-expect';

import { jest, test } from '@jest/globals';
import { render } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';

import { useIndex } from './hook';
import IndexPage from './index';

jest.mock('./hook', () => ({
  useIndex: jest.fn(() => ({
    data: {},
    error: undefined,
  })),
}));

test('Assert "An error has occurred." is displayed when an error is returned from the API', () => {
  (useIndex as any).mockImplementation(() => ({
    data: {},
    loadingError: { response: { status: 500 } },
  }));

  const { getByText } = render(
    <BrowserRouter>
      <Page />
    </BrowserRouter>,
  );

  expect(
    getByText('An error has occurred.'),
  ).toBeInTheDocument();
});

Case 3

And the third case is that we want to check data is displayed when there is no error.

import '@testing-library/jest-dom';
import '@testing-library/jest-dom/extend-expect';

import { jest, test } from '@jest/globals';
import { render } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';

import { useIndex } from './hook';
import IndexPage from './index';

jest.mock('./hook', () => ({
  useIndex: jest.fn(() => ({
    data: {},
    error: undefined,
  })),
}));

test('Assert data is displayed when there is no error', () => {
  (useIndex as any).mockImplementation(() => ({
    data: {
      id: 218115303,
      name: 'swr',
      description: 'React Hooks for Data Fetching',
      full_name: 'vercel/swr',
      owner: {
        id: 14985020,
        login: 'vercel'
      }
    },
    loadingError: undefined,
  }));

  const { getByText } = render(
    <BrowserRouter>
      <Page />
    </BrowserRouter>,
  );

  expect(getByText('swr')).toBeInTheDocument();
});
we are hiring

優秀な技術者と一緒に、好きな場所で働きませんか

株式会社もばらぶでは、優秀で意欲に溢れる方を常に求めています。働く場所は自由、働く時間も柔軟に選択可能です。

現在、以下の職種を募集中です。ご興味のある方は、リンク先をご参照下さい。

コメントを残す