定義
Playwright flaky test は初回実行で失敗したが 自動 retry で成功 したテストである。failed は初回とすべての retry が 同じ理由で失敗 する再現可能(deterministic)な欠陥である。CI job が赤でも、この 2 つを先に分けないと修正方向(テスト安定化 vs アプリ/ビルドバグ)が変わる。
なぜ必要か
E2E(End-to-End)テストはネットワーク遅延、SSE(Server-Sent Events、サーバーがブラウザへイベントを push する接続)、ポータル UI、hydration(サーバー HTML にクライアントイベントを接続する過程)のタイミングに敏感である。チームが「flaky を直すか」「アプリバグを直すか」を混同すると、同じ赤い CI ログを見ながら食い違った作業になる。
failOnFlakyTests: true 設定では retry が成功しても CI exit code が 1 のため、GitHub conclusion だけでは flaky と failed は区別できない。Playwright レポート・stdout の attempt ごとの結果 を見る必要がある。
動作原理
- passed: 初回
test()実行が成功。 - flaky: attempt 1 失敗 → retry 成功。原因はたいてい 順序競合(タイマー、focus、ネットワーク predicate)。
- failed: すべての attempt が同じ assertion/例外。原因は アプリロジック、環境、production ビルド成果物(例: CSS が
<script>でロード)。 - 診断の深さ:
pageerrorはメッセージだけのことが多い。CDP(Chrome DevTools Protocol)Runtime.exceptionThrownは例外の URL・lineNumber を返す。 - 再現: dev サーバーではなく
production build+next start(または同等環境)で失敗テストを回す。原因設定 on/off の A/B ビルド で仮説を検証する。
よくある flaky パターン:
| パターン | 症状 | 代替 |
|---|---|---|
固定 setTimeout + SSE refetch | パーセント・状態 assertion の順序が入れ替わる | Promise gate でイベント順序を制御 |
| Radix Select キーボード | portal option focus 前にキー入力 | option visible・focused を待つ |
networkidle | クリック無反応 | dialog open・button enabled など semantic 待機 |
緩い waitForRequest | 別 API リクエストを先に捕まえる | method・pathname・query 一致 predicate |
実務での適用
CI 調査手順:
- 期間内の push ワークフローログ全体 を収集(数件サンプルだけ見ない)。
- 各テストを passed / flaky / failed でタグ付け。
- flaky 上位はテスト安定化、100% failed は production 再現 + CDP。
- custom webpack
splitChunks変更後、HTML の script タグ・build manifest で CSS が JS entry に混ざっていないか確認。
トレードオフ
- retry を増やすと flaky は通るが 実際の不安定さは残る。
failOnFlakyTestsはそれを CI で露呈する。 - CDP 接続はローカル再現に有利だが CI ごとに付けにくい — stdout パース・artifact 方針を別途持つ。
networkidle・sleepは書きやすいが flake を 隠し 再発する。
使ってはいけない場合
- 単体テストレベルのロジックに Playwright triage は過剰 — Vitest 等で隔離する。
- インフラ障害(artifact アップロード失敗、ディスク full)でログがないとき flaky 率を推定しない。
- flaky テストから assertion を削除して CI を緑にするのは欠陥隠蔽である。
よくある間違い
- GitHub job conclusion = flaky と決めつける。
group-deleteのように 123/123 同一 SyntaxError を flaky と呼ぶ — deterministic failed である。- dev サーバーだけ回して production ビルド欠陥を見逃す。
page.route()だけで SSR 認証リクエストを mock し、サーバー・ブラウザ mock 不一致になる。
関連概念
- webpack-splitchunks-vendor-shared-chunk — CSS が JS entry に入り
<script src="*.css">が生じる罠 - ssr-hydration-mismatch —
networkidle≠ hydration 完了 - react-render-count-isolation-testing — レンダー回数隔離の単体テスト