「Next.jsにJestを入れたら、設定エラーの解決だけで半日溶けた」——これ、フロントエンド初学者の通過儀礼になりがちです。ネット上の記事の多くがPages Router時代の古い設定のままで、コピペするとApp Routerでは動かないからです。

先に結論です。Next.jsのJest設定は、公式のnext/jestを使えば設定ファイル十数行で完了します。ts-jestもBabelも不要です。この記事では2026年7月時点の最新環境(Next.js 16 / React 19 / Jest 30)で、実際に動くテストを書くところまでを一気に解説します。

私は現役のフロントエンドエンジニアとして、レビューで「テストが書けるかどうか」が単価や評価を分ける場面を何度も見てきました。これからNext.jsでテストを始める人は、この記事の手順どおりに進めれば最短で環境が整います。

この記事でわかること
・Next.js 16(App Router)でのJestの正しい設定手順
・ts-jestが不要な理由と、古い記事の設定が動かない理由
・コピペで動くテスト例3つ(表示・クリック・ルーターのモック)
・Server Componentのテストの現実解と、Vitestという選択肢

独学に限界を感じたら

プログラミング教室がおすすめ。挫折せず最短で実力を伸ばせます。

PR

結論:next/jestだけでいい(ts-jestは入れない)

Next.jsにはJest用の公式設定ラッパーnext/jestが同梱されています。これを使うと、以下を全部自動でやってくれます。

  • TypeScript/JSXの変換(Next.jsコンパイラ=SWCが担当)
  • CSS・CSS Modules・画像・next/fontの自動モック
  • .env系ファイルの読み込み
  • node_modules.nextのテスト対象からの除外

ここで初心者がハマる最大のポイントを言います。古い解説記事にある「next/jestpreset: "ts-jest"」の併記は矛盾した設定です。next/jestはSWCでTypeScriptを変換するため、ts-jestを重ねると変換が二重になり、動いたとしても遅くなるだけ。かつての本記事もこの構成を紹介していましたが、2026年の正解は「ts-jestを入れない」です。

今回の環境(2026年7月時点)

  • Next.js 16(App Router / Turbopackがデフォルト)
  • React 19
  • Jest 30(2025年6月リリース。jsdom 26に更新され、実行速度とメモリ効率が大きく改善)
  • TypeScript 5系 / Node.js 20以上

Next.js 16ではビルドがTurbopackになりましたが、Jestはビルドとは別レイヤーで動くため、next/jestの設定はこれまでどおり使えます。Next.js 16の変更点全体はNext.js 16移行ガイドにまとめています。

セットアップ手順(4ステップ)

Step1:プロジェクトを作成する

npx create-next-app@latest my-app --typescript

いくつか質問されますが、基本はデフォルトのままEnterでOKです(App Routerが標準で選ばれます)。すでにApp Routerのプロジェクトがある人はこのステップは飛ばしてください。

create-next-appの質問プロンプトの例

※画面はイメージです。バージョンによって質問項目は多少変わります。

Step2:Jestと関連パッケージをインストールする

npm install -D jest jest-environment-jsdom @testing-library/react @testing-library/dom @testing-library/jest-dom ts-node @types/jest

それぞれの役割を一言で説明すると、jest-environment-jsdomはブラウザ環境の再現、@testing-library/reactはコンポーネントの描画と操作、@testing-library/jest-domは「画面に存在するか」等の便利なマッチャー追加、ts-nodeは設定ファイルをTypeScriptで書くために必要です。

ts-jestはリストにありません。それで正しいです。

Step3:jest.config.ts と jest.setup.ts を作成する

プロジェクトルートにjest.config.tsを作成します。これが公式ドキュメント準拠の最小構成です。

import type { Config } from "jest";
import nextJest from "next/jest.js";

const createJestConfig = nextJest({
  // next.config.jsと.envを読み込むため、Next.jsアプリのパスを指定
  dir: "./",
});

const config: Config = {
  coverageProvider: "v8",
  testEnvironment: "jsdom",
  setupFilesAfterEnv: ["<rootDir>/jest.setup.ts"],
  moduleNameMapper: {
    // tsconfig.jsonの paths(@/*)に合わせる
    "^@/(.*)$": "<rootDir>/src/$1",
  },
};

// next/jestが非同期のNext.js設定を読み込めるよう、この形でexportする
export default createJestConfig(config);

続いて、全テストの前に共通で読み込まれるjest.setup.tsをルートに作成します。

import "@testing-library/jest-dom";

