Next.js 12 系以降の Jest セットアップ方法

## 前提

Next.js のユニットテスト自動化ツールとして、Jest を利用する。ここではそのセットアップ方法について記述する。

Next.js（TypeScript）の環境が用意できていない場合は、`npx create-next-app@latest --ts` コマンドで用意しておく。

なお、Next.js 12 系以降では Rust コンパイラーを利用した Jest の構成がデフォルトとなっているので、そちらの構成に従う。

## 必要なパッケージインストール

Jest で必要なパッケージをインストールする。

```bash
npm install --save-dev jest @testing-library/react @testing-library/jest-dom
```

## 設定ファイルの作成

Jest の設定ファイルである `jest.config.ts`をプロジェクトルートに作成し、以下のコードを記述する。

```js
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: "./src",
});

// Add any custom config to be passed to Jest
const customJestConfig = {
  setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
  // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
  moduleDirectories: ["node_modules", "<rootDir>/"],
  testEnvironment: "jest-environment-jsdom",
};

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
```

## スタイルシートと画像のモック作成

スタイルシートと画像はテストでは使用されないが、それらをインポートするとエラーが発生する可能性があるため、モックする必要がある。

以下のようにモックファイルを作成する。

- \_\_mocks\_\_/fileMock.ts

  ```ts
  export {};
  module.exports = "test-file-stub";
  ```

- \_\_mocks\_\_/styleMock.ts

  ```ts
  export {};
  module.exports = {};
  ```

## Jest の拡張（jest.config.ts ファイルの作成）

`@testing-library/jest-dom` テストの作成を容易にするなど、便利なカスタムマッチャーのセットが含まれているので、反映させるための`jest.config.ts`ファイルを作成する。

```ts
import "@testing-library/jest-dom/extend-expect";
```

> 各テストの前にセットアップオプションを追加する必要がある場合は、上記`jest.setup.js` のファイルに追加するのが一般的とのこと。

## Jest の実行

package.json に以下のテストスクリプトを追加する。

```json
"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start",
  "test": "jest --watch"  // ★追記
}
```

テストファイルは以下の例のように作成し、テストファイルは `src` 配下の `__tests__`ディレクトリ以下に作成していく。

- 例：`src/pages/__tests__/index.test.tsx`

  ```tsx
  // src/pages/__tests__/index.test.tsx
  import { render, screen } from "@testing-library/react";
  import Home from "../pages/index";

  describe("Home", () => {
    it("renders a heading", () => {
      render(<Home />);

      const heading = screen.getByRole("heading", {
        name: /welcome to next\.js!/i,
      });

      expect(heading).toBeInTheDocument();
    });
  });
  ```

必要に応じて、スナップショットを追加する。

- 例：`src/pages/__tests__/snapshot.tsx`

  ```tsx
  // src/pages/__tests__/snapshot.tsx
  import { render } from "@testing-library/react";
  import Home from "../pages/index";

  it("renders homepage unchanged", () => {
    const { container } = render(<Home />);
    expect(container).toMatchSnapshot();
  });
  ```

## 画像ファイルを扱う場合の設定

画像や CSS を `import` する際は、WebPack によって解決されている。

しかし Jest は WebPack の機能を持っていないため、画像や CSS がインポートされたときに JavaScript として読み込もうとしてもシンタックスエラーが発生する。

そのため、以下のように `jest.config.js` に設定を加え、画像ファイルと CSS をモック化する必要がある。

```js
module.exports = {
  "moduleNameMapper": {
    "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
    "\\.(css|scss)$": "<rootDir>/__mocks__/styleMock.js",
  },
}
``` 

> 参考：[【Jest】画像ファイルやCSSのインポートに失敗する場合の対処法 -- Qiita](https://qiita.com/Amsel/items/8a4859d06a8de551abf8)

## 参考サイト

- [Jest and React Testing Library -- Next.js 公式ドキュメント](https://nextjs.org/docs/testing#jest-and-react-testing-library)