😃

Next.jsでJestをセットアップしよう!

に公開

コードの信頼性を高める上でテストは不可欠なものです。フロントエンド開発においてもこの重要性は変わりません。しかし、テスト環境のセットアップはちょっとした壁かもしれません。

そこで今回は Next.js で Jest をセットアップする手順を紹介します。

前提

$ sw_vers
ProductName:		macOS
ProductVersion:		13.0

$ node -v
v20.11.0

$ pnpm -v
8.15.1

$ pnpm next -v
Next.js v14.1.0

セットアップ

1. テスト用アプリケーションの作成

テスト対象の Next.js アプリケーションを作ります。

$ pnpm create next-app
../Library/pnpm/store/v3/tmp/dlx-18079   | Progress: resolved 1, reused 0, downl../Library/pnpm/store/v3/tmp/dlx-18079   |   +1 +
../Library/pnpm/store/v3/tmp/dlx-18079   | Progress: resolved 1, reused 0, downl../Library/pnpm/store/v3/tmp/dlx-18079   | Progress: resolved 1, reused 1, downloaded 0, added 1, done
 What is your project named? test-example
 Would you like to use TypeScript? Yes
 Would you like to use ESLint? No
 Would you like to use Tailwind CSS? No
 Would you like to use `src/` directory? Yes
 Would you like to use App Router? (recommended) … Yes
 Would you like to customize the default import alias (@/*)? … No
Creating a new Next.js app in /Users/nabe/work/test-example.

Using pnpm.

Initializing project with template: app


Installing dependencies:
- react
- react-dom
- next

Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom

Packages: +28
++++++++++++++++++++++++++++
Progress: resolved 36, reused 28, downloaded 0, added 28, done

dependencies:
+ next 14.1.0
+ react 18.2.0
+ react-dom 18.2.0

devDependencies:
+ @types/node 20.11.20
+ @types/react 18.2.58
+ @types/react-dom 18.2.19
+ typescript 5.3.3

Done in 2.9s
Initialized a git repository.

Success! Created test-example at /Users/nabe/work/test-example

2. パッケージのインストール

UI コンポーネントのテストに必要なパッケージをインストールします。

pnpm install -D jest \
@types/jest \
jest-environment-jsdom \
@testing-library/react \
@testing-library/jest-dom \
@testing-library/user-event

Jest 以外の各パッケージの役割は以下の通りです。

パッケージ 役割
@types/jest expect や test などの型を import 無しで参照できるようにする
jest-environment-jsdom テストの実行環境で DOM API シミュレートする
@testing-library/react レンダリングなどReactコンポーネントをテストするための機能を提供する
@testing-library/jest-dom UI コンポーネントの検証に便利な機能を Jest に追加する
@testing-library/user-event ユーザー操作をシミュレートする
package.json
{
  "name": "test-example",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "test": "jest"
  },
  "dependencies": {
    "next": "14.1.0",
    "react": "^18",
    "react-dom": "^18"
  },
  "devDependencies": {
    "@testing-library/jest-dom": "^6.4.2",
    "@testing-library/react": "^14.2.1",
    "@testing-library/user-event": "^14.5.2",
    "@types/jest": "^29.5.12",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "typescript": "^5"
  }
}

3. 設定ファイルの生成

基本的な Jest 設定ファイルを生成します。
後で Next.js で動作するために必要なオプションをここに追加します。

pnpm create jest@latest
.../Library/pnpm/store/v3/tmp/dlx-14502  | +237 ++++++++++++++++++++++++
.../Library/pnpm/store/v3/tmp/dlx-14502  | Progress: resolved 237, reused 237, downloaded 0, added 237, done

The following questions will help Jest to create a suitable configuration for your project

 Would you like to use Jest when running "test" script in "package.json"? yes
 Would you like to use Typescript for the configuration file? no
 Choose the test environment that will be used for testing jsdom (browser-like)
 Do you want Jest to add coverage reports? yes
 Which provider should be used to instrument code for coverage? babel
 Automatically clear mock calls, instances, contexts and results before every test? yes

✏️  Modified /Users/nabe/work/next-test-example2/package.json

📝  Configuration file created at /Users/nabe/work/next-test-example2/jest.config.js

4. セットアップファイルの作成

各テストファイルのコードを実行する前に、テスト環境に jest-dom をインポートしてUIコンポーネントの検証ができるようマッチャーを拡張します。
jest.config.jssetupFilesAfterEnv にこのファイルのパスを指定するとテストファイルごとにセットアップファイルのコードが1回実行されるようになります。パスの指定はこの後の手順で行います。

jest.setup.ts
import '@testing-library/jest-dom';

https://jestjs.io/ja/docs/configuration#setupfiles-array

5. 設定ファイルの編集

next/jest を使うように設定ファイルを更新します。
Jest が Next.js で動作するために必要なオプションが設定されます。

jest.config.js
/**
 * For a detailed explanation regarding each configuration property, visit:
 * https://jestjs.io/docs/configuration
 */

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

+ const createJestConfig = nextJest({
+   // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
+   dir: './',
+ });

/** @type {import('jest').Config} */
const config = {
  // ...
  // A list of paths to modules that run some code to configure or set up the testing framework before each test
+  setupFilesAfterEnv: ['./jest.setup.ts'],
-  // setupFilesAfterEnv: [],
  // ...
  // The test environment that will be used for testing
+  testEnvironment: 'jest-environment-jsdom',
-  testEnvironment: 'jsdom'
  // ...
}

+ module.exports = createJestConfig(config);
- module.exports = config;

https://nextjs.org/docs/app/building-your-application/testing/jest

動作確認

単純なコンポーネントを使って実際にテストしてみましょう。

テスト対象

src/components/Form.tsx
type Props = {
  name: string;
  onSubmit?: (event: React.FormEvent<HTMLFormElement>) => void;
};
export const Form = ({ name, onSubmit }: Props) => {
  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        onSubmit?.(event);
      }}
    >
      <h2>アカウント情報</h2>
      <p>{name}</p>
      <div>
        <button>編集する</button>
      </div>
    </form>
  );
};

テストコード

src/components/Form.test.tsx
import { fireEvent, render, screen } from '@testing-library/react';
import { Form } from './Form';

test('名前を表示すること', () => {
  render(<Form name="john" />);
  expect(screen.getByRole('button')).toBeInTheDocument();
});

test('ボタンをクリックすると、イベントハンドラーが呼ばれること', () => {
  const mockFn = jest.fn();
  render(<Form name="john" onSubmit={mockFn} />);
  fireEvent.click(screen.getByRole('button'));
  expect(mockFn).toHaveBeenCalled();
});

テスト結果

pnpm test

> test-example@0.1.0 test /Users/nabe/work/test-example
> jest

 PASS  src/components/Form.test.tsx
 名前を表示すること (29 ms)
 ボタンをクリックすると、イベントハンドラーが呼ばれること (8 ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |
 Form.tsx |     100 |      100 |     100 |     100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.619 s, estimated 1 s
Ran all test suites.

まとめ

この記事では、Next.jsでJestをセットアップする手順を紹介しました。

  1. テスト用の Next.js アプリケーションを作成し、必要なパッケージをインストールしました
  2. Jestの設定ファイルを生成し、Next.jsで動作するためのオプションを追加しました
  3. 単純なコンポーネントを使ってテストを実行し、成功したことを確認しました

Discussion