playwright-testing について
フロントエンド開発者向けのテストスキルです。適切なテスト層を選び、可観測性と決定性によって誤検知や不安定さを抑える方法を扱います。Playwright MCPやCanvasゲームのテスト手順も含みます。
主な機能
- 01リスクに応じたテスト層の選択
- 02時間・乱数・ネットワークの制御
- 03安定したテスト用インターフェースの追加
- 04エラー・通信・スクリーンショットの収集
- 05画像比較による視覚差分の確認
活用シーン
- 01重要なユーザーフローのE2Eテスト
- 02Canvasゲームのテスト安定化
- 03CIでの断続的な失敗の診断
MCP 対応
Playwright MCPを使ったブラウザー操作、ページ確認、コンソール・ネットワーク診断、スクリーンショット取得の手順を示します。Playwright MCPツールの利用者向けです。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ chongdashu/ phaserjs-oakwoods --skill playwright-testingインストール後、Claude Code で/playwright-testingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/flake-reduction.mdphaser-canvas-testing.mdplaywright-mcp-cheatsheet.mdscripts/imgdiff.py詳細
フロントエンドテスト
適切なテストレイヤーを選び、アプリを観測可能にし、非決定性を排除することで、信頼性の高い確信をすばやく得られ、安全なリファクタリングが可能になります。失敗を対処可能なものにしましょう。
基本方針:1 分あたりの確信度
フロントエンドテストが失敗する理由は 2 つあります。製品が壊れているか、テストが嘘をついているかです。目指すべきは、シグナルを最大化し、「テストが嘘をついている」状態を最小限に抑えることです。
テストを書く前に、次のことを確認してください:
- どのようなユーザーリスクをカバーしますか(金銭、進行状況、認証、データ損失、クラッシュ)?
- この種類のバグを検出できる最も狭いレイヤーはどれですか(純粋なロジック、UI、フルブラウザー)?
- どのような非決定性がありますか(時間、乱数、非同期読み込み、ネットワーク、アニメーション、フォント、GPU)?
setTimeout以外に、どのような「準備完了」シグナルを待てますか?- CI で診断できるように、失敗時に何を出力またはスクリーンショットに残すべきですか?
基本原則:
- 実装ではなく、契約をテストする:安定した、ユーザーにとって意味のある結果と公開された接点を検証します。
- 再試行より決定性を優先する:時間、乱数、ネットワークを制御可能にし、フレークを発生源から取り除きます。
- デバッガーのように観測する:失敗時にコンソールエラー、ネットワークエラー、スクリーンショット、状態ダンプを確認します。
- まずは 1 つの重要なフローから:信頼できるスモークテストは、フレークの多い 50 個のテストに勝ります。
テストレイヤーの選択ツリー
必要な確信が得られる、最も低コストのレイヤーを選びます。
| レイヤー | 速度 | 用途 |
|---|---|---|
| ユニット | 最速 | 純粋関数、リデューサー、バリデーター、数学、経路探索、決定論的シミュレーション |
| コンポーネント | 中速 | IO をモックした UI の動作(React Testing Library、Vue Testing Library) |
| E2E | 最も低速 | ルーティング、ストレージ、実際のバンドル/ランタイムをまたぐ重要なユーザーフロー |
| ビジュアル | 特化型 | レイアウトやピクセルのリグレッション。canvas/WebGL では、決定性を固定してからのみ実施 |
クイックスタート:最初のスモークテスト
- 重要なフローを 1 つ定義する:「ページが読み込まれる → ユーザーが開始できる → 重要な操作が 1 つ機能する」
- アプリにテスト用の接点を追加する(以下を参照)
- ランナーを選ぶ:E2E には Playwright MCP、ロジックにはユニットテスト
- 失敗を明確にする:コンソールエラーとリクエストの失敗をテスト失敗として扱う
- 安定化する:乱数のシードを固定し、時間を凍結し、ビューポートを固定し、アニメーションを無効にする
具体的な MCP ワークフロー:ゲームのテスト
Phaser/canvas ゲームをテストするための手順:
1. mcp__playwright__browser_navigate
→ http://localhost:3000?test=1&seed=42
2. mcp__playwright__browser_evaluate
→ () => new Promise(r => { const c = () => window.__TEST__?.ready ? r(true) : setTimeout(c, 100); c(); })
(Wait for game ready)
3. mcp__playwright__browser_console_messages
→ level: "error"
(Fail if any errors)
4. mcp__playwright__browser_snapshot
→ Get UI state and refs
5. mcp__playwright__browser_click
→ element: "Start Button", ref: [from snapshot]
6. mcp__playwright__browser_evaluate
→ () => window.__TEST__.state()
(Assert game state is correct)
7. mcp__playwright__browser_press_key
→ key: "ArrowRight" (or WASD for movement)
8. mcp__playwright__browser_evaluate
→ () => window.__TEST__.state().player.x
(Verify movement happened)
9. mcp__playwright__browser_take_screenshot
→ filename: "gameplay-state.png"
(Visual evidence after deterministic setup)
推奨するテスト用の接点
テストしやすくするため、アプリに追加します(読み取り専用、安定、最小限)。
window.__TEST__ = {
ready: false, // true after first interactive frame
seed: null, // current RNG seed
sceneKey: null, // current scene/route
state: () => ({ // JSON-serializable snapshot
scene: this.sceneKey,
player: { x, y, hp },
score: gameState.score,
entities: entities.map(e => ({ id: e.id, type: e.type, x: e.x, y: e.y }))
}),
commands: { // optional mutation commands
reset: () => {},
seed: (n) => {},
skipIntro: () => {}
}
};
ルール:ID と不可欠なフィールドを公開し、生の Phaser/エンジンオブジェクトは公開しないでください。
避けるべきアンチパターン
❌ 間違ったレイヤーをテストする:純粋なロジックに対する E2E テスト
ついやってしまう理由:「ブラウザー経由ですべてテストしよう」
より良い方法:ロジックにはユニットテストを使い、E2E は統合契約に限定します
❌ 実装の詳細をテストする:DOM 構造やクラス名を検証する
ついやってしまう理由:DevTools で見えるものを簡単に検証できる
より良い方法:ユーザーにとって意味のある出力(テキスト、スコア、HP の変化)を検証します
❌ スリープに依存するテスト:wait 2s then click
ついやってしまう理由:簡単で「自分のマシンでは動く」
より良い方法:明示的な準備完了シグナル(DOM マーカー、window.__TEST__.ready)を待ちます
❌ 制御されていない乱数:アサーションで乱数や時間を使う
ついやってしまう理由:「ゲームがランダムなら、テストもランダムにすべき」
より良い方法:乱数のシードを固定し(?seed=42)、時間を凍結し、安定した不変条件を検証します
❌ 決定性のないピクセルスナップショット:フレークする canvas のスクリーンショット
ついやってしまう理由:「ビジュアルのバグを自動で検出できる」
より良い方法:まず決定論的モードにし、その後、既知の安定したフレームでスクリーンショットを撮ります
❌ 戦略としての再試行:「再試行を 3 回に増やすだけ」
ついやってしまう理由:CI をグリーンにできる手っ取り早い修正
より良い方法:フレークの発生源を修正します。再試行は実際の問題を隠してしまいます
失敗したテストのデバッグ
テストが失敗したときは、次の順に証拠を集めます。
- コンソールエラー:
mcp__playwright__browser_console_messages({ level: "error" }) - ネットワークの失敗:
mcp__playwright__browser_network_requests()→ 2xx 以外がないか確認します - スクリーンショット:
mcp__playwright__browser_take_screenshot()→ 失敗時の視覚的な状態を確認します - アプリの状態:
mcp__playwright__browser_evaluate({ function: "() => window.__TEST__.state()" }) - フレークの分類(references/flake-reduction.md を参照):
- 準備状態の問題ですか? → 明示的な待機を追加します
- タイミングの問題ですか? → アニメーション/物理演算を制御します
- 環境の問題ですか? → ビューポート/DPR を固定します
- データの問題ですか? → テストデータを分離します
完了基準:テストはどこまで必要ですか?
最小限の実用的なテストスイート:
- 1 つのスモークテストで、アプリが読み込まれ、主要なアクションが機能することを確認する
- テスト用の接点がある(準備完了フラグと状態を持つ
window.__TEST__) - 決定論的なモードを用意する(canvas/ゲームでは
?test=1でシードを有効にする) - コンソールエラーでテストを失敗させる(サイレントな失敗をなくす)
- CI でテストを実行する(プッシュごと)
次の場合は、テストをさらに拡充します:
- 重要なフロー(認証、支払い、保存/読み込み)に専用の E2E テストがある
- ユニットテストで複雑なロジック(経路探索、ダメージ計算、ステートマシン)をカバーしている
- 決定論的な動作を固定したうえで、主要な画面(メニュー、HUD)のビジュアルリグレッションテストを行う
imgdiff.py によるビジュアルリグレッション
スクリーンショットをピクセル単位で比較するには:
# Compare baseline to current
python scripts/imgdiff.py baseline.png current.png --out diff.png
# Allow small tolerance (anti-aliasing differences)
python scripts/imgdiff.py baseline.png current.png --max-rms 2.0
終了コード:0 = 一致、1 = 不一致、2 = エラー
UI スライスのリグレッション(ナインスライス/リボン/バー)
Canvas UI の問題(パネルの継ぎ目、分割されたリボン、見えない HUD の塗りつぶし)は、ゲームプレイ全体のフローではなく、専用の UI ハーネスを使うと見つけやすくなります。
- UI アセットのみを読み込むシンプルな
test.html/シーンを作成します。 - 生のスライスを組み立て済みパネルの隣に(複数のサイズで)描画し、「生の切り抜き+拡大縮小」と「複数スライスの結合」の両方の表示を含めて、リボン/バーも描画します。
.commands.showTest(n)を使って各モードを決定論的に切り替えられるよう、window.__TEST__を公開します。- 対象を絞ったスクリーンショット(パネル、リボン、バー)を取得し、CI で差分を確認します。
決定論的なセットアップとスクリーンショットのワークフローについては、references/phaser-canvas-testing.md を参照してください。
状況に応じた指針
状況に応じてアプローチを調整します:
- DOM アプリ:Playwright の標準セレクターを使い、テキスト/要素を待ちます
- Canvas ゲーム:テスト用の接点が必須です。
window.__TEST__.readyで待ちます - ハイブリッド:メニューには DOM を、ゲームプレイにはテスト用の接点を使います
- CI のみで GPU を使用:ソフトウェアレンダリングのフラグが必要になる場合があります。またはビジュアルテストをスキップします
- UI スライスのリグレッション:ナインスライス/リボン/バーの描画上の問題には、決定論的なモードと対象を絞ったスクリーンショットを備えた、小規模な UI ハーネスのシーン/ページを優先します(
references/phaser-canvas-testing.md)。
同梱リソース
必要に応じて、以下を参照してください:
references/playwright-mcp-cheatsheet.md:MCP ツールの詳細な使用パターンreferences/phaser-canvas-testing.md:Phaser ゲーム向けの決定論的モードreferences/flake-reduction.md:フレークの分類と修正方法
覚えておくこと
準備状態とアプリの状態を確認するための小さく安定した接点を追加すれば、Canvas/WebGL ゲームを含む、ほとんどあらゆるフロントエンドをテスト可能にできます。信頼できるスモークテストが基盤になります。保守の手間がかからないテストを目指しましょう。決定論的で、準備状態を明示し、失敗時の証拠が豊富なテストです。目標はカバレッジの数値ではなく、確信を得ることです。