Playwright 自動待機とタイムアウト
この章では、Playwright の自動待機メカニズムと、手動待機およびタイムアウト設定の完全な知識について詳しく説明します。
自動待機が必要な理由
現代の Web アプリケーションは非同期レンダリングを多用するため、ページのコンテンツが瞬時にすべて読み込まれるわけではありません。
従来のテストフレームワークでは、開発者は待機のためにコードを書かなければなりませんでした。sleep 或 waitForしかし、これらの操作は柔軟性に欠け、待ちすぎるとテストが遅くなるか、待ち時間が不足してフレーキー(不安定)になるかのいずれかです。
Playwright は待機ロジックをすべての Locator と Action に組み込み、この問題を根本的に解決します。
3層の自動待機システム
第一層:Locator の自動待機
Locator を作成しても、Playwright はすぐに要素を検索しません。操作やアサーションを実行したときに検索を開始し、自動的に待機します。
例
const btn = page.getByRole('button', { name: '遅延して出現するボタン' });
// クリック時にボタンが現れるまで自動待機(最大 action timeout 時間待機)
await btn.click();
第二層:Action の操作可能性チェック
操作(click、fill など)を実行する前に、Playwright は要素が次の状態であることを確認します:Attached → Visible → Stable → Receives Events → Enabled。
第三層:Assertion の自動リトライ
アサーションが失敗してもすぐにはエラーになりません。条件が満たされるかタイムアウトになるまでリトライを続けます。
例
await expect(page.getByText('数据加载完成')).toBeVisible();
手動待機メソッド
自動待機だけでは不十分な特別なシナリオでは、Playwright は手動待機メソッドも提供しています。
page.waitForTimeout(ms) ——固定待機
例
await page.waitForTimeout(2000);
使用はできるだけ避けてください。
waitForTimeout固定待機はデバイスの性能差により非常に不安定です。後述のwaitForURL、waitForResponse<<<SEP>>> <<<SEP>>> などのイベント駆動待機を優先的に使用してください。
page.waitForURL() ——URL の変化を待機
例
await page.waitForURL('https://www.example.com/dashboard');
// URL が特定のパターンを含むまで待機
await page.waitForURL(/dashboard/);
page.waitForLoadState() ——読み込み状態を待機
例
await page.waitForLoadState('load');
// DOMContentLoaded を待機
await page.waitForLoadState('domcontentloaded');
// ネットワークがアイドル状態になるまで待機
await page.waitForLoadState('networkidle');
page.waitForResponse() ——ネットワークレスポンスを待機
例
const response = await page.waitForResponse(
resp => resp.url().includes('/api/data') && resp.status() === 200
);
// レスポンスデータを取得
const data = await response.json();
page.waitForEvent() ——イベントを待機
例
const dialogPromise = page.waitForEvent('dialog');
await page.getByRole('button', { name: '删除' }).click();
const dialog = await dialogPromise;
await dialog.accept();
// 新しいページが開くまで待機
const pagePromise = page.context().waitForEvent('page');
await page.getByRole('link', { name: '新窗口打开' }).click();
const newPage = await pagePromise;
タイムアウト設定の詳細
Playwright には4種類のタイムアウトがあり、それぞれ異なるレベルに作用します:
| タイムアウトの種類 | 設定ファイルの場所 | デフォルト値 | 対象 |
|---|---|---|---|
| Test timeout | timeout | 30000ms | テストケース全体 |
| Expect timeout | expect.timeout | 5000ms | アサーションのリトライ |
| Action timeout | use.actionTimeout | なし(制限なし) | 要素操作(click、fill など) |
| Navigation timeout | use.navigationTimeout | なし(制限なし) | ページナビゲーション(goto、goBack など) |
グローバル設定
例
import { defineConfig } from '@playwright/test';
export default defineConfig({
// 各テストの合計タイムアウト時間(ミリ秒)
timeout: 60000,
// アサーション自動リトライのタイムアウト時間
expect: {
timeout: 10000,
},
use: {
// 各操作(click、fill など)のタイムアウト時間
actionTimeout: 15000,
// 各ナビゲーションのタイムアウト時間
navigationTimeout: 30000,
},
});
個別設定(グローバル設定より優先)
例
test.setTimeout(120000);
// 単一操作のタイムアウトを設定
await page.getByRole('button').click({ timeout: 30000 });
// 単一ナビゲーションのタイムアウトを設定
await page.goto('https://www.example.com/', { timeout: 60000 });
タイムアウトの優先順位
個別設定 > 設定ファイルのグローバル設定 > デフォルト値。
タイムアウトを適切に設定するためのアドバイス
| シナリオ | 推奨タイムアウト | 説明 |
|---|---|---|
| ローカル開発 | デフォルト値 | ローカルサービスの応答が速いため、デフォルト値で十分 |
| CI 環境 | デフォルト値の2〜3倍 | CI マシンの性能変動が大きい |
| 遅いページ | actionTimeout: 15000 | 大きなフォーム、複雑なページ |
| サードパーティサービス呼び出し | test.setTimeout(120000) | 外部 API の応答が遅い |