mcpField
G
game-qa

game-qa

github.com/hungifyテスト・品質016 回インストール1 週間前に更新
リポジトリ

game-qa について

ブラウザーゲーム向けのPlaywright QAスキルです。ゲームプレイ、画面、性能、アクセシビリティのテストパターンに加え、検査用にゲーム状態を公開する方法を紹介します。

主な機能

  1. 01ゲームプレイとスコアのテストパターン
  2. 02スクリーンショット回帰テスト
  3. 03性能とFPSの確認
  4. 04axeによるアクセシビリティテスト
  5. 05ゲーム状態の検査フック
  6. 06モバイル入力のテストパターン

活用シーン

  1. 01ゲームシーンとプレイヤー入力の検証
  2. 02画面変更前後のスクリーンショット確認
  3. 03性能基準とアクセシビリティのテスト
  4. 04状態データによるゲーム動作の検査

MCP 対応

付属ガイドでは、MCPサーバーの設定とスクリプトテストではなくMCPを使う場面を説明しています。視覚評価にMCPを使う方法も記載されています。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/hungify/playables-skills --skill game-qa

インストール後、Claude Code で/game-qaを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

clock-control.md
gameplay-invariants.md
iterate-client.md
mobile-tests.md
playwright-mcp.md
test-patterns.md
visual-regression.md

詳細

Playwright によるゲーム QA

ブラウザーゲームを専門とする QA エンジニアです。Playwright を使用して、ビジュアルの正確性、ゲームプレイの動作、パフォーマンス、アクセシビリティを検証する自動テストを作成します。

パフォーマンスに関する注意事項

  • 各手順には十分な時間をかけてください。速度より品質が重要です。
  • 検証手順を省略しないでください。問題を早期に発見できます。
  • 変更を加える前に、各ファイルの全体を確認してください。
  • ページが読み込まれることだけでなく、ゲームプレイを検証するテストを作成してください。

参考ファイル

詳細については、このディレクトリにある関連ファイルを参照してください。

  • test-patterns.md — カスタムフィクスチャコード、起動テスト、ゲームプレイ検証テスト、スコアリングテスト
  • gameplay-invariants.md — 7 つの主要なゲームプレイ不変条件パターンすべて(スコアリング、死亡、ボタン、render_game_to_text、デザイン意図、エンティティ監査、ミュート)
  • visual-regression.md — スクリーンショット比較テスト、動的要素のマスキング、パフォーマンス/FPS テスト、アクセシビリティテスト、決定論的テストのパターン
  • clock-control.md — フレーム単位で正確なテストを行うための Playwright Clock API パターン
  • playwright-mcp.md — MCP サーバーのセットアップ、MCP とスクリプトによるテストの使い分け、検査フロー
  • iterate-client.md — スタンドアロンの iterate クライアントの使い方、アクション JSON 形式、出力の解釈
  • mobile-tests.md — モバイル入力のシミュレーションとレスポンシブレイアウトのテストパターン

技術スタック

  • テストランナー:Playwright Test(@playwright/test)
  • ビジュアルリグレッション:Playwright 標準の toHaveScreenshot()
  • アクセシビリティ:@axe-core/playwright
  • ビルドツールとの統合:webServer 設定による Vite 開発サーバー
  • 言語:JavaScript ES モジュール

プロジェクトのセットアップ

ゲームプロジェクトに Playwright を追加する場合:

npm install -D @playwright/test @axe-core/playwright
npx playwright install chromium

package.json のスクリプトに追加します。

{
    "scripts": {
        "test": "npx playwright test",
        "test:ui": "npx playwright test --ui",
        "test:headed": "npx playwright test --headed",
        "test:update-snapshots": "npx playwright test --update-snapshots"
    }
}

必須のディレクトリ構成

tests/
├── e2e/
│   ├── game.spec.js       # Core game tests (boot, scenes, input, score)
│   ├── visual.spec.js     # Visual regression screenshots
│   └── perf.spec.js       # Performance and FPS tests
├── fixtures/
│   ├── game-test.js       # Custom test fixture with game helpers
│   └── screenshot.css     # CSS to mask dynamic elements for visual tests
├── helpers/
│   └── seed-random.js     # Seeded PRNG for deterministic game behavior
playwright.config.js

Playwright の設定

import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
    testDir: './tests',
    fullyParallel: true,
    forbidOnly: !!process.env.CI,
    retries: process.env.CI ? 2 : 0,
    workers: process.env.CI ? 1 : undefined,
    reporter: [['html', { open: 'never' }], ['list']],

    use: {
        baseURL: 'http://localhost:3000',
        trace: 'on-first-retry',
        screenshot: 'only-on-failure',
        video: 'retain-on-failure'
    },

    expect: {
        toHaveScreenshot: {
            maxDiffPixels: 200,
            threshold: 0.3
        }
    },

    projects: [
        { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
        { name: 'mobile-chrome', use: { ...devices['Pixel 5'] } }
    ],

    webServer: {
        command: 'npm run dev',
        url: 'http://localhost:3000',
        reuseExistingServer: !process.env.CI,
        timeout: 30000
    }
});

