コンテンツにスキップ

フレーキーテストを自動修復する

ユースケース: テストスイートの2%がフレーキーで、赤いビルドを見ても「本物の失敗かどうか」判断できない。リトライは問題を隠すだけで、人間は同じ3パターンのフレークを延々と直し続けている。この「修正」自体を自動化したい。

フレーキーテストはコード変更なしに失敗するため、失敗そのものからは「何を直せばいいか」が分かりません。原因の多くはスクリーンショットには写らないタイミングの問題です: 遅れて流れ込んでくるコンテンツ、クリックを横取りするトースト、locator()click() の間にボタンを動かす段階的レンダリング。診断には画面が時間とともにどう動いたかの証拠が必要で、その先に修正候補の生成と、修正が効いたことの統計的な証明が要ります。

ループはこうです: 検出 → 証拠収集 → 診断と修正(エージェント) → 反復実行で検証 → PR

1. 検出: リトライをフレークのセンサーにする

Section titled “1. 検出: リトライをフレークのセンサーにする”

retries を有効にしていれば、「リトライで通った」こと自体がフレークの信号です。カスタムレポーターで拾います:

flaky-reporter.ts
import type { Reporter, TestCase, TestResult } from '@playwright/test/reporter';
export default class FlakyReporter implements Reporter {
private flaky: string[] = [];
onTestEnd(test: TestCase, result: TestResult) {
if (result.status === 'passed' && result.retry > 0) this.flaky.push(test.id);
}
onEnd() {
require('node:fs').writeFileSync('flaky.json', JSON.stringify(this.flaky));
}
}

トレースが示すのはPlaywrightが何をしたかであって、アクションの合間に画面が何をしていたかではありません — そしてフレークが棲んでいるのは後者です。agent-screen-observer のパッシブモードは、テスト実行中は待ち時間ゼロでフレームを記録し、失敗したときだけ解析して、視覚イベント(遅発のレイアウトシフト、クリック地点に重なったトースト、段階的レンダリングのバースト)をコンパクトなテキスト+切り抜き画像として添付します:

// playwright.config.ts — 通常のtrace設定に加えて
import { test } from 'agent-screen-observer/playwright';
test.use({
screenObserverOptions: { mode: 'passive', attach: 'retain-on-failure' },
});

画面が落ち着いたように見えた後、+1.8秒でレイアウトがシフトした」というレポートが得られれば、「謎のタイムアウト」は名前のついた修正可能な欠陥に変わります。

3. エージェントで診断とパッチ

Section titled “3. エージェントで診断とパッチ”

コーディングエージェント(ヘッドレスモードのClaude Codeなど)に、証拠を詰めた簡潔なプロンプトを渡します:

Terminal window
claude -p "テスト '$TEST_ID' はフレーキーです(リトライで成功)。
証拠:
- 失敗した試行のエラー + トレース要約: trace.txt
- 画面観察レポート: observer-report.json
最も可能性の高い原因を特定し、テストに最小の修正を適用してください
(ロケーターが曖昧な場合はアプリへの data-testid 追加も可)。
ルール: waitForTimeout 禁止。web-firstアサーション優先。テストを弱めないこと。"

修正の探索空間は絞り込みます — 典型的な修復は小さく機械的です:

フレークのパターン(証拠から) 機械的な修正
遅発のレイアウトシフトがクリック対象を動かす まず原因をアサート(画像やリストのロード完了)してからクリック
トーストがボタンに重なる 一時表示要素の消滅を待つ(領域はレポートに載っている)
データロードとの競合 テキストのアサートを expect.poll / toPass によるAPI状態の確認に置き換え
曖昧なロケーターが2要素にマッチ role+name に絞るかテストIDを付与

4. 反復実行で検証 — 省略不可のステップ

Section titled “4. 反復実行で検証 — 省略不可のステップ”

反復実行による証明のないフレーク修正は、ただの迷信です:

Terminal window
npx playwright test $TEST_FILE --repeat-each=30 --workers=4

これをPRのゲートにします。30回連続グリーンなら、証拠を添えてPRを作成します:

Terminal window
gh pr create --title "fix(flaky): stabilize $TEST_ID" \
--body "原因: 画面観察レポートによる遅発レイアウトシフト(+1.8s)。30/30リピートでグリーン。"

人間がレビューするのは検証済み・証拠付きの1行diffです — 再現に費やす午後ではなく、数分で済みます。

  • ループには上限を設けます。エージェントの修正が --repeat-each を通らなければ、延々とイテレーションせず、集めた証拠とともに人間へエスカレーションします。
  • 「フレーキーテスト」の一部はアプリ側の本物のレースです。オブザーバーの証拠を見ればどちら側のバグかは大抵分かります — そちらはバグトラッカーに回し、テストを「安定化」してバグを握りつぶさないこと。
  • 修復はCI上でスケジュール実行(flaky.json を対象にナイトリー)し、PRビルドの中では回さないこと — 人間のためのフィードバックループは速いまま保ちます。