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

Playwright でページネーション付き一覧のページ遷移をE2Eテストする

一覧ページのページネーション操作(次へ・前へ・ページ番号クリック)を Playwright でE2Eテストし、URL クエリと表示件数の整合性を検証する例。

nextjstestingplaywright

対応バージョン

nextjs 15react 19playwright 1

前提環境

Playwright の基本的なテスト記述と Next.js App Router のページ構造を理解していること

概要

Playwright を使い、ページネーション付き一覧ページで「次へ」「前へ」「ページ番号クリック」を操作し、URL の page クエリパラメータと表示カード件数が正しく変わることをE2Eテストする。page.url()locator を組み合わせて URL 同期を検証するパターンを示す。

インストール

npm install -D @playwright/test
npx playwright install chromium

実装

基本的なページネーションフロー

// e2e/pagination.spec.ts
import { test, expect } from "@playwright/test";

const BASE_URL = "http://localhost:3000";
const PAGE_SIZE = 24;

test.describe("ページネーション", () => {
  test("1 ページ目: URL に page クエリがなく、カードが最大 PAGE_SIZE 件表示される", async ({ page }) => {
    await page.goto(`${BASE_URL}/samples`);

    // page クエリなし or page=1 を確認
    const url = new URL(page.url());
    expect(url.searchParams.get("page")).toBeNull();

    // カードが PAGE_SIZE 件以下
    const cards = page.locator("[data-testid='sample-card']");
    await expect(cards).toHaveCount(PAGE_SIZE);
  });

  test("「次のページ」をクリックすると page=2 になる", async ({ page }) => {
    await page.goto(`${BASE_URL}/samples`);

    await page.getByRole("link", { name: "次のページ" }).click();
    await page.waitForURL(/page=2/);

    const url = new URL(page.url());
    expect(url.searchParams.get("page")).toBe("2");
  });

  test("ページ番号をクリックすると該当ページに遷移する", async ({ page }) => {
    await page.goto(`${BASE_URL}/samples`);

    await page.getByRole("link", { name: "3", exact: true }).first().click();
    await page.waitForURL(/page=3/);

    const url = new URL(page.url());
    expect(url.searchParams.get("page")).toBe("3");
  });

  test("「前のページ」をクリックすると page が 1 つ戻る", async ({ page }) => {
    await page.goto(`${BASE_URL}/samples?page=3`);

    await page.getByRole("link", { name: "前のページ" }).click();
    await page.waitForURL(/page=2/);

    const url = new URL(page.url());
    expect(url.searchParams.get("page")).toBe("2");
  });

  test("1 ページ目では「前のページ」リンクが表示されない", async ({ page }) => {
    await page.goto(`${BASE_URL}/samples`);

    await expect(
      page.getByRole("link", { name: "前のページ" })
    ).not.toBeVisible();
  });
});

フィルタとページネーションの組み合わせ

test.describe("フィルタ × ページネーション", () => {
  test("フィルタ変更時に page がリセットされる", async ({ page }) => {
    // 2 ページ目でフィルタを変更
    await page.goto(`${BASE_URL}/samples?page=2`);

    // フレームワークフィルタを変更
    await page.getByRole("combobox", { name: "フレームワーク" }).selectOption("nextjs");
    await page.waitForURL((url) => !url.includes("page=2"));

    const url = new URL(page.url());
    expect(url.searchParams.get("page")).toBeNull();
  });

  test("フィルタを維持したままページ遷移できる", async ({ page }) => {
    await page.goto(`${BASE_URL}/samples?framework=nextjs`);

    await page.getByRole("link", { name: "次のページ" }).click();
    await page.waitForURL(/page=2/);

    const url = new URL(page.url());
    // フィルタが維持されていることを確認
    expect(url.searchParams.get("framework")).toBe("nextjs");
    expect(url.searchParams.get("page")).toBe("2");
  });
});

aria-current="page" でアクティブページを検証

test("現在のページ番号が aria-current='page' になっている", async ({ page }) => {
  await page.goto(`${BASE_URL}/samples?page=2`);

  const current = page.locator("[aria-current='page']");
  await expect(current).toHaveText("2");
});

Playwright の設定ファイル

// playwright.config.ts
import { defineConfig } from "@playwright/test";

export default defineConfig({
  testDir: "./e2e",
  use: {
    baseURL: "http://localhost:3000",
  },
  webServer: {
    command: "npm run dev",
    url: "http://localhost:3000",
    reuseExistingServer: !process.env.CI,
  },
});

ポイント

  • page.waitForURL(/page=2/) で URL 変化を待ってから検証する。click() 直後に page.url() を読むと遷移前の URL が返ることがある
  • page.getByRole("link", { name: "次のページ" }) はボタンテキストや aria-label に対応するロールベースロケーターで、実装変更に強い。data-testid は最終手段
  • aria-current="page" を検証することで、アクセシビリティ属性が正しく実装されているかをE2Eレベルで確認できる
  • webServer 設定で reuseExistingServer: !process.env.CI を使うと、ローカルでは起動済みサーバーを再利用でき、CI では必ず新規起動できる
  • フィルタ × ページネーションの組み合わせテストは、フィルタ変更時の page リセットと、ページ遷移時のフィルタ維持の両方を検証することで、URL 状態管理のバグを早期に検出できる
  • data-testid='sample-card' などのテスト用属性は process.env.NODE_ENV === 'test' のみ出力する実装にするか、E2E 用に常時出力してもよい(プロジェクトの方針による)

注意点

jest-url-search-params-test は URLSearchParams の単体テスト。jest-component-test はコンポーネントの Jest テスト。これはブラウザ操作でページネーション UI の動作とURL同期を検証するE2Eテストに特化。

関連サンプル