Playwright 自動待機とタイムアウト

この章では、Playwright の自動待機メカニズムと、手動待機およびタイムアウト設定の完全な知識について詳しく説明します。


自動待機が必要な理由

現代の Web アプリケーションは非同期レンダリングを多用するため、ページのコンテンツが瞬時にすべて読み込まれるわけではありません。

従来のテストフレームワークでは、開発者は待機のためにコードを書かなければなりませんでした。sleep 或 waitForしかし、これらの操作は柔軟性に欠け、待ちすぎるとテストが遅くなるか、待ち時間が不足してフレーキー(不安定)になるかのいずれかです。

Playwright は待機ロジックをすべての Locator と Action に組み込み、この問題を根本的に解決します。


3層の自動待機システム

第一層:Locator の自動待機

Locator を作成しても、Playwright はすぐに要素を検索しません。操作やアサーションを実行したときに検索を開始し、自動的に待機します。

例

// Locator を作成(この時点では要素を検索しない)
const btn = page.getByRole('button', { name: '遅延して出現するボタン' });

// クリック時にボタンが現れるまで自動待機(最大 action timeout 時間待機)
await btn.click();

第二層:Action の操作可能性チェック

操作(click、fill など)を実行する前に、Playwright は要素が次の状態であることを確認します:Attached → Visible → Stable → Receives Events → Enabled。

第三層:Assertion の自動リトライ

アサーションが失敗してもすぐにはエラーになりません。条件が満たされるかタイムアウトになるまでリトライを続けます。

例

// このアサーションは、テキストが表示されるかタイムアウトになるまで5秒間リトライを続けます
await expect(page.getByText('数据加载完成')).toBeVisible();

手動待機メソッド

自動待機だけでは不十分な特別なシナリオでは、Playwright は手動待機メソッドも提供しています。

page.waitForTimeout(ms) ——固定待機

例

// 2秒間の固定待機(通常は推奨されません)
await page.waitForTimeout(2000);

使用はできるだけ避けてください。waitForTimeout固定待機はデバイスの性能差により非常に不安定です。後述のwaitForURL、waitForResponse<<<SEP>>> <<<SEP>>> などのイベント駆動待機を優先的に使用してください。

page.waitForURL() ——URL の変化を待機

例

// URL が完全一致するまで待機
await page.waitForURL('https://www.example.com/dashboard');

// URL が特定のパターンを含むまで待機
await page.waitForURL(/dashboard/);

page.waitForLoadState() ——読み込み状態を待機

例

// load イベントを待機
await page.waitForLoadState('load');

// DOMContentLoaded を待機
await page.waitForLoadState('domcontentloaded');

// ネットワークがアイドル状態になるまで待機
await page.waitForLoadState('networkidle');

page.waitForResponse() ——ネットワークレスポンスを待機

例

// 特定の API レスポンスを待機
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 timeouttimeout30000msテストケース全体
Expect timeoutexpect.timeout5000msアサーションのリトライ
Action timeoutuse.actionTimeoutなし(制限なし)要素操作(click、fill など)
Navigation timeoutuse.navigationTimeoutなし(制限なし)ページナビゲーション(goto、goBack など)

グローバル設定

例

// ファイルパス:playwright.config.ts
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 の応答が遅い
その他の拡張