レビュー待ち·難易度: 中級·更新: 2026-04-18

Jest で Next.js Route Handler をテストする

Request / Response オブジェクトを直接渡して Route Handler 関数をユニットテストする例。GET / POST それぞれのハッピーパスとエラーパスを検証する。

nextjstestingapijest

対応バージョン

nextjs 15react 19jest 29

前提環境

Next.js Route Handler の基本と Jest の基本的なテストの書き方を理解していること

概要

Route Handler 関数に new Request() を直接渡してレスポンスを検証するユニットテストパターン。E2E テストなしで GET / POST それぞれのハッピーパスとエラーパスを高速に確認できる。

インストール

npm install jest @types/jest ts-jest

実装

テスト対象の Route Handler

// app/api/users/route.ts
import { NextResponse } from "next/server";

type User = { id: number; name: string };

const users: User[] = [
  { id: 1, name: "山田太郎" },
  { id: 2, name: "田中花子" },
];

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const name = searchParams.get("name");

  const result = name
    ? users.filter((u) => u.name.includes(name))
    : users;

  return NextResponse.json(result);
}

export async function POST(request: Request) {
  let body: unknown;
  try {
    body = await request.json();
  } catch {
    return NextResponse.json({ error: "Invalid JSON" }, { status: 400 });
  }

  if (typeof (body as Record<string, unknown>).name !== "string") {
    return NextResponse.json({ error: "name is required" }, { status: 400 });
  }

  const newUser: User = { id: users.length + 1, name: (body as { name: string }).name };
  users.push(newUser);
  return NextResponse.json(newUser, { status: 201 });
}

GET ハンドラのテスト

// app/api/users/route.test.ts
import { GET, POST } from "./route";

describe("GET /api/users", () => {
  it("全ユーザーを返す", async () => {
    const request = new Request("http://localhost/api/users");
    const response = await GET(request);
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data).toHaveLength(2);
    expect(data[0]).toMatchObject({ id: 1, name: "山田太郎" });
  });

  it("name クエリで絞り込める", async () => {
    const request = new Request("http://localhost/api/users?name=山田");
    const response = await GET(request);
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data).toHaveLength(1);
    expect(data[0].name).toBe("山田太郎");
  });

  it("該当なしは空配列を返す", async () => {
    const request = new Request("http://localhost/api/users?name=存在しない");
    const response = await GET(request);
    const data = await response.json();

    expect(response.status).toBe(200);
    expect(data).toHaveLength(0);
  });
});

POST ハンドラのテスト

describe("POST /api/users", () => {
  it("正常に作成できる", async () => {
    const request = new Request("http://localhost/api/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: "鈴木一郎" }),
    });
    const response = await POST(request);
    const data = await response.json();

    expect(response.status).toBe(201);
    expect(data).toMatchObject({ name: "鈴木一郎" });
    expect(typeof data.id).toBe("number");
  });

  it("name がない場合は 400 を返す", async () => {
    const request = new Request("http://localhost/api/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email: "test@example.com" }),
    });
    const response = await POST(request);
    const data = await response.json();

    expect(response.status).toBe(400);
    expect(data.error).toBe("name is required");
  });

  it("不正な JSON は 400 を返す", async () => {
    const request = new Request("http://localhost/api/users", {
      method: "POST",
      body: "invalid json",
    });
    const response = await POST(request);

    expect(response.status).toBe(400);
  });
});

ポイント

  • Route Handler はただの非同期関数((request: Request) => Promise<Response>)なので、new Request() を直接渡してテストできる。サーバーを起動する必要がない
  • new Request(url, { method, headers, body }) で任意のリクエストを組み立てられる。クエリパラメータは URL 文字列に含めて渡す
  • response.json() でレスポンスボディをデシリアライズし、response.status でステータスコードを検証する
  • jest-mock-module との使い分け: Route Handler が外部モジュール(DB・メール送信等)に依存している場合は jest.mock() と組み合わせる。このパターンはインメモリロジックのハンドラに適している
  • Prisma など外部依存がある場合は jest.mock("@prisma/client") でモックしてから同じパターンで使える

注意点

jest-mock-module はモジュールを差し替えてコンポーネントをテストするパターン。これは Route Handler 関数に Request オブジェクトを直接渡してレスポンスを検証するサーバー側ユニットテスト。

関連サンプル