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

Playwright でログインから保護ページ到達までの認証フローを E2E テストする

Playwright でログインフォームへの入力・送信・Cookie 設定・保護ページへのリダイレクト確認・ログアウトまでの認証フローを E2E テストする例。

nextjstestingauthenticationplaywright

対応バージョン

nextjs 15react 19playwright 1

前提環境

Playwright の基本テスト構成(test / expect / locator)と Next.js の認証フローを理解していること

概要

Playwright で認証フロー全体を E2E テストする。ログインフォームへの入力・送信・保護ページへの redirect 確認・ログアウトまでの一連の操作を検証する。storageState を使ってセッションを保存・再利用することで、複数テストでのログイン操作の繰り返しを省略できる。

インストール

npm install --save-dev @playwright/test
npx playwright install chromium

実装

Playwright 設定

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

export default defineConfig({
  testDir: "./e2e",
  use: {
    baseURL: "http://localhost:3000",
    trace: "on-first-retry",
  },
  projects: [
    {
      name: "setup",
      testMatch: /.*\.setup\.ts/,
    },
    {
      name: "authenticated",
      use: {
        ...devices["Desktop Chrome"],
        storageState: "e2e/.auth/user.json",
      },
      dependencies: ["setup"],
    },
    {
      name: "unauthenticated",
      use: { ...devices["Desktop Chrome"] },
    },
  ],
  webServer: {
    command: "npm run dev",
    url: "http://localhost:3000",
    reuseExistingServer: !process.env.CI,
  },
});

認証セットアップ(セッション保存)

// e2e/auth.setup.ts
import { test as setup, expect } from "@playwright/test";
import path from "path";

const authFile = path.join(__dirname, ".auth/user.json");

setup("ログインしてセッションを保存", async ({ page }) => {
  await page.goto("/login");

  await page.getByPlaceholder("メールアドレス").fill("user@example.com");
  await page.getByPlaceholder("パスワード").fill("password");
  await page.getByRole("button", { name: "ログイン" }).click();

  // ダッシュボードへの redirect を確認
  await expect(page).toHaveURL("/dashboard");

  // Cookie を含むストレージ状態をファイルに保存
  await page.context().storageState({ path: authFile });
});

認証済みユーザーのテスト

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

// playwright.config.ts の "authenticated" プロジェクトが storageState を自動注入する
test("ダッシュボードが表示される", async ({ page }) => {
  await page.goto("/dashboard");

  // ログインページへ redirect されないことを確認
  await expect(page).toHaveURL("/dashboard");
  await expect(page.getByRole("heading", { name: "ダッシュボード" })).toBeVisible();
});

test("ログイン済みでログインページにアクセスするとダッシュボードへ redirect される", async ({
  page,
}) => {
  await page.goto("/login");
  await expect(page).toHaveURL("/dashboard");
});

test("ログアウト後は保護ページへアクセスできない", async ({ page }) => {
  // ログアウト API を呼び出す
  await page.request.post("/api/logout");

  await page.goto("/dashboard");

  // ログインページへ redirect されることを確認
  await expect(page).toHaveURL("/login");
});

未認証ユーザーのテスト

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

// "unauthenticated" プロジェクトで実行(storageState なし)
test("未認証で保護ページにアクセスするとログインページへ redirect される", async ({
  page,
}) => {
  await page.goto("/dashboard");
  await expect(page).toHaveURL("/login");
});

test("ログインフォームに正しい認証情報を入力するとダッシュボードへ遷移する", async ({
  page,
}) => {
  await page.goto("/login");

  await page.getByPlaceholder("メールアドレス").fill("user@example.com");
  await page.getByPlaceholder("パスワード").fill("password");
  await page.getByRole("button", { name: "ログイン" }).click();

  await expect(page).toHaveURL("/dashboard");
});

test("誤った認証情報ではエラーメッセージが表示される", async ({ page }) => {
  await page.goto("/login");

  await page.getByPlaceholder("メールアドレス").fill("wrong@example.com");
  await page.getByPlaceholder("パスワード").fill("wrongpassword");
  await page.getByRole("button", { name: "ログイン" }).click();

  await expect(
    page.getByText("メールアドレスまたはパスワードが正しくありません"),
  ).toBeVisible();
  await expect(page).toHaveURL("/login");
});

ポイント

  • storageState を使うと Cookie を含むブラウザセッション全体をファイルに保存できる。auth.setup.ts で 1 回だけログインし、以降のテストはその状態を再利用するため、テストごとにログイン操作を繰り返す必要がない
  • playwright.config.tsdependencies: ["setup"] を設定すると、setup プロジェクトが完了してから authenticated プロジェクトが実行される。セッションファイルが確実に存在する状態でテストが始まる
  • page.request.post("/api/logout") は Playwright の API リクエスト機能でサーバー側の Cookie を削除する。その後 page.goto で保護ページにアクセスして redirect を確認する
  • getByRole / getByPlaceholder などのセマンティックロケーターを使うことで、UI の実装詳細(クラス名 / ID)の変更に影響されない堅牢なテストになる
  • e2e/.auth/ ディレクトリはセッション情報を含むため .gitignore に追加し、リポジトリにコミットしない

注意点

playwright-file-upload-e2e は file input 操作の E2E テスト。これはログイン→保護ページ→ログアウトの認証フロー全体を E2E テストするパターンに特化。storageState を使ったセッション再利用で繰り返しログイン操作を省略するパターンも示す。

関連サンプル