Page テストが重いからコンポーネントを分けてテストする方針で、Jest と React Testing Library を入れた手順をまとめます。
環境
- Next.js 16.0.3
- React 19.2.0 / ReactDOM 19.2.0
- TypeScript 5.x
- ESLint (eslint-config-next を利用)
依存の追加
npm install --save-dev jest@29.7.0 jest-environment-jsdom@29.7.0 \
@testing-library/react@16 @testing-library/jest-dom@6 \
@types/jest@29
Jest 設定
next/jest は CommonJS 前提なので、jest.config.js を CJS で置きます。
jest.config.js
/* eslint-disable @typescript-eslint/no-require-imports */
// next/jest は CJS 想定のため require を使う
const nextJest = require("next/jest");
// Next.js の設定や env を Jest へ引き継ぐ
const createJestConfig = nextJest({ dir: "./" });
// jsdom で実行し、パスエイリアスも解決
const customJestConfig = {
testEnvironment: "jsdom",
setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
moduleNameMapper: {
"^@/(.*)$": "<rootDir>/$1",
},
};
module.exports = createJestConfig(customJestConfig);
カスタムマッチャを有効化するセットアップと型定義も用意
jest.setup.ts
// jest-dom のカスタムマッチャを有効化するために読み込む
import "@testing-library/jest-dom";
types / jest.d.ts
/// <reference types="jest" />
// Jest と jest-dom の型をまとめて読み込むための宣言ファイル
import "@testing-library/jest-dom";
package.json(例)
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint",
"test": "jest",
"test:ci": "jest --ci"
}
}
コンポーネントを分けてテストする
Page 直叩きではなく、見出しをコンポーネント化してテストします。
Title.tsx
type TitleProps = {
text: string;
};
export default function Title({ text }: TitleProps) {
// 見出し文言を受け取り、装飾付きで表示するだけのコンポーネント
return <h1 className="text-3xl font-bold underline">{text}</h1>;
}
page.tsxではこのコンポーネントを使うだけにします。
page.tsx
import Title from "./components/Title";
export default function Home() {
return (
<div>
{/* 見出しはコンポーネント化してテストしやすくする */}
<Title text="Hello world!" />
<button
className="inline-block cursor-pointer rounded-md bg-gray-800 px-4 py-3 text-center text-sm font-semibold uppercase text-white transition duration-200 ease-in-out hover:bg-gray-900"
>
Button
</button>
</div>
);
}
コンポーネントのテスト
__tests__/components/Title.test.tsx を作成。
Title.test.tsx
import { render, screen } from "@testing-library/react";
import Title from "@/app/components/Title";
describe("Title component", () => {
it("renders provided heading text", () => {
// 見出しコンポーネントが渡された文言を表示することを確認する
render(<Title text="Sample Heading" />);
expect(
screen.getByRole("heading", { name: "Sample Heading" }),
).toBeInTheDocument();
});
});
実行
npm test -- --runInBand
おわりに
-
公式ドキュメントを見る限り、
next/jestは CJS 前提っぽいなのでjest.config.jsは CJS で書く。 -
App Router では Page 全体のテストより、コンポーネントを分けて Testing Library で薄く当てると扱いやすい。
-
moduleNameMapperで@/エイリアスを解決しておくと import が楽。
参考