| name | e2e-review |
| description | E2Eコードレビュー用。PR確認・品質チェック時に使用。MUST FIX/SHOULD FIXチェックリスト・エラーメッセージ別対処法・.catch隠蔽問題の検出方法・FAQを含む。禁止事項の詳細は .claude/rules/prohibited-patterns.md を参照。 |
E2E Code Review Skill
禁止事項・4層責務・Locator原則は rules/(常時読み込み済み)。
このSkillはレビュー手順とチェックリストに特化。
§1. レビュー手順
- §2.0 機械ゲート(
npm run gate)を実行し、出力を確認する(読むだけのチェックより先。機械的に落とせるデブリを最初に潰す)
- §2のMUST FIXチェックリストを上から確認
- §3のSHOULD FIX確認
- §8 self-interrogation を作成者自身に自己申告させる(grep で拾えないデブリ — 未使用追加物・PR本文との乖離・新規
@deprecated)
- Locator具体指摘が必要なら
/e2e-locator Skill参照
- 指摘は「理由」+「正しい実装例」をセットで
なぜコマンドを先に回すのか: 「読むだけ」のルールは注意の希釈で素通りする(自己レビュー1往復を通過した後でも tsc エラー・Action 直書き Locator・未使用 export が master 直前まで残る事例が起きる)。grep / コマンドで落とせるものは人間の目視に頼らず機械で落とす。
再レビュー時のフレッシュスキャン原則: 複数ラウンドのレビューでは「前ラウンドで指摘した箇所が直っているか」の確認に集中しがちになり、Round 1 で見逃したものはその後も発見されにくい。再レビュー時は前ラウンドのコメントを参照せず、diff を最初から通読する。修正コードに混入した新たな問題も「対応内容に問題なし」と素通りしやすいため、変更箇所の周辺コードも含めて新鮮な目でチェックする。
§2. MUST FIX(PR差し戻し基準)
§2.0 機械ゲート(コマンドで機械的に落とす — 最優先)
必ず実行して出力を確認する。チェックボックスを目視で埋めるのではなく、コマンドの結果で判定する。
複数プロジェクトを含むワークスペースでは、対象プロジェクトのディレクトリに cd してから実行する。
npm run gate; echo "exit: $?"
検出ロジックの正本は scripts/gate.sh(CI でも PR ごとに同一判定が走る)。
カバー範囲: tsc 型チェック / Action・Test 層 Locator 直書き / .catch 隠蔽 / text= / XPath /
private readonly / Fixture 未経由 import / Test 内 new Action / Action 層 expect /
タイムアウト・URL ハードコード / Date.now() 一意名 / MODAL ハイブリッド / 未定義タグ /
ordinal・waitForTimeout・expect 部分一致の理由コメントなし / describe 内 configure /
verify 内 waitForTimeout(AST)/ 数値定数の宣言元コメントなし / メタ層(Rules 総量ラチェット・
Skill 間参照・SKILL.md サイズ)+ ⚠️ 警告(Page Object waitForTimeout の目視補完等)。
npm run gate がない場合は以下を個別に実行する:
npx tsc --noEmit; echo "exit: $?"
grep -rnE "\.(locator|getBy[A-Za-z]+)\(" src/actions/
grep -rn "\.catch(() => false)\|\.catch(() => true)" src/
未使用 export(どのテストからも呼ばれないメソッド・PO クラス)は tsc では拾えない(noUnusedLocals はローカル変数/import まで)。これは §8 self-interrogation で作成者に自己申告させる。
セキュリティ
定数管理
Locator
4層責務
エラーハンドリング
テスト条件の黙殺
テストデータ準備の構造(ベース作成フローの肥大・模倣伝播)
テスト手順書(JSDoc)と実装の同期
§3. SHOULD FIX
§4. .catch(() => false) 検出と修正
検出:
grep -rn ".catch(() => false)" src/
grep -rn ".catch(() => true)" src/
5箇所以上 → AIコピペを強く疑う。
修正:
const isVisible = await element.isVisible({ timeout: 5000 }).catch(() => false);
try {
await expect(element).toBeVisible({ timeout: TIMEOUTS.CHECK });
await element.click();
} catch {
}
§5. エラーメッセージ別対処
Target page, context or browser has been closed
原因: URL遷移未待機(外部認証遷移時に多発)
await this.page.waitForURL(URL_PATTERNS.AUTH_LOGIN, { timeout: TIMEOUTS.DEFAULT });
await this.page.waitForTimeout(TIMEOUTS.AUTH_STABILIZATION);
Timeout exceeded
原因: SPA描画待機不足 / モーダルアニメーション / セレクタ誤り
await page.waitForLoadState('networkidle');
await page.waitForTimeout(TIMEOUTS.SPA_RENDERING);
Element is not visible / outside of the viewport
await page.waitForTimeout(TIMEOUTS.MODAL_ANIMATION);
await button.scrollIntoViewIfNeeded();
await button.click({ force: true });
strict mode violation
原因: :has-text()部分一致で複数マッチ
page.locator('span:text-is("ログイン")')
page.locator('[role="dialog"] span:has-text("ログイン")')
§6. FAQ
Q: Action層でwaitFor()は使える?
はい。waitFor()は待機操作でアサーションではない。禁止はexpect()のみ。
Q: 意味層の厚さとは?
要素のセマンティック情報の充実度。厚い(data-testidあり、ラベル付きフォーム、テキストボタン)→セマンティックLocator可。薄い(ラベルなしチェックボックス、アイコンのみボタン)→:near()/data属性。プロジェクト導入時にUI全体の意味層の厚さを評価すること。
Q: waitForTimeoutは使っていい?
はい。SPA/外部認証/モーダルでは必要。TIMEOUTS定数+理由コメントが条件。
Q: .first()は常にダメ?
できる限り避ける。使う場合: 親要素で絞り込み + 理由コメント + TODO。
Q: 既存コードがルール違反していたら?
コピーせず正しいパターンで実装。可能なら既存も修正。
§7. テスト結果報告プロトコル(Pass 判定の検証)
テスト結果を「Pass」と報告する前に、テストランナーが正常終了したことを必ず確認する。途中ログに ✓ が出ていても、ランナーが正常終了していなければ結果は 未確定。
確認すべき 3 点
- プロセスの終了コード:
npx playwright test ...; echo $? で確認。0 以外(例: 1, 144)は失敗または異常終了
- 最終サマリー行: 標準出力の末尾に
N passed (Mm) のサマリーが出力されていること
- report.json の完全性:
test-results/report.json が存在し、stats.unexpected === 0 かつ JSON として完結していること
npx playwright test ... 2>&1 | tail -3
cat test-results/report.json | jq '.stats'
偽陽性(Pass と誤報告)が起きやすいケース
| 状況 | 何が起きるか | 正しい報告 |
|---|
| ブラウザクラッシュ(exit code 144 等) | 途中まで ✓ 出力されているがサマリーなし | 「結果未確定、再実行が必要」 |
report.json が JSON 不完全 / 切れている | プロセス強制終了で書き込み中断 | 「結果未確定」 |
| Ctrl+C 等で中断 | 途中まで完走しているように見える | 「中断された、結果不明」 |
| timeout で kill | 個別 test は ✓ でも全体は failed | サマリー行を見て判定 |
ルール: 上記いずれかが疑われる場合は「Pass」と報告せず、再実行を提案する。ユーザーに「全テスト合格」と伝えて良いのは、3 点の確認が揃ったときのみ。
再レビュー時の数値再測定: fix コミット後の再レビューでは、サイズ・件数などの数値主張を前回測定値の流用で「一致」とせず必ず再測定する(fix コミット自体が数値を変える)。
§8. self-interrogation(PR 化前の自己申告 — grep で拾えないデブリ)
§2.0 のコマンドは構文・境界デブリを機械的に落とす。だが 「呼ばれない追加物」「PR本文と diff の乖離」「不要な互換コード」は grep では拾えない。作成者自身(AI 含む)に PR 化前に以下を明文で自己申告させる。「無い」で済ませず、列挙して各々に理由を添える。
Q1. 未使用の追加物を全列挙し、各々の「残す理由」を述べよ
本 PR で追加した次のうち、どのテストからも呼ばれていないものを全て列挙する。各々について「将来のテストで使う予定(どのテストか明記)」か「今すぐ削除すべき」かを判断する。
- 追加した public メソッド(Action / Page Object)
- 追加した Page Object クラス・ファイル
- 追加した env キー・constants の定数
- 追加した関数引数・オプション
「将来使うかも」で残すなら どのテストでいつ使うかを書く。書けないものは dead code として削除する。
grep -rn "SomeMethodName\|SomePageClass" src/
Q2. PR本文と git diff --name-only を突き合わせ、食い違いを指摘せよ
git diff --name-only main...HEAD
- PR本文が言及している変更(「○○を追加」等)が 実際に diff に存在するか
- diff にあるのに本文で説明されていない変更がないか
- 存在しないテスト・機能を主張していないか
Q3. 本 PR で新規追加した @deprecated がないか確認せよ
git diff main...HEAD | grep -n "@deprecated"
@deprecated は「既存の利用者がいるから消せない」ものに付ける互換マーカー。
- 本 PR で新規に追加したコードに
@deprecated が付いていたら矛盾(新規=互換対象となる既存利用者がいない)→ そのコードは最初から不要なので削除する。
- 既存コードの
@deprecated(前の PR で付いたもの)はこの限りではない。