Playwright CLI によるビジュアル QA
黄金律: 新しいコマンド出力なしに結論を出さない。「問題ないはず」は禁止です。
最小セットアップ
- Playwright をプロジェクトの devDependency として追加する。
playwright.config.tsには 375px の明示的なビューポート(devices['Pixel 7']は 412px のため不可)と、desktop-chromeおよびmobile-chromeプロジェクトを含める。 - キャプチャ用スクリプトは
scripts/shot.mjsに記述する(MCP は使用しないこと:CLI の方が高速で再現性が高い)。 - axe 用に
@axe-core/playwrightをインストールする。 - 実際のパフォーマンスを測定するには本番ビルドを配信する(
npm run build && npm run start)。開発サーバーはデバッグのみに使用する。
ページおよびロケールごとのチェック
- コンソールとネットワーク:
page.on('console')、page.on('pageerror')、page.on('requestfailed')および HTTP ステータス 400 以上のレスポンス。違反は赤。 - オーバーフロー: 各ビューポートで
document.documentElement.scrollWidth <= clientWidth + 1を確認する。オーバーフローがある場合は、原因要素をリストする(getBoundingClientRect().right > innerWidth)。 - アクセシビリティ: axe で
critical/serious違反なし。h1は 1 つだけ。img[alt]は完全であること。すべてのインタラクティブ要素でフォーカスが可視であること(:focus-visibleを実際のキーボードで確認し、CSS を目視で判断しない)。タブ順序は論理的であること。 - モーション軽減:
page.emulateMedia({ reducedMotion: 'reduce' })を設定する。ピン、自動再生、200ms を超えるアニメーションがないこと。 - リンク: すべての
hrefを抽出し、内部リンクは 200 を検証し、外部リンクは参考情報としてマークする。href="#"でハンドラのないものは 0 件。 - SEO:
title、meta description、canonical、OG、ロケールごとのhreflang、解析可能な JSON-LD、sitemap.xmlおよびrobots.txtが 200 を返すこと。 - パフォーマンス: 読み込み後に PerformanceObserver で LCP/CLS を測定する。目標はデスクトップで LCP < 2.5 秒、CLS < 0.1。自動スクロール中の 5 秒間、rAF で長いフレーム(>50ms)をカウントしてスクロールジャンクを測定する。
- キャンバス/スクロール: ヘッドレスモードではキャンバスが真っ黒になる可能性があるため、DOM で確認する:期待される opacity/transform を持つ要素、ビートのテキストが正しい範囲に存在し可視であること、
windowに状態が公開されている場合はその存在。
ループ
- 各実行後:ゲート/コマンド/結果/ステータスのテーブルと、証拠(セレクタ、ログ、またはキャプチャ)付きのブロッカーリストを含むレポートを生成する。
- ゲートが失敗した場合:修正する(独自のテスト/スクリプト)か、証拠付きの具体的な
src/修正を提案する。その後、完全なサイクルを繰り返す。 - タイムスタンプ付きのキャプチャを
docs/qa/に保存する(プライマリロケールごとにデスクトップ + モバイル)。ベースラインと比較して回帰を検出する。 - 赤のゲートまたは未実行のゲートがある状態で「準備完了」を宣言しない。
正直な限界
- ヘッドレスモードから実際の iOS でのフレームシーケンスを検証することはできない:レポートにその旨を記載する。
- Lighthouse(
npx lighthouse)はオプションですが、本番ビルドでは推奨されます。実行できない場合は、推定するのではなくその旨を伝える。