PlaywrightによるE2Eテスト
Playwrightは、Microsoftが開発している信頼性の高いEnd-to-End (E2E) テストのためのフレームワークです。Chromium, WebKit, Firefoxを含むすべてのモダンブラウザをサポートしています。
主な特徴
- クロスブラウザ対応: Chrome, Edge, Firefox, Safari (WebKit) で動作します。
- 高い信頼性: 自動待機 (Auto-wait) 機能により、要素が表示されるまで操作を待機するため、Flaky(不安定)なテストを減らせます。
- 強力なツール: コード生成 (Codegen)、Playwright Inspector、Trace Viewerなどが標準で付属しています。
- 完全な分離: 各テストは独立したブラウザコンテキストで実行されるため、状態の干渉がありません。
インストールとセットアップ
プロジェクトにPlaywrightを導入するには、以下のコマンドを実行します。
npm init playwright@latest
セットアップウィザードが表示されるので、以下の項目を選択します。
- TypeScriptかJavaScriptか(TypeScript推奨)
- テストフォルダの名前(デフォルト:
tests) - GitHub Actionsワークフローを追加するかどうか
テストの基本構造
Playwrightのテストファイルは通常 tests ディレクトリに配置します。
import { test, expect } from '@playwright/test';
test('ホームページのタイトルが正しいこと', async ({ page }) => {
// ページにアクセス
await page.goto('https://playwright.dev/');
// タイトルに "Playwright" が含まれていることを確認
await expect(page).toHaveTitle(/Playwright/);
});
test('Get Startedリンクが機能すること', async ({ page }) => {
await page.goto('https://playwright.dev/');
// "Get started" リンクをクリック
await page.getByRole('link', { name: 'Get started' }).click();
// URLが "/docs/intro" を含むことを確認
await expect(page).toHaveURL(/.*intro/);
});
ロケーター (Locators)
Playwrightでは、ユーザーの操作に近い形で要素を取得する推奨ロケーターがあります。
page.getByRole(): ボタン、リンク、見出しなどの役割で取得(最も推奨)page.getByText(): テキスト内容で取得page.getByLabel(): フォームのラベルで取得page.getByPlaceholder(): プレースホルダーテキストで取得page.getByAltText(): 画像のaltテキストで取得page.getByTestId():data-testid属性で取得
// ボタンをクリック
await page.getByRole('button', { name: '送信' }).click();
// テキスト入力
await page.getByLabel('ユーザー名').fill('user123');
自動待機 (Auto-waiting)
Playwrightの大きな特徴の一つは、操作を行う前に要素が操作可能な状態になるまで自動的に待機することです。これにより、sleep や明示的な待機処理を書く必要が大幅に減ります。
例えば click() を実行すると、Playwrightは以下の条件がすべて満たされるまで待機します:
- DOMに存在する (Attached)
- 表示されている (Visible):
display: noneやvisibility: hiddenでない - アニメーションが停止している (Stable)
- イベントを受け取れる (Receives Events): 他の要素に隠れていない
- 有効である (Enabled):
disabled属性がない
これらのチェックは、タイムアウト(デフォルト30秒)になるまで繰り返し行われます。
アサーション (Assertions)
expect 関数を使用して、要素の状態やページの状態を検証します。これらは自動的にリトライを行います。
// 要素が表示されているか
await expect(locator).toBeVisible();
// テキストが含まれているか
await expect(locator).toContainText('完了');
// 入力値が正しいか
await expect(locator).toHaveValue('user123');
// チェックボックスがチェックされているか
await expect(locator).toBeChecked();
テストの実行
コマンドラインでの実行
すべてのテストを実行:
npx playwright test
特定のファイルのみ実行:
npx playwright test tests/example.spec.ts
ヘッドレスモード(ブラウザを表示しない)ではなく、ブラウザを表示して実行:
npx playwright test --headed
UIモード
インタラクティブなUIモードでテストを実行・デバッグできます。タイムトラベルデバッグなどが可能です。
npx playwright test --ui
レポートの表示
テスト実行後、HTMLレポートを表示するには:
npx playwright show-report
VS Code 拡張機能
VS Codeを使用している場合、公式の Playwright Test for VSCode 拡張機能をインストールすることを強く推奨します。 これにより、エディタ上から直接テストを実行したり、デバッグしたりすることが可能になります。
Flakyなテストを防ぐためのフロントエンド実装
テストの安定性(Flakinessの排除)は、テストコードだけでなく、フロントエンドの実装にも大きく依存します。
1. テスト用属性 (data-testid) の活用
CSSクラスやIDはスタイリングのために変更される可能性があります。テスト専用の属性 data-testid を付与することで、デザイン変更の影響を受けない堅牢なロケーターを作成できます。
// 推奨されない実装
<button className="btn-primary-large">送信</button>
// 推奨される実装
<button data-testid="submit-button">送信</button>
テスト側では page.getByTestId('submit-button') で取得します。
2. セマンティックなHTMLとARIAロール
Playwrightは getByRole の使用を推奨しています。適切なHTMLタグ(<button>, <nav>, <h1>など)やARIA属性を使用することで、アクセシビリティを向上させると同時に、テストもしやすくなります。
3. ローディング状態の可視化
非同期処理中はスピナーやスケルトンスクリーンを表示し、処理完了後にそれらが消えるように実装します。これにより、テストコード側で「ローディングが消えるまで待つ」という明確な待機条件を記述できます。
// ローディングが消えるのを待つことで、データ読み込み完了を保証
await expect(page.getByTestId('loading-spinner')).not.toBeVisible();
4. 動的なコンテンツの制御
テスト実行時は、日付、ランダムな数値、アニメーションなどが結果に影響しないように注意します。必要に応じて、モックデータを使用したり、アニメーションを無効化する設定を検討してください。
ベストプラクティス
- ロケーターの優先順位: 可能な限り
getByRoleなどのユーザーに見える属性を使用し、CSSセレクターやXPathは避ける。 - Web First Assertions:
await expect(...)を使用して、非同期な状態変化を適切に待機する。 - 独立性: 各テストは独立させ、他のテストの実行順序や状態に依存しないようにする。
- Codegenの活用:
npx playwright codegenを使用して、操作を記録しテストコードの雛形を生成する。