MeWrite Docs

Playwright: Timeout exceeded

PlaywrightのE2Eテストでタイムアウトした場合のエラー

概要

PlaywrightでE2Eテスト実行中に、要素の待機やアクションがタイムアウトした場合に発生するエラーです。

エラーメッセージ

TimeoutError: Timeout 30000ms exceeded.
=========================== logs ===========================
waiting for locator('button[type="submit"]')

または

TimeoutError: page.waitForSelector: Timeout 30000ms exceeded.

原因

  1. 要素が存在しない: セレクタが間違っている
  2. 動的コンテンツ: 非同期でロードされる要素
  3. ページ遷移: ナビゲーション中の待機不足
  4. ネットワーク遅延: APIレスポンスが遅い

解決策

1. 適切なロケーターを使用

1
2
3
4
5
6
7
// 悪い例:脆いセレクタ
await page.click('.btn-primary:nth-child(2)');

// 良い例:意味のあるロケーター
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByTestId('submit-button').click();
await page.getByLabel('Email').fill('test@example.com');

2. 自動待機を活用

1
2
3
4
5
6
// Playwrightは自動的に要素を待機
await page.getByRole('button', { name: 'Save' }).click();

// 明示的な待機は通常不要だが、必要な場合
await page.waitForLoadState('networkidle');
await page.waitForURL('**/dashboard');

3. タイムアウト設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// テストごとの設定
test('slow test', async ({ page }) => {
  test.setTimeout(60000);  // 60秒

  await page.goto('/slow-page');
});

// アクションごとの設定
await page.getByRole('button').click({ timeout: 10000 });

// グローバル設定(playwright.config.ts)
export default defineConfig({
  timeout: 30000,
  expect: {
    timeout: 5000
  }
});

4. ネットワークの待機

1
2
3
4
5
6
7
8
// 特定のAPIレスポンスを待機
const responsePromise = page.waitForResponse('**/api/users');
await page.getByRole('button', { name: 'Load Users' }).click();
const response = await responsePromise;
expect(response.status()).toBe(200);

// すべてのリクエストが完了するまで待機
await page.waitForLoadState('networkidle');

5. 条件付き待機

1
2
3
4
5
6
7
8
// 要素が表示されるまで待機
await expect(page.getByText('Success')).toBeVisible();

// 要素が非表示になるまで待機
await expect(page.getByRole('dialog')).toBeHidden();

// 要素の数を待機
await expect(page.getByTestId('item')).toHaveCount(5);

6. リトライロジック

1
2
3
4
5
6
7
8
// expect は自動的にリトライする
await expect(page.getByRole('alert')).toHaveText('Saved successfully');

// カスタムリトライ
await expect(async () => {
  const count = await page.getByTestId('item').count();
  expect(count).toBeGreaterThan(0);
}).toPass({ timeout: 10000 });

7. フレームの処理

1
2
3
4
5
6
// iframeを待機して操作
const frame = page.frameLocator('#my-iframe');
await frame.getByRole('button', { name: 'Click' }).click();

// フレームが読み込まれるまで待機
await page.waitForSelector('iframe#my-iframe');

8. ダイアログの処理

1
2
3
4
5
6
7
8
// ダイアログを事前に設定
page.on('dialog', dialog => dialog.accept());

// または待機して処理
const dialogPromise = page.waitForEvent('dialog');
await page.getByRole('button', { name: 'Delete' }).click();
const dialog = await dialogPromise;
await dialog.accept();

9. スクリーンショットで デバッグ

1
2
3
4
5
6
7
8
9
test('debug test', async ({ page }) => {
  await page.goto('/');

  // 失敗時にスクリーンショット
  await page.screenshot({ path: 'debug.png' });

  // トレースを有効化(playwright.config.ts)
  // trace: 'on-first-retry'
});

10. 並列実行の制御

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// playwright.config.ts
export default defineConfig({
  // ワーカー数を制限
  workers: process.env.CI ? 1 : undefined,

  // テストを順次実行
  fullyParallel: false,

  // リトライ設定
  retries: process.env.CI ? 2 : 0
});

よくある間違い

  • page.waitForTimeout() の使用(非推奨、代わりに自動待機を使用)
  • セレクタに CSS クラス名を使用(変更に弱い)
  • ネットワークリクエストの完了を待たずに次のアクションを実行
  • 動的に生成される要素のIDに依存

Playwright の他のエラー

最終更新: 2025-12-09