みかづきブログ・カスタム

基本的にはちょちょいのほいです。

Next.jsにJestを導入してテストを書く 💯

Nuxt.jsではJestを使ったテストを作成していたのですが、Next.jsに導入したことがなかったので導入方法を調べました。
Next.jsのドキュメントにJestの導入方法がまとまっていたのでここを参考にしました。

nextjs.org

ライブラリの導入

yarn add -D jest @testing-library/react @testing-library/jest-dom react-test-renderer @types/react-test-renderer

必要なライブラリを導入します。
ドキュメントには記載がないですが、react-test-rendererも導入しました。

ja.reactjs.org

jest.config.jsの作成

jest.config.js

const nextJest = require('next/jest');

const createJestConfig = nextJest({
  dir: './',
});

const customJestConfig = {
  moduleDirectories: ['node_modules', '<rootDir>/'],
  testEnvironment: 'jest-environment-jsdom',
};

module.exports = createJestConfig(customJestConfig);

プロジェクトのルートにjest.config.jsを作成します。

テストの作成

Btn.tsx

export default function Btn({ label = '', onClick = function () {} }) {
  return (
    <div onClick={ onClick } className="btn">
      <span>{ label }</span>
    </div>
  );
};

試しにこんな感じのボタンのテストを書いてみました。

Btn.text.ts

import { cleanup, fireEvent, render } from '@testing-library/react';
import renderer, { ReactTestRendererJSON } from 'react-test-renderer';
import Btn from '~/components/atoms/Btn';

afterEach(cleanup);

test('Btn', () => {
  const { toJSON } = renderer.create(<Btn />);
  const tree = toJSON() as ReactTestRendererJSON;

  expect(tree).toMatchSnapshot(); // DOM構造に変更がないことを確認
  expect(/btn/.test(tree.props.className)).toBe(true); // クラスが.btnであることを確認
});

test('label', () => {
  const label = 'label';
  const { getByText } = render(<Btn label={label} />);

  expect(getByText(new RegExp(label))).toBeTruthy(); // ラベルがpropsと一致することを確認
});

test('click', () => {
  const onClick = jest.fn();
  const { getByText } = render(<Btn onClick={onClick} label="label" />);

  fireEvent.click(getByText(/label/i));

  expect(onClick).toHaveBeenCalledTimes(1); // クリックイベントが呼び出されたことを確認
});

DOM構造の確認、クラスの確認、propsで渡したlabelの確認、コールバックイベントが発火するかの確認をするとこんな感じになると思います。