E2E(エンドツーエンド)テストは、ユーザーの操作をシミュレーションして、アプリケーション全体が期待通りに動作するかを検証するテスト手法です。Playwrightは、Microsoftが開発したオープンソースのE2Eテストフレームワークで、Chromium・Firefox・WebKitの3つのブラウザエンジンを単一のAPIで操作できます。
この記事では、Playwrightをゼロからセットアップし、最初のテストを書いて実行するまでを解説します。
なぜPlaywrightか?
E2Eテストフレームワークは複数ありますが、Playwrightが選ばれる理由は明確です。
flowchart LR
subgraph PW["Playwrightの強み"]
A["クロスブラウザ対応"]
B["自動待機"]
C["並列実行"]
D["テスト生成"]
E["トレースビューア"]
end
style PW fill:#3b82f6,color:#fff
| 特徴 | 説明 |
|---|---|
| クロスブラウザ | Chromium、Firefox、WebKit(Safari)をすべてサポート |
| 自動待機 | 要素が操作可能になるまで自動で待機し、フレーキーなテストを減らす |
| 並列実行 | 追加サービス不要で複数テストを同時実行 |
| テスト生成 | codegenコマンドでブラウザ操作を記録してコードを自動生成 |
| 多言語対応 | JavaScript/TypeScript、Python、.NET、Javaで利用可能 |
セットアップ
プロジェクトの作成
新規プロジェクトでPlaywrightを始める最も簡単な方法は、初期化コマンドを使うことです。
# 新しいディレクトリを作成
mkdir my-e2e-tests
cd my-e2e-tests
# Playwrightプロジェクトを初期化
npm init playwright@latest
初期化ウィザードが起動し、以下を選択できます:
- TypeScript / JavaScriptの選択
- テストディレクトリの名前(デフォルト:
tests) - GitHub Actionsワークフローの追加
- ブラウザのインストール
既存プロジェクトへの追加
既にNode.jsプロジェクトがある場合は、パッケージを直接追加します。
# テストフレームワークをインストール
npm install --save-dev @playwright/test
# ブラウザをインストール
npx playwright install
生成されるファイル構成
初期化後、以下のファイルが作成されます。
my-e2e-tests/
├── tests/
│ └── example.spec.ts # サンプルテスト
├── tests-examples/
│ └── demo-todo-app.spec.ts # 詳細なサンプル
├── playwright.config.ts # 設定ファイル
├── package.json
└── package-lock.json
設定ファイルの基本
playwright.config.tsはテスト実行の挙動を制御します。最初は最小限の設定から始めましょう。
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
// テストファイルのディレクトリ
testDir: './tests',
// テストのタイムアウト(ミリ秒)
timeout: 30000,
// 並列実行
fullyParallel: true,
// CIではリトライを有効化
retries: process.env.CI ? 2 : 0,
// テスト対象のブラウザ
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});
| 設定項目 | 用途 |
|---|---|
testDir |
テストファイルの格納ディレクトリ |
timeout |
各テストの最大実行時間 |
fullyParallel |
ファイル内テストの並列実行を許可 |
retries |
失敗時の再試行回数 |
projects |
テスト対象のブラウザ設定 |
最初のテストを書く
テストの基本構造
テストファイル tests/login.spec.ts を作成します。
import { test, expect } from '@playwright/test';
test('ページタイトルを検証する', async ({ page }) => {
// ページに遷移
await page.goto('https://playwright.dev');
// タイトルに"Playwright"が含まれることを検証
await expect(page).toHaveTitle(/Playwright/);
});
ポイントを整理します:
test関数でテストケースを定義する{ page }はPlaywrightが自動で提供するフィクスチャ(ブラウザのページオブジェクト)- すべての操作は
async/awaitで記述する expectで結果を検証する
テストの実行
# すべてのテストを実行
npx playwright test
# 特定のファイルを実行
npx playwright test tests/login.spec.ts
# 特定のブラウザで実行
npx playwright test --project=chromium
# ブラウザを表示して実行(デバッグ向き)
npx playwright test --headed
テストレポートの確認
テスト完了後、HTMLレポートを表示できます。
npx playwright show-report
ロケーター: 要素の見つけ方
ロケーターは、テスト対象の要素を特定するための仕組みです。Playwrightは、アクセシビリティに基づくロケーターを推奨しています。
推奨ロケーター(getByシリーズ)
// ロール(WAI-ARIA)で検索 — 最も推奨
await page.getByRole('button', { name: '送信' });
await page.getByRole('heading', { name: 'ようこそ' });
await page.getByRole('link', { name: 'ログイン' });
// ラベルで検索(フォーム要素向け)
await page.getByLabel('メールアドレス');
// プレースホルダーで検索
await page.getByPlaceholder('検索...');
// テキスト内容で検索
await page.getByText('利用規約に同意する');
// テストIDで検索(カスタム属性)
await page.getByTestId('submit-button');
ロケーターの優先順位
flowchart TD
A["getByRole"] --> B["getByLabel"]
B --> C["getByPlaceholder"]
C --> D["getByText"]
D --> E["getByTestId"]
E --> F["CSSセレクター"]
style A fill:#22c55e,color:#fff
style B fill:#22c55e,color:#fff
style C fill:#3b82f6,color:#fff
style D fill:#3b82f6,color:#fff
style E fill:#f59e0b,color:#fff
style F fill:#ef4444,color:#fff
| 優先度 | ロケーター | 理由 |
|---|---|---|
| 高 | getByRole |
アクセシビリティに準拠し、ユーザーの視点に最も近い |
| 高 | getByLabel |
フォーム要素に最適 |
| 中 | getByPlaceholder |
ラベルがない場合の代替 |
| 中 | getByText |
表示テキストで特定できる場合 |
| 低 | getByTestId |
他のロケーターが使えない場合の安全策 |
| 避ける | CSSセレクター | UIの変更に壊れやすい |
getByRoleが推奨される理由は、スクリーンリーダーなどの支援技術が認識する方法と同じだからです。これにより、テストはアクセシビリティの検証も兼ねます。
アサーション: 結果の検証
自動リトライアサーション
Playwrightのアサーションは条件が満たされるまで自動でリトライします。これがフレーキーなテストを防ぐ鍵です。
// 要素の可視性
await expect(page.getByRole('alert')).toBeVisible();
await expect(page.getByRole('alert')).toBeHidden();
// テキスト内容
await expect(page.getByRole('heading')).toHaveText('ダッシュボード');
await expect(page.locator('.message')).toContainText('成功');
// URL
await expect(page).toHaveURL(/dashboard/);
// 要素の数
await expect(page.getByRole('listitem')).toHaveCount(3);
// 入力値
await expect(page.getByLabel('名前')).toHaveValue('田中太郎');
// CSSクラス
await expect(page.locator('.btn')).toHaveClass(/active/);
ソフトアサーション
通常のアサーションは失敗すると即座にテストを中断しますが、ソフトアサーションはすべてのチェックを実行してからまとめて報告します。
await expect.soft(page.getByTestId('status')).toHaveText('OK');
await expect.soft(page.getByTestId('count')).toHaveText('5');
// 両方のチェック結果がレポートに表示される
実践的なテスト例
ログインフォームのテストを書いてみましょう。
import { test, expect } from '@playwright/test';
test.describe('ログイン機能', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/login');
});
test('正しい情報でログインできる', async ({ page }) => {
await page.getByLabel('メールアドレス').fill('user@example.com');
await page.getByLabel('パスワード').fill('password123');
await page.getByRole('button', { name: 'ログイン' }).click();
await expect(page).toHaveURL(/dashboard/);
await expect(page.getByRole('heading')).toHaveText('ダッシュボード');
});
test('空のフォームでエラーが表示される', async ({ page }) => {
await page.getByRole('button', { name: 'ログイン' }).click();
await expect(page.getByRole('alert')).toBeVisible();
await expect(page.getByRole('alert')).toContainText('入力してください');
});
test('間違ったパスワードでエラーが表示される', async ({ page }) => {
await page.getByLabel('メールアドレス').fill('user@example.com');
await page.getByLabel('パスワード').fill('wrong');
await page.getByRole('button', { name: 'ログイン' }).click();
await expect(page.getByRole('alert')).toContainText('認証に失敗しました');
});
});
注目すべきポイント:
test.describeでテストをグループ化しているtest.beforeEachで各テスト前にログインページに遷移しているgetByLabelとgetByRoleで要素をアクセシブルに取得している- 明示的な待機(
waitForやsleep)が一切不要
デバッグ
テストが失敗した時、Playwrightは強力なデバッグ機能を提供します。
UIモード
テストの実行状況をリアルタイムで確認できるインタラクティブなUIです。
npx playwright test --ui
デバッグモード
ステップ実行でテストの各操作を確認できます。
npx playwright test --debug
トレースビューア
CI環境で失敗したテストを後から調査できます。設定で有効にします。
// playwright.config.ts
export default defineConfig({
use: {
trace: 'on-first-retry', // リトライ時にトレースを記録
},
});
トレースには以下が記録されます:
- 各操作のスクリーンショット
- DOMスナップショット
- ネットワークリクエスト
- コンソールログ
# トレースファイルを開く
npx playwright show-trace trace.zip
テスト生成(codegen)
ブラウザを操作するだけで、テストコードを自動生成できます。
npx playwright codegen https://example.com
ブラウザが起動し、操作を記録してPlaywrightのコードに変換します。初心者がロケーターの書き方を学ぶのにも最適です。
自動待機の仕組み
Playwrightが他のフレームワークと一線を画す機能が**自動待機(Auto-wait)**です。
flowchart TD
A["アクションを実行<br/>例: click()"] --> B{"要素が<br/>存在する?"}
B -->|No| C["リトライ"]
C --> B
B -->|Yes| D{"要素が<br/>表示されている?"}
D -->|No| C
D -->|Yes| E{"要素が<br/>安定している?"}
E -->|No| C
E -->|Yes| F{"要素が<br/>有効(enabled)?"}
F -->|No| C
F -->|Yes| G{"他の要素に<br/>遮られていない?"}
G -->|No| C
G -->|Yes| H["アクション実行"]
style A fill:#3b82f6,color:#fff
style H fill:#22c55e,color:#fff
style C fill:#f59e0b,color:#fff
click()を呼ぶだけで、Playwrightは要素が「クリック可能」な状態になるまで自動で待機します。これにより、以下のような不安定なコードを書く必要がなくなります。
// 悪い例: 手動で待機する
await page.waitForTimeout(3000); // 3秒待つ
await page.click('#submit');
// 良い例: Playwrightに任せる
await page.getByRole('button', { name: '送信' }).click();
// 自動でクリック可能になるまで待機する
まとめ
| 概念 | ポイント |
|---|---|
| セットアップ | npm init playwright@latestで即座に始められる |
| ロケーター | getByRoleを最優先で使う |
| アサーション | 自動リトライによりsleep不要 |
| 自動待機 | 要素の操作可能性を自動で確認 |
| デバッグ | UIモード、トレースビューア、codegenが利用可能 |
| 設定 | playwright.config.tsでブラウザ・並列数・リトライを制御 |
Playwrightの最大の利点は、テストコードがシンプルに保たれることです。自動待機とアクセシブルなロケーターにより、テストは「ユーザーが何をするか」だけに集中でき、「いつ要素が表示されるか」を気にする必要がありません。
参考リンク
- Playwright公式ドキュメント
- Playwright Getting Started
- Playwright Best Practices
- Playwright Locators
- Microsoft Learn: Build your first E2E test
- Greffier, Jean-François. Practical Playwright Test. APress, 2026.
- Kelhini, Faraz K. and Mayhew, Butch. Hands-On Automated Testing with Playwright. Packt, 2026.