これで.toBeInTheDocument()などのマッチャーが全テストで使えるようになり、テストファイルごとにimportを書く必要がなくなります。

moduleNameMappertsconfig.jsonのpathsと食い違うと「モジュールが見つからない」エラーの原因になるので、srcディレクトリを使っていない構成の人は<rootDir>/$1に読み替えてください。

Step4:package.jsonにtestスクリプトを追加する

{
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test": "jest",
    "test:watch": "jest --watch"
  }
}

開発中はnpm run test:watchが便利です。ファイルを保存するたびに関連テストだけが自動で再実行されます。

動くテスト例3つ(コピペOK)

例1:ページが正しく表示されるかのテスト

まずは一番シンプルな「見出しが表示されるか」のテストです。App Routerのトップページを対象にします。

export default function Page() {
  return (
    <main>
      <h1>Hello Next</h1>
    </main>
  );
}
import { render, screen } from "@testing-library/react";
import Page from "@/app/page";

describe("Page", () => {
  it("「Hello Next」という見出しが表示される", () => {
    render(<Page />);
    const heading = screen.getByRole("heading", { level: 1 });
    expect(heading).toHaveTextContent("Hello Next");
  });
});

テスト駆動の感覚を掴むため、まずはpage.tsxの文言をわざと変えてnpm run testを実行してみてください。期待どおり失敗することを確認するのが大事です。

Jestのテストが失敗したときの出力例

文言を戻して再実行し、緑のPASSが出れば環境構築は完了です。

Jestのテストが成功したときの出力例

例2:クライアントコンポーネントのクリック操作をテストする

実務のテストの主戦場はここです。useStateを使ったカウンターを例にします。

"use client";

import { useState } from "react";

export default function Counter() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount((c) => c + 1)}>count is {count}</button>
  );
}
import { render, screen, fireEvent } from "@testing-library/react";
import Counter from "@/components/Counter";

describe("Counter", () => {
  it("2回クリックするとcountが2になる", () => {
    render(<Counter />);
    const button = screen.getByRole("button");
    fireEvent.click(button);
    fireEvent.click(button);
    expect(button).toHaveTextContent("count is 2");
  });
});

"use client"が付いたコンポーネントは、Jest上ではただのReactコンポーネントとして動きます。特別な設定は不要です。より実際のユーザー操作に近づけたい場合は@testing-library/user-eventを追加で入れると、キーボード入力なども再現できます。

例3:useRouterをモックして画面遷移をテストする

App RouterのuseRouternext/navigation)を含むコンポーネントは、そのままrenderするとエラーになります。next/navigationをモック(偽物に差し替え)するのが定番の対処です。

import { render, screen, fireEvent } from "@testing-library/react";
import LoginButton from "@/components/LoginButton";

const push = jest.fn();
jest.mock("next/navigation", () => ({
  useRouter: () => ({ push }),
}));

describe("LoginButton", () => {
  it("クリックすると/loginへ遷移する", () => {
    render(<LoginButton />);
    fireEvent.click(screen.getByRole("button"));
    expect(push).toHaveBeenCalledWith("/login");
  });
});

現場でよくあるのは、このnext/navigationのモック、next/imageまわり、fetchのモックの3点セットで詰まるパターンです。逆に言えば、この3つの型を覚えればApp Routerのコンポーネントテストの大半は書けます。

Reactコンポーネント単体のテストの考え方(クエリの優先順位など)はReact+Jest入門で詳しく解説しています。

App Routerのテストで知っておくべき注意点

asyncなServer ComponentはJestでテストできない

意外に知られていない事実ですが、async関数として定義したServer Componentは、2026年現在もJest・Vitestともに公式サポート外です。Next.jsの公式ドキュメントも、async Server ComponentにはE2Eテスト(Playwrightなど)を推奨しています。

では実務ではどうするか。私が現場で採用している現実解は次の3つです。

  1. ユニットテストはクライアントコンポーネント中心に書く(同期的なServer Componentは通常どおりテスト可能)
  2. データ取得や整形ロジックは純粋な関数に切り出してテストする(コンポーネントから分離すればasyncでも普通にテストできる)
  3. asyncなServer Componentを通した結合部分はE2Eテストに任せる

「Server Componentがテストできないならテスト自体を諦める」のは典型的な失敗例です。テスト可能な形にロジックを寄せる設計は、そのままコンポーネント設計の質も上げてくれます。ディレクトリ構成から整えたい人はNext.jsのディレクトリ設計も参考にしてください。

