Playwright E2E: Claude Code 활용 가이드
playwright e2e: Claude Code 활용. 실용적인 팁과 코드 예시를 포함합니다.
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/
정리
Playwrightはクロス브라우저대응の安定したE2E 테스트環境を提供します。Claude Codeを활용すれば、페이지객체설계、인증フロー、ビジュアル테스트などの複雑な테스트シナリオも효율적으로구축가능합니다。
단위 테스트の高度な手法はVitest上級テクニックを、API모크의 상세 정보는MSW API모크활용가이드를 참고하세요.Playwright공식 문서도 확인해 두세요.
Claude Code 워크플로우를 한 단계 업그레이드하세요
지금 바로 Claude Code에 복사해 쓸 수 있는 검증된 프롬프트 템플릿 50선.
이 글을 작성한 사람
Masa
Claude Code를 적극 활용하는 엔지니어. 10개 언어, 2,000페이지 이상의 테크 미디어 claudecode-lab.com을 운영 중.
관련 글
Claude Code Agent SDK 입문 ― 자율 에이전트를 빠르게 구축하는 방법
Claude Code Agent SDK로 자율형 AI 에이전트를 구축하는 방법을 해설합니다. 설정부터 도구 정의, 멀티스텝 실행까지 실전 코드와 함께 소개합니다.
Claude Code 컨텍스트 관리 테크닉 완전 가이드
Claude Code의 컨텍스트 윈도우를 최대한 활용하는 실전 테크닉을 해설합니다. 토큰 절약, 대화 분할, CLAUDE.md 활용법까지 소개합니다.
Claude Code MCP Server 설정 및 실전 활용 가이드
Claude Code의 MCP Server 기능을 종합적으로 소개합니다. 외부 도구 연결, 서버 설정, 실전 통합 사례까지 한 번에 알아보세요.