Playwright E2E with Claude Code
Learn about playwright e2e using Claude Code. Practical tips and code examples included.
PlaywrightでE2Eテストを自動化する
Playwrightはクロスブラウザ対応のE2Eテストフレームワークです。Chromium、Firefox、WebKitの3つのブラウザエンジンをサポートし、安定したテスト実行を実現します。Claude Codeはテストシナリオの設計からページオブジェクトの構築まで的確にサポートします。
ページオブジェクトパターン
Claude Codeにページオブジェクトの設計を依頼しましょう。
> Playwrightでログインページのページオブジェクトを作って。
> エラー表示の確認、成功時のリダイレクト確認を含めて。
import { Page, Locator, expect } from "@playwright/test";
export class LoginPage {
readonly page: Page;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
readonly errorMessage: Locator;
readonly rememberMeCheckbox: Locator;
constructor(page: Page) {
this.page = page;
this.emailInput = page.getByLabel("メールアドレス");
this.passwordInput = page.getByLabel("パスワード");
this.submitButton = page.getByRole("button", { name: "ログイン" });
this.errorMessage = page.getByRole("alert");
this.rememberMeCheckbox = page.getByLabel("ログイン状態を保持");
}
async goto() {
await this.page.goto("/login");
}
async login(email: string, password: string) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
async expectError(message: string) {
await expect(this.errorMessage).toContainText(message);
}
async expectRedirectTo(path: string) {
await expect(this.page).toHaveURL(new RegExp(path));
}
}
テストシナリオの実装
ページオブジェクトを使ったテストの記述です。
import { test, expect } from "@playwright/test";
import { LoginPage } from "./pages/login-page";
import { DashboardPage } from "./pages/dashboard-page";
test.describe("認証フロー", () => {
let loginPage: LoginPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.goto();
});
test("有効な認証情報でログインできる", async ({ page }) => {
await loginPage.login("admin@example.com", "password123");
await loginPage.expectRedirectTo("/dashboard");
const dashboard = new DashboardPage(page);
await expect(dashboard.welcomeMessage).toContainText("ようこそ");
});
test("無効なパスワードでエラーが表示される", async () => {
await loginPage.login("admin@example.com", "wrong-password");
await loginPage.expectError("メールアドレスまたはパスワードが正しくありません");
});
test("空のフォームでバリデーションエラーが表示される", async () => {
await loginPage.submitButton.click();
await expect(loginPage.emailInput).toHaveAttribute("aria-invalid", "true");
});
});
認証状態の共有
テスト間で認証状態を共有して実行速度を向上させるパターンです。
// auth.setup.ts
import { test as setup, expect } from "@playwright/test";
const authFile = "playwright/.auth/user.json";
setup("authentication", async ({ page }) => {
await page.goto("/login");
await page.getByLabel("メールアドレス").fill("test@example.com");
await page.getByLabel("パスワード").fill("password123");
await page.getByRole("button", { name: "ログイン" }).click();
await page.waitForURL("/dashboard");
await expect(page.getByText("ようこそ")).toBeVisible();
await page.context().storageState({ path: authFile });
});
// playwright.config.ts
import { defineConfig } from "@playwright/test";
export default defineConfig({
projects: [
{ name: "setup", testMatch: /.*\.setup\.ts/ },
{
name: "chromium",
use: {
storageState: "playwright/.auth/user.json",
},
dependencies: ["setup"],
},
],
});
APIモックとネットワーク制御
テスト中のAPIリクエストをインターセプトするパターンです。
test("APIエラー時にエラー画面が表示される", async ({ page }) => {
await page.route("**/api/users", (route) =>
route.fulfill({
status: 500,
contentType: "application/json",
body: JSON.stringify({ error: "Internal Server Error" }),
})
);
await page.goto("/users");
await expect(page.getByText("データの取得に失敗しました")).toBeVisible();
await expect(page.getByRole("button", { name: "再試行" })).toBeVisible();
});
test("遅いネットワークでローディング表示される", async ({ page }) => {
await page.route("**/api/users", async (route) => {
await new Promise((resolve) => setTimeout(resolve, 3000));
await route.continue();
});
await page.goto("/users");
await expect(page.getByText("読み込み中")).toBeVisible();
});
ビジュアルリグレッションテスト
スクリーンショット比較で視覚的な変更を検出します。
test("ダッシュボード画面のビジュアルチェック", async ({ page }) => {
await page.goto("/dashboard");
await page.waitForLoadState("networkidle");
await expect(page).toHaveScreenshot("dashboard.png", {
maxDiffPixelRatio: 0.01,
animations: "disabled",
});
});
test("モバイル表示のビジュアルチェック", async ({ page }) => {
await page.setViewportSize({ width: 375, height: 812 });
await page.goto("/dashboard");
await expect(page).toHaveScreenshot("dashboard-mobile.png");
});
CI/CDでの設定
GitHub Actionsでの実行設定です。
# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npx playwright install --with-deps
- run: npx playwright test
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: playwright-report/
Summary
Playwrightはクロスブラウザ対応の安定したE2Eテスト環境を提供します。Claude Codeを活用すれば、ページオブジェクト設計、認証フロー、ビジュアルテストなどの複雑なテストシナリオも効率的に構築可能です。
ユニットテストの高度な手法はVitest上級テクニックを、APIモックの詳細はMSW APIモック活用ガイドを参照してください。Playwright公式ドキュメントも確認しておきましょう。
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
Free PDF: Claude Code Cheatsheet in 5 Minutes
Key commands, shortcuts, and prompt examples on a single printable page.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
Getting Started with Claude Code Agent SDK — Build Autonomous Agents Fast
Learn how to build autonomous AI agents with Claude Code Agent SDK. Covers setup, tool definitions, and multi-step execution with practical code examples.
The Complete Guide to Context Management in Claude Code
Learn practical techniques to maximize Claude Code's context window. Covers token optimization, conversation splitting, and CLAUDE.md usage.
Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More
Mastering Claude Code Hooks: Auto-Format, Auto-Test, and More. A practical guide with code examples.