Playwright Trace ViewerでAI生成E2Eテストの失敗原因を10分で絞る — 4証拠の読み順
更新日: 2026-07-26
AIにE2Eテストを書いてもらった。ローカルでは通った。でもCIでは赤い。もう一度実行すると、今度は通る。
そこでエラーログをAIへ渡したら、timeout: 60000を足す修正が返ってきた。
でも、ちょっと待ってください。その修正で、本当に原因は消えたんでしょうか。
結論から言うと、コードを直す前にtraceを残し、Action、DOM snapshot、Network、Consoleの4証拠を順番に読みます。
AIは証拠の比較、原因仮説の整理、最小修正案の作成をかなり速くできます。一方で、何が正しい仕様か、traceをどこまで共有してよいか、どの修正を採用するかは人間が判断します。
ログの最後の1行だけで事件を解こうとしない。現場に残った証拠を、時間順に見る。
僕はこの調査手順を 「証拠の読み順」 と呼びます。
この記事では、まず10分で意図的な失敗traceを作り、Trace Viewerを開きます。そのあと、4証拠の読み方、AIへ渡すプロンプト、CIへ入れる設定、効かない条件までつなげます。
最初に4つの用語だけ
E2Eテスト は、ユーザーがブラウザで行う操作を、入口から結果まで通して確かめるテストです。ログイン、検索、購入など、複数の画面やAPIをまたぐ流れを検査します。
trace は、テスト中に何が起きたかを後からたどるための記録です。PlaywrightのTrace Viewerでは、操作、DOMの状態、通信、Consoleなどを時間順に確認できます。
retry は、失敗したテストをもう一度実行する仕組みです。Playwrightは、最初から通ったテストをpassed、最初は落ちたが再実行で通ったテストをflaky、再実行しても落ちたテストをfailedとして分けます。
locator は、ボタンや入力欄など、操作したい要素を見つけるための表現です。getByRoleやgetByLabelのように、ユーザーから見える役割や名前で探せます。
ここで大事なのは、retryで通ったことを「直った」と考えないことです。
一度落ちてから通ったなら、それは成功の証明ではなく、条件によって結果が変わる証拠 です。
人間、AI、Playwrightの役割を先に分ける
| 担当 | 任せること | 任せないこと |
|---|---|---|
| 人間 | 期待仕様、許容時間、機密境界、修正承認 | trace内の大量比較 |
| AI | 証拠の要約、仮説の順位付け、修正候補、再発防止案 | 仕様の最終決定、traceの無断外部送信 |
| Playwright | 操作記録、DOM snapshot、通信、Console、再実行分類 | 業務上どちらが正しいかの判断 |
AIに向いているのは、たくさんの観測事実を並べ、共通点と差分を探す仕事です。
人間が持つべきなのは、「検索結果は0件でも正常なのか」「3秒を超えたら失敗なのか」「この通信内容を外部サービスへ渡してよいか」という判断です。
つまり、AIに原因を当ててもらうのではなく、AIが比較できる証拠を人間が用意する。この順番です。
10分の初回成功: 失敗traceを自分で開く
まずは、外部サイトにもバックエンドにも接続しない最小例で試します。わざと失敗させるので、赤くなって正解です。
tests/search.spec.tsを作ります。
import { test, expect } from '@playwright/test';
test('商品検索の結果件数を表示する', async ({ page }) => {
await page.setContent(`
<main>
<button type="button">検索</button>
<div id="result">0件</div>
</main>
`);
await page.getByRole('button', { name: '検索' }).click();
// 画面は「0件」なので、ここは意図的に失敗する
await expect(page.locator('#result')).toHaveText('3件');
});
次の2コマンドを実行します。
npx playwright test tests/search.spec.ts --trace on
npx playwright show-trace test-results/**/trace.zip
Trace Viewerが開いたら、失敗したexpect.toHaveTextを選んでください。期待値は3件、実際のDOMは0件です。
これで最初の成功です。
テストは落ちています。でも、「なぜ落ちたかを目で選べる状態」まで進みました。理解した、ではなく、証拠が動いた。
なお、--trace onは各テストのtraceを記録するため、ローカルの少数テストで調査する時に向いています。Playwright公式は、CIではすべての実行で常時記録するより、最初のretryで記録する設定を案内しています。そこは後半で設定します。
4証拠はAction → DOM → Network → Consoleの順で読む
Trace Viewerには情報が多いです。最初から全部を見ると、むしろ迷います。
そこで読み順を固定します。
- Actionで「どこから失敗したか」を決める
- DOM snapshotで「その瞬間に何が見えていたか」を確かめる
- Networkで「必要なデータが届いたか」を確かめる
- Consoleで「画面側の例外や警告」を確かめる
順に見ていきましょう。
証拠1: Actionで最初のズレを探す
Actionには、click、fill、expectなど、テストが実行した操作が並びます。
ここで見るのは、最後に赤くなった行だけではありません。赤い行より一つ前の操作が、期待どおり完了しているか を見ます。
たとえば、次の失敗は全部「結果が表示されない」に見えます。
- 検索ボタンを別の要素が覆っていて、clickできなかった
- clickは通ったが、検索APIを呼んでいなかった
- APIは成功したが、DOMの表示更新が遅れていた
- DOMは更新されたが、テストのlocatorが古い文言を探していた
エラーログの最後だけを見ると、どれもtimeoutに見えます。でも、最初にズレたActionは違います。
Playwrightのlocator actionは、要素が表示されているか、安定しているか、イベントを受け取れるか、有効かなどを確認してから操作します。clickで止まったなら、まず「待ち時間が短い」より、Actionの詳細と直前状態を見る方が筋がええんです。
Actionで見る3点
- 失敗したActionの名前
- 開始から失敗までの時間
- 直前に成功したActionと、その時の画面
ここで原因がlocatorの取り違えだと分かったら、timeoutを延ばしても直りません。間違った住所で、配達を長く待つようなものです。
証拠2: DOM snapshotで「その瞬間」を見る
DOMは、ブラウザが持っている画面構造です。Trace Viewerのsnapshotを使うと、テストがそのActionを行った時点の状態を前後にたどれます。
スクリーンショットは見た目を確認するのに便利です。一方、DOM snapshotでは、要素の役割、属性、文言、構造をより詳しく確かめられます。
たとえばgetByRole('button', { name: '検索' })が失敗した時、次を確認します。
- 本当にbuttonとして存在するか
- 名前が「検索」ではなく「商品を検索」へ変わっていないか
- disabledになっていないか
- 同じ名前のbuttonが2つ存在しないか
- dialogやoverlayの下に隠れていないか
AIが生成したテストでは、CSS classやDOM階層へ強く依存するlocatorが混ざることがあります。
// 壊れやすい例
await page.locator('div:nth-child(3) > button.btn-primary').click();
// ユーザーの認識に近い例
await page.getByRole('button', { name: '検索' }).click();
ただし、後者へ変えればいつでも正しいわけではありません。同名buttonが複数あるなら、画面側のアクセシビリティ設計か、検索範囲の設計を人間が決める必要があります。
AIにはlocator候補を出してもらう。どのUI表現が仕様として安定しているかは、人間が決める。
証拠3: Networkで「届かなかった」を分ける
画面に結果が出ない時、DOMだけを直し続けても治らない場合があります。
Networkでは、ブラウザが送ったrequestと受け取ったresponseを確認します。
見る順番は次の通りです。
- 期待したAPI requestが発生したか
- statusは成功か、4xxか、5xxか
- responseは期待した形か
- 異常に時間がかかっていないか
- retry前後で内容が変わっていないか
たとえば、検索APIが500を返しているなら、locatorの修正では直りません。401なら認証状態、429ならレート制限、200なのに空配列ならtest dataや環境の問題が候補になります。
ここで大事なのは、statusだけで断定しないことです。
200でもエラー情報を返すAPIはありますし、404が「商品なし」という正常仕様の場合もあります。業務上の期待は人間が定義します。
また、request/responseにはtoken、cookie、個人情報、テスト用アカウント情報が含まれる可能性があります。trace.zipを、そのまま外部AIや公開チャットへ投入しないでください。
必要な箇所をマスクした要約へ変換するか、組織で許可された閉じた環境だけを使います。
証拠4: Consoleで画面側の例外を探す
通信が成功し、DOMも途中まで更新されているのに画面が完成しない。
そんな時はConsoleを見ます。
よくある候補は次です。
-
TypeErrorなどのJavaScript例外 - hydrationの不一致
- 未処理Promise rejection
- feature flagや環境変数の不足
- アプリが出している独自エラーログ
ただし、Console warningが1件あるから、それが原因とは限りません。広告、拡張機能、開発用warningなど、失敗と無関係なノイズもあります。
Actionの時刻とConsoleの時刻を照合し、失敗直前に何が起きたかを見ます。
相関と因果は別物。
Consoleは容疑者一覧であって、判決ではありません。
原因を5分類すると修正が小さくなる
4証拠を読んだら、原因候補を次の5つへ分類します。
| 分類 | 代表的な証拠 | 修正の方向 |
|---|---|---|
| locator | ActionとDOMが不一致 | 安定したrole/name/test idへ変更 |
| test data | API成功だが期待データなし | テストごとのデータ作成・掃除 |
| application | Network成功後にConsole例外 | 本体コード修正と回帰テスト |
| network | 4xx/5xx/遅延 | mock、契約テスト、環境修正 |
| environment | CIだけ設定・時刻・locale差 | 実行条件の固定と明示 |
分類の目的は、きれいなラベルを付けることではありません。
修正範囲を小さくすること です。
locatorの問題なら、アプリ全体のtimeoutを延ばさない。test dataの問題なら、UIを無理に待たせない。environmentの問題なら、テスト本文へ謎の分岐を足さない。
原因と修正の層をそろえると、未来の手戻りが減ります。
AIへ任せるプロンプト1: 仮説を3件に絞る
trace全部ではなく、機密を除いた観測事実を渡します。
あなたはE2Eテスト調査の補助者です。
次の観測事実だけを使い、原因仮説を最大3件に絞ってください。
各仮説に次を付けてください。
- 根拠となる観測事実
- その仮説を否定できる反証条件
- 次に1つだけ見る証拠
- locator / test data / application / network / environment の分類
証拠がない内容は「推測」と明記してください。
期待仕様を勝手に変更しないでください。
ポイントは「原因を当てて」ではなく、反証条件と次の証拠を要求すること です。
AIの答えを結論ではなく、調査順へ変えます。
AIへ任せるプロンプト2: 最小修正を比較する
期待仕様は変えません。
固定sleep、無条件retry、全体timeout延長を追加せず、
観測された原因を除く最小修正案を2案ください。
各案について次を示してください。
- 変更ファイルと変更理由
- 副作用
- 再発を検知するassertion
- 採用前に人間が確認すること
証拠で支えられない修正は提案しないでください。
禁止事項を先に置くと、「とりあえず待つ」という対症療法が混ざりにくくなります。
もちろん、timeout変更が正しい場合もあります。たとえば業務上30秒かかる処理を5秒で失敗させているなら、expect timeoutの見直しは候補です。
ただし、Playwrightにはテスト全体のtimeoutとexpectのtimeoutが別にあります。公式ドキュメントでは、既定のtest timeoutは30秒、expect timeoutは5秒です。どちらを変えるかは、「何を待っているか」を確認してから決めます。
AIへ任せるプロンプト3: 再発防止をチーム資産にする
次の失敗記録から、再発防止案を作ってください。
出力を分けてください。
1. Playwright設定で自動化すること
2. テストコードへ追加すること
3. アプリ側で直すこと
4. 人間がレビュー時に判断すること
5. traceに残してはいけない機密
実行済みの確認と、未実行の提案を明記してください。
修正コードだけでなく、次に同じことが起きた時の観測手段まで残します。
コピーできるコードより、途中でやめない更新の仕組み。そこまで作って、初めてチームの資産になります。
CIでは最初のretryだけtraceを記録する
ローカル調査では--trace onが分かりやすいですが、CIの全テストで常時traceを取ると、実行時間と保存容量が増えます。
Playwright公式が案内する基本形は、最初のretryでtraceを記録する設定です。
import { defineConfig } from '@playwright/test';
export default defineConfig({
retries: process.env.CI ? 1 : 0,
reporter: [['html', { open: 'never' }]],
use: {
trace: 'on-first-retry',
},
});
retryを使わず、最初の失敗を残したいチームはretain-on-failureも選べます。
ここで気をつけたいのが、retries: 1を「一回落ちても通れば合格」と運用しないことです。Playwrightはretryで通ったテストをflakyとして区別します。
チームでは少なくとも次を決めておくと迷いが減ります。
- flakyをPRの合格に含めるか
- trace artifactの保存期間
- traceを閲覧できる人
- 認証情報や個人情報を含むテストの扱い
- 同じテストが何回flakyになったら修正対象にするか
retryは証拠を取る機会です。失敗を見えなくする消しゴムではありません。
traceを安全に扱う
Playwrightの公式CIガイドも、trace、HTML report、Console logなどのartifactには、テストユーザーの資格情報、access token、画面やソースコードなどが含まれ得ると注意しています。
安全ルールはシンプルです。
- 本番アカウントでE2Eを実行しない
- traceを公開artifactにしない
- 信頼済みの保存先と閲覧権限を使う
- 保存期間を必要最小限にする
- 外部AIへ渡す時は組織ルールを確認し、必要箇所だけ匿名化する
AIへ渡すこと自体が悪いわけではありません。
問題は、何が入っているか確認せず、zipを丸ごと渡すことです。
共有範囲を決めるのは人間。比較と要約を速めるのはAI。この境界を崩さないようにします。
この方法が効かない条件
Trace Viewerは、ブラウザから観測できる失敗に強いです。
でも、次の原因はtraceだけで確定できないことがあります。
- 外部サービス内部の障害
- queueや非同期workerの内部状態
- databaseのlockやreplication遅延
- 仕様書と実装のどちらが正しいか
- ユーザー環境固有の端末・ネットワーク問題
この場合は、traceの時刻、request ID、テスト名を起点に、サーバーログ、分散trace、メトリクス、監査ログへ進みます。
つまり、この方法は万能な原因特定法ではありません。
ブラウザの外へ原因がある時に、次の観測場所を選ぶための入口 です。
また、テストが単純でローカルですぐ再現できるなら、Trace Viewerを開かずエラーメッセージだけで十分な場合もあります。すべての失敗へ重い調査を持ち込む必要はありません。
見分け方は、「同じ条件で再現するか」です。
毎回同じ行で同じ理由なら、まず通常のデバッグ。CIだけ、たまに、retryで結果が変わるなら、traceを残す価値が上がります。
今日10分でやること
最初からチーム全体へ導入しなくて大丈夫です。
今日やることは一つだけ。
手元の失敗テストを1本、--trace onで実行し、赤いActionと直前のDOMを開く。
原因を直せなくてもかまいません。「次にNetworkを見る」「locatorを見直す」と選べたら、推測ゲームからは一歩抜けています。
AIがコードを書く速度は、これからも上がると思います。
せやからこそ、人間の仕事は、生成された答えを眺めることから、正しい証拠を集め、判断の境界を設計することへ移っていく。
未来の自分が、CIの再実行ボタンを何度も押さずに済む。今日の小さなtraceが、その時間を省いてくれます。
動作確認
- 最小テストと
playwright.config.tsはPlaywright 1.62.0で実行しました。 -
Expected: "3件"/Received: "0件"で意図どおり失敗し、trace.zipが生成されることを確認しました。 - CI artifact設定は環境依存のため、この記事では動作未確認です。
参考リンク(一次情報・2026-07-26確認)
生成AI活用エンジニア&3児のパパ。AI×開発の実践知を毎日発信しています → X