Vitestという選択肢もある(比較表)

2026年現在、新規プロジェクトではJestではなくVitestを選ぶチームも増えています。Next.js公式もJest・Vitest両方のセットアップガイドを提供しており、どちらも「公式に認められた選択肢」です。

項目Jest 30Vitest
Next.js公式ガイドあり(next/jest)あり
導入のしやすさnext/jestでほぼ自動vite系プラグインの設定が必要
実行速度v30で大幅改善ESMネイティブで高速
ESM対応変換を挟むネイティブ対応
実務での採用実績・情報量圧倒的に多い急速に増加中
async Server Component非対応非対応

プロのコツとしては、既存プロジェクトや転職市場対策ならJest、ESM前提の新規プロジェクトならVitestという選び方が無難です。

Testing Libraryの書き方はどちらでもほぼ共通なので、片方を覚えればもう片方への移行コストは小さいです。求人票で今なお圧倒的に多く名指しされるのはJestなので、初学者はまずJestからで損しません。

まとめ:テストが書けるNext.jsエンジニアは強い

  • Next.js 16のJest設定はnext/jest一択。ts-jestは不要(併記は二重変換の矛盾設定)
  • 手順は「インストール → jest.config.ts → jest.setup.ts → testスクリプト」の4ステップ
  • ユニットテストはクライアントコンポーネントと純関数中心、asyncなServer ComponentはE2Eで
  • 新規プロジェクトならVitestも有力。書き方はほぼ共通なので迷いすぎない

テストは「書ける人が少ないのに、現場では確実に求められる」スキルです。私がレビューする側で見てきた限り、職務経歴書に「Jest/Testing Libraryでのテスト経験」と書けるだけで、書類の通過率も現場での信頼も明確に変わります。

独学でここまで到達できたなら、あとは実務経験を積む段階です。テストが書けるスキルを武器に、転職エージェントやフリーランスエージェントで「テスト文化のある現場」を条件に案件を探してみると、キャリアの伸びが一段速くなります。

次のステップとしては、React+Jestの基礎でテストの書き方の引き出しを増やすか、Next.js 16の変更点を押さえて土台を固めるのがおすすめです。

よくある質問(FAQ)

Q. ts-jestやBabelの設定は本当に不要ですか?

不要です。next/jestがNext.jsコンパイラ(SWC)でTypeScript/JSXを変換するため、ts-jestやbabel-jestを追加すると変換が二重になります。Babel構成が必要になるのは、プロジェクト自体がNext.jsコンパイラをオプトアウトしている特殊なケースだけです。

Q. テストファイルはどこに置くのが正解ですか?

ルートの__tests__ディレクトリにまとめる方式と、コンポーネントの隣にButton.test.tsxのように置くコロケーション方式のどちらでもOKです。App Routerではappディレクトリ内に置いてもルーティングと衝突しません。現場ではコロケーション方式が主流になりつつあります。

Q. JestとVitest、初心者はどちらを学ぶべきですか?

まずはJestをおすすめします。求人・案件で名指しされる頻度が高く、日本語情報も豊富だからです。テストの本体であるTesting Libraryの書き方は両者ほぼ共通なので、Jestで基礎を固めればVitestへは数時間で移行できます。基礎固めにはReact+Jest入門をどうぞ。

あわせて読みたい関連記事

Reactテスト入門|Vitestで始める2026年の新標準【Jest比較】CRA前提のJest入門はもう古い——2026年にReactのテストを始めるなら「Vite + Vitest + React Testing Library」がほぼ設定ゼロの新標準です。レンダリング・クリック・非同期の動くテストコード3例と、Jestからの移行が簡単な理由まで現役エンジニアが解説します。frontendlab.magicgifted.com Next.js 16移行ガイド|破壊的変更と新機能まとめ【2026】Turbopackが標準に、middlewareはproxyへ、paramsの同期アクセスは完全廃止——Next.js 16の破壊的変更と新機能を公式アップグレードガイドに沿って整理。codemodで自動化できる部分と手作業が必要な部分を切り分け、コピペで使える移行手順を解説します。frontendlab.magicgifted.com Next.js ESLint・Prettier設定 完全ガイド【2026】Next.jsにESLintとPrettierを導入する手順を2026年の最新構成で解説。create-next-app標準のeslint-config-nextにPrettierを競合なく組み込み、保存時の自動整形、husky+lint-stagedのコミット前チェックまでコピペで設定します。frontendlab.magicgifted.com