重要なポイント:

  • webServer はテストの前に Vite を自動起動します。
  • reuseExistingServer はローカルで実行中の開発サーバーを再利用します。
  • baseURL は vite.config.js で設定された Vite のポートに合わせます。
  • スクリーンショットの許容差は大きめに設定します(ゲームでは描画にわずかな差が生じるため)。

テスト可能にするための要件

Playwright でゲームの状態を検査できるように、ゲームは main.js 内で次のグローバル変数を window に公開する必要があります。

1. コアグローバル変数(必須)
// Expose for Playwright QA
window.__GAME__ = game;
window.__GAME_STATE__ = gameState;
window.__EVENT_BUS__ = eventBus;
window.__EVENTS__ = Events;
2. render_game_to_text()(必須)

AI エージェントがピクセルを解釈せずにゲームの状態を把握できるよう、現在のゲーム状態を簡潔な JSON 文字列で返します。座標系、ゲームモード、スコア、プレイヤーの状態を含める必要があります。

window.render_game_to_text = () => {
    if (!game || !gameState) return JSON.stringify({ error: 'not_ready' });

    const activeScenes = game.scene.getScenes(true).map((s) => s.scene.key);
    const payload = {
        coords: 'origin:top-left x:right y:down', // coordinate system
        mode: gameState.gameOver ? 'game_over' : 'playing',
        scene: activeScenes[0] || null,
        score: gameState.score,
        bestScore: gameState.bestScore
    };

    // Add player info when in gameplay
    const gameScene = game.scene.getScene('GameScene');
    if (gameState.started && gameScene?.player?.sprite) {
        const s = gameScene.player.sprite;
        const body = s.body;
        payload.player = {
            x: Math.round(s.x),
            y: Math.round(s.y),
            vx: Math.round(body.velocity.x),
            vy: Math.round(body.velocity.y),
            onGround: body.blocked.down
        };
    }

    // Extend with visible entities as you add them:
    // payload.entities = obstacles.map(o => ({ x: o.x, y: o.y, type: o.type }));

    return JSON.stringify(payload);
};

render_game_to_text() のガイドライン:

  • ペイロードは簡潔に保ちます。現在表示されている、操作可能な要素のみを含めます。
  • 座標系の注記(原点と軸の方向)を含めます。
  • プレイヤーの位置/速度、アクティブな障害物/敵、収集アイテム、タイマー、スコア、モードフラグを含めます。
  • 大量の履歴は避け、現在関連する情報のみを含めます。
  • iterate クライアントと AI エージェントは、スクリーンショットを使わずにゲームの動作を検証するためにこれを使用します。
3. advanceTime(ms)(必須)

テストスクリプトでゲームを正確な時間だけ進められるようにします。ゲームループは RAF で通常どおり実行され、実時間が経過するまで待機します。

window.advanceTime = (ms) => {
    return new Promise((resolve) => {
        const start = performance.now();
        function step() {
            if (performance.now() - start >= ms) return resolve();
            requestAnimationFrame(step);
        }
        requestAnimationFrame(step);
    });
};

@playwright/test でフレーム単位の正確な制御を行うには、page.clock.install() と page.clock.runFor() を使用してください。advanceTime フックは主にスタンドアロンの iterate クライアント(scripts/iterate-client.js)で使われます。

Three.js ゲームの場合も、同様に Game オーケストレーターのインスタンスを公開してください。

カスタムフィクスチャコード、起動テスト、ゲームプレイ検証テスト、スコアリングテストについては、test-patterns.md を参照してください。

7 つの主要なゲームプレイ不変条件パターンすべて(スコアリング、死亡、ボタン、render_game_to_text、デザイン意図、エンティティ監査、ミュート)については、gameplay-invariants.md を参照してください。

ゲームに QA を追加する場合

  1. Playwright をインストールします:npm install -D @playwright/test @axe-core/playwright && npx playwright install chromium
  2. ゲームの開発サーバーのポートを指定して playwright.config.js を作成します
  3. main.js で window.__GAME__、window.__GAME_STATE__、window.__EVENT_BUS__ を公開します
  4. gamePage フィクスチャを含む tests/fixtures/game-test.js を作成します
  5. 決定論的な動作を実現するために tests/helpers/seed-random.js を作成します
  6. tests/e2e/ にテストを記述します:
    • game.spec.js — 起動、シーン遷移、入力、スコアリング、ゲームオーバー
    • visual.spec.js — 各シーンのスクリーンショット回帰テスト
    • perf.spec.js — 読み込み時間、FPS の予算
  7. npm スクリプトを追加します:test、test:ui、test:headed、test:update-snapshots
  8. 初期ベースラインを生成します:npm run test:update-snapshots

自動テストの対象にしないもの

  • アニメーションするオブジェクトの正確なピクセル位置(クロックを制御しないと非決定的になります)
  • ゲームプレイ中のスクリーンショット — オブジェクトが動くため、安定したスクリーンショットを撮影できません。代わりに MCP を使用します
  • 音声の再生(Playwright では音声を検査できません。evaluate を使って音声オブジェクトが存在することをテストします)
  • モック化していない外部 API 呼び出し(例:Play.fun SDK — page.route() でモック化します)
  • 主観的なビジュアル品質 — 「見栄えがよいか」の評価には MCP を使用します

コメント