ツール比較 約6分で読めます
Playwright E2Eテスト実践ガイド|セットアップから CI 連携まで【2026年版】
Playwright による E2E テストの実装方法を完全解説。セットアップ、要素の待機、スクリーンショット、並列実行、GitHub Actions連携まで実例付きで紹介。
Playwright は Microsoft が開発する E2E(End-to-End)テストフレームワークで、2026年現在では最も人気のあるテストツールの一つです。Chromium、Firefox、WebKit の全主要ブラウザを単一のAPIで操作でき、TypeScript・Python・.NET・Java に対応しています。
Playwright の特徴
- クロスブラウザ: Chrome、Firefox、Safari(WebKit)を単一コードで
- 高速: 並列実行で大量のテストを短時間で
- デバッグしやすい: トレース、ビデオ、スクリーンショット自動記録
- 自動待機: 要素の出現を自動的に待つ
- ネットワーク制御: API モック、レスポンス改ざん
- モバイルエミュレーション: iPhone、Android デバイスの模擬
Cypress との比較
| 項目 | Cypress | Playwright |
|---|---|---|
| 対応ブラウザ | Chromium系 + Firefox | 全主要ブラウザ(Safari も) |
| 実行速度 | 普通 | 高速 |
| 並列実行 | 有料 | 無料 |
| 複数タブ | 制限あり | 対応 |
| iframe | 制限あり | 対応 |
| 価格 | 一部有料 | 完全無料 |
| API | 独自 | シンプル |
インストール
npm init playwright@latest
対話的にセットアップされます。以下を選択:
- TypeScript / JavaScript
- テストディレクトリ(
tests推奨) - GitHub Actions の追加(推奨)
- Playwright ブラウザのインストール
# ブラウザを個別にインストール
npx playwright install
基本的なテスト
// tests/example.spec.ts
import { test, expect } from '@playwright/test';
test('ホームページのタイトルが正しい', async ({ page }) => {
await page.goto('https://clvr.lol');
await expect(page).toHaveTitle(/Code & Craft/);
});
test('記事ページに遷移できる', async ({ page }) => {
await page.goto('https://clvr.lol');
await page.getByRole('link', { name: '記事一覧' }).click();
await expect(page).toHaveURL(/\/blog/);
});
要素の取得方法
Playwright は ロール(Role)ベースのセレクタを推奨しています。
推奨: セマンティックなロケーター
// Role ベース(最優先)
await page.getByRole('button', { name: '送信' }).click();
await page.getByRole('link', { name: 'ホーム' }).click();
await page.getByRole('heading', { name: 'タイトル' });
// Label ベース
await page.getByLabel('メールアドレス').fill('test@example.com');
// Placeholder
await page.getByPlaceholder('パスワード').fill('secret');
// テキスト
await page.getByText('こんにちは').click();
// Test ID(カスタム属性 data-testid)
await page.getByTestId('submit-button').click();
非推奨: CSS セレクタ
// 避ける(HTML 構造に依存)
await page.locator('#btn-submit').click();
await page.locator('.header > nav a').click();
アサーション
// 要素の状態
await expect(page.getByRole('button')).toBeVisible();
await expect(page.getByRole('button')).toBeEnabled();
await expect(page.getByRole('button')).toBeDisabled();
await expect(page.getByRole('checkbox')).toBeChecked();
// テキスト
await expect(page.getByRole('heading')).toHaveText('タイトル');
await expect(page.getByRole('heading')).toContainText('タイトル');
// URL
await expect(page).toHaveURL('/blog');
await expect(page).toHaveURL(/\/blog\/\d+/);
// ページタイトル
await expect(page).toHaveTitle(/Code & Craft/);
// 要素数
await expect(page.getByRole('article')).toHaveCount(10);
// 属性
await expect(page.getByRole('link')).toHaveAttribute('href', '/about');
// スクリーンショット比較
await expect(page).toHaveScreenshot('homepage.png');
Playwright のアサーションは 自動的にリトライします。要素が出現するまで最大 5 秒(デフォルト)待機してくれるため、手動の waitFor は不要です。
フォーム操作
test('ログインフォーム', async ({ page }) => {
await page.goto('/login');
// 入力
await page.getByLabel('メールアドレス').fill('user@example.com');
await page.getByLabel('パスワード').fill('password');
// チェックボックス
await page.getByLabel('ログイン状態を保持').check();
// セレクトボックス
await page.getByLabel('言語').selectOption('ja');
// ファイルアップロード
await page.getByLabel('アバター').setInputFiles('./test-files/avatar.png');
// 送信
await page.getByRole('button', { name: 'ログイン' }).click();
// 遷移確認
await expect(page).toHaveURL('/dashboard');
});
待機(待ち処理)
Playwright は自動待機が基本ですが、明示的な待機も可能です。
// 要素が表示されるまで待機
await page.waitForSelector('.content');
// 特定のURLに遷移するまで待機
await page.waitForURL('/dashboard');
// ネットワークが落ち着くまで待機
await page.waitForLoadState('networkidle');
// カスタム条件で待機
await page.waitForFunction(() => document.title.includes('完了'));
// 時間で待機(非推奨)
await page.waitForTimeout(1000);
ネットワーク制御とモック
API レスポンスのモック
test('APIエラー時の表示', async ({ page }) => {
await page.route('**/api/users', (route) => {
route.fulfill({
status: 500,
contentType: 'application/json',
body: JSON.stringify({ error: 'サーバーエラー' }),
});
});
await page.goto('/users');
await expect(page.getByText('エラーが発生しました')).toBeVisible();
});
レスポンスの監視
test('API レスポンスを検証', async ({ page }) => {
const responsePromise = page.waitForResponse('**/api/posts');
await page.goto('/blog');
const response = await responsePromise;
expect(response.status()).toBe(200);
const data = await response.json();
expect(data.length).toBeGreaterThan(0);
});
スクリーンショット・ビデオ
// フルページスクリーンショット
await page.screenshot({ path: 'fullpage.png', fullPage: true });
// 特定要素のスクリーンショット
await page.getByRole('article').screenshot({ path: 'article.png' });
// ビジュアルリグレッションテスト
await expect(page).toHaveScreenshot('homepage.png', {
maxDiffPixels: 100,
});
設定ファイル playwright.config.ts でトレース・ビデオの自動記録を有効化:
import { defineConfig } from '@playwright/test';
export default defineConfig({
use: {
trace: 'on-first-retry', // 失敗時のみトレース
screenshot: 'only-on-failure', // 失敗時のみスクショ
video: 'retain-on-failure', // 失敗時のみ保存
},
});
並列実行と複数ブラウザ
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
fullyParallel: true,
workers: process.env.CI ? 2 : 4,
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
{
name: 'Mobile Chrome',
use: { ...devices['Pixel 5'] },
},
{
name: 'Mobile Safari',
use: { ...devices['iPhone 13'] },
},
],
});
# 全ブラウザでテスト
npx playwright test
# 特定ブラウザのみ
npx playwright test --project=chromium
# 並列数を指定
npx playwright test --workers=8
デバッグツール
Inspector
npx playwright test --debug
コードステップ実行とライブ検査ができます。
Trace Viewer
失敗時のトレースを詳細に確認:
npx playwright show-trace trace.zip
各ステップのスナップショット、コンソール、ネットワークを閲覧できます。
Codegen(コード自動生成)
npx playwright codegen https://clvr.lol
ブラウザ操作をそのままテストコードに変換してくれます。テスト初心者に特に便利です。
Page Object Model
複雑なテストは Page Object パターンで整理します。
// pages/login.page.ts
export class LoginPage {
constructor(private page: Page) {}
async goto() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.page.getByLabel('メールアドレス').fill(email);
await this.page.getByLabel('パスワード').fill(password);
await this.page.getByRole('button', { name: 'ログイン' }).click();
}
}
// tests/login.spec.ts
import { test } from '@playwright/test';
import { LoginPage } from '../pages/login.page';
test('ログイン成功', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login('user@example.com', 'password');
});
GitHub Actions での実行
name: Playwright Tests
on: [push, pull_request]
jobs:
test:
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: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
まとめ
Playwright は、2026年現在における E2E テストの最有力選択肢です。
導入を推奨するケース:
- 新規プロジェクト
- Cypress の機能制限(クロスブラウザ、並列実行)に困っている
- モバイル対応のテストが必要
- ビジュアルリグレッションテストをしたい
学習ステップ:
codegenでテストを自動生成して試す- 基本的なアサーションとロケーターを覚える
- Page Object パターンに進化させる
- CI/CD に統合
始めるのは簡単で、スケールも容易です。まずは 3-5 個のクリティカルパスをカバーするテストから始めましょう。