Skip to main content

phaser-game-testing

Test Phaser games and canvas/WebGL applications with deterministic automation. Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y for Phaser 3 games. Use agent-browser CLI for browser automation, Vitest/Jest/RTL, flaky test triage, CI stabilization, and Phaser games needing deterministic input plus screenshot/state assertions. Trigger: "test phaser game", "phaser testing", "game testing", "canvas testing", "webgl testing", "test", "E2E", "flaky", "visual regression", "Playwright".

Quellinformationen

Repository
pmarashian/cursor-agent-skills
Letzte Quellaktivität
13. Februar 2026 um 19:51
Erkannte Sprache von SKILL.md
Englisch
Sterne
2
Forks
1

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
9 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
phaser-game-testing
description
Test Phaser games and canvas/WebGL applications with deterministic automation. Plan, implement, and debug frontend tests: unit/integration/E2E/visual/a11y for Phaser 3 games. Use agent-browser CLI for browser automation, Vitest/Jest/RTL, flaky test triage, CI stabilization, and Phaser games needing deterministic input plus screenshot/state assertions. Trigger: "test phaser game", "phaser testing", "game testing", "canvas testing", "webgl testing", "test", "E2E", "flaky", "visual regression", "Playwright".
# Phaser Game Testing Test Phaser 3 games reliably: enable safe refactors by choosing the right test layer, making canvas/WebGL games observable, and eliminating nondeterminism so failures are actionable. ## Philosophy: Confidence Per Minute Frontend tests fail for two reasons: the product is broken, or the test is lying. Your job is to maximize signal and minimize "test is lying". **Before writing a test, ask**: - What user risk am I covering (money, progression, auth, data loss, crashes)? - What's the narrowest layer that catches this bug class (pure logic vs UI vs full browser)? - What nondeterminism exists (time, RNG, async loading, network, animations, fonts, GPU)? - What "ready" signal can I wait on besides `setTimeout`? - What should a failure print/screenshot so it's diagnosable in CI? **Core principles**: 1. **Test the contract, not the implementation**: assert stable user-meaningful outcomes and public seams. 2. **Prefer determinism over retries**: make time/RNG/network controllable; remove flake at the source. 3. **Observe like a debugger**: console errors, network failures, screenshots, and state dumps on failure. 4. **One critical flow first**: a reliable smoke test beats 50 flaky tests. ## Unit Testing for Pure Logic **Decision Tree**: Is this pure logic? → Use unit tests, not browser automation. For pure logic utilities (maze generation, score sorting, storage, math algorithms), use **Vitest** for fast, deterministic unit tests. Reserve browser automation (agent-browser) for integration contracts and UI flows. ### What Should Be Unit Tested - ✅ **Maze generation algorithms** - Deterministic with seeded RNG - ✅ **Score sorting/validation** - Pure data transformations - ✅ **Storage utilities** - localStorage wrappers, serialization - ✅ **Math/algorithm utilities** - Pathfinding, damage calculations - ✅ **State management logic** - Reducers, state machines - ✅ **RNG utilities** - Seeded random number generators ### Vitest Setup Pattern ```bash npm install -D vitest @vitest/ui ``` ```typescript // vitest.config.ts import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { globals: true, environment: 'node', }, }); ``` ```json // package.json { "scripts": { "test": "vitest", "test:ui": "vitest --ui" } } ``` ### Workflow: Logic Changes 1. **Write unit test first** → Verify logic in isolation 2. **Run tests** → `npm test` 3. **Test in browser if needed** → Only for integration verification ### Anti-Pattern: Browser Automation for Pure Functions ❌ **Wrong**: Using agent-browser to test a maze generation function ```bash agent-browser eval "generateMaze(10, 10, 42)" ``` ✅ **Correct**: Unit test with Vitest ```typescript import { describe, it, expect } from 'vitest'; import { generateMaze } from './maze'; describe('generateMaze', () => { it('generates same maze with same seed', () => { const maze1 = generateMaze(10, 10, 42); const maze2 = generateMaze(10, 10, 42); expect(maze1).toEqual(maze2); }); }); ``` See `references/unit-testing-setup.md` for complete Vitest configuration and examples. ## Test Layer Decision Tree Pick the cheapest layer that provides needed confidence: | Layer | Speed | Use For | | ------------- | ----------- | --------------------------------------------------------------------------------- | | **Unit** | Fastest | Pure functions, reducers, validators, math, pathfinding, deterministic simulation | | **Component** | Medium | UI behavior with mocked IO (React Testing Library, Vue Testing Library) | | **E2E** | Slowest | Critical user flows across routing, storage, real bundling/runtime | | **Visual** | Specialized | Layout/pixel regressions; for canvas/WebGL, only after locking determinism | ## Quick Start: First Smoke Test 1. **Define 1 critical flow**: "page loads → user can start → one key action works" 2. **Add a test seam** to the app (see below) 3. **Choose runner**: agent-browser CLI for E2E, unit tests for logic 4. **Fail loudly**: treat console errors and failed requests as test failures 5. **Stabilize**: seed RNG, freeze time, fix viewport, disable animations ## Concrete agent-browser Workflow: Testing a Game Step-by-step sequence for testing a Phaser/canvas game: **Important**: For Phaser games, **skip `snapshot -i`** and use `window.__TEST__` directly. ``` 1. agent-browser open http://localhost:3000?test=1&seed=42 2. agent-browser eval "new Promise(r => { const c = () => window.__TEST__?.ready ? r(true) : setTimeout(c, 100); c(); })" (Wait for game ready) 3. agent-browser errors (Fail if any errors) 4. agent-browser eval "window.__TEST__.commands.goToScene('GameScene')" (Use test seam commands instead of DOM clicks) 5. agent-browser eval "window.__TEST__.gameState()" (Assert game state is correct) 6. agent-browser press ArrowRight (Or WASD for movement) 7. agent-browser eval "window.__TEST__.gameState().player.x" (Verify movement happened) 8. agent-browser screenshot gameplay-state.png (Visual evidence after deterministic setup) ``` **Note**: For DOM-based UI (menus, buttons), you may still use `snapshot -i` and `click @e1`, but prefer test seam commands when available. ## Standardized Test Seam Pattern **Important**: Agents should **skip `snapshot -i`** for Phaser games and go directly to `window.__TEST__`. The test seam provides all necessary access without DOM inspection. ### TestManager Singleton Pattern Use a centralized TestManager singleton for consistent test seam management across all scenes: ```javascript // utils/TestManager.js class TestManager { constructor() { this.ready = false; this.seed = null; this.sceneKey = null; this.scenes = new Map(); // sceneKey -> scene instance } registerScene(sceneKey, sceneInstance) { this.scenes.set(sceneKey, sceneInstance); this.sceneKey = sceneKey; } getCurrentScene() { return this.scenes.get(this.sceneKey); } gameState() { const scene = this.getCurrentScene(); if (!scene) return { scene: null }; return { scene: this.sceneKey, score: scene.gameState?.score || 0, timer: scene.gameState?.timer || 0, inventory: scene.gameState?.inventory || [], // Add scene-specific state via scene.getTestState() ...(scene.getTestState ? scene.getTestState() : {}) }; } commands = { clickStartGame: () => { const scene = this.getCurrentScene(); scene?.startGame?.(); }, collectCoin: (x, y) => { const scene = this.getCurrentScene(); scene?.collectCoin?.(x, y); }, goToScene: (key, data) => { const game = this.getCurrentScene()?.scene?.game; if (game) { game.scene.start(key, data); } } }; } // Initialize singleton window.__TEST__ = new TestManager(); ``` ### BaseScene Pattern Create a BaseScene class that automatically registers with TestManager: ```javascript // scenes/BaseScene.js export class BaseScene extends Phaser.Scene { constructor(config) { super(config); } create() { // Auto-register with TestManager if (window.__TEST__) { window.__TEST__.registerScene(this.scene.key, this); } // Scene-specific initialization this.initScene(); } // Override in subclasses initScene() {} // Override to provide scene-specific test state getTestState() { return {}; } } ``` ### Consistent `window.__TEST__` Structure All scenes should expose the same structure: ```javascript window.__TEST__ = { sceneKey: null, // Current active scene (managed by TestManager) ready: false, // true after first interactive frame seed: null, // current RNG seed gameState: () => ({ // JSON-serializable snapshot scene: window.__TEST__.sceneKey, score: gameState.score, timer: gameState.timer, inventory: gameState.inventory, // Scene-specific state added via getTestState() }), commands: { // Functional triggers (not raw Phaser API) clickStartGame: () => {}, collectCoin: (x, y) => {}, goToScene: (key, data) => {}, reset: () => {}, seed: (n) => {}, } }; ``` ### Anti-Pattern: Don't Implement `__TEST__` Individually ❌ **Wrong**: Each scene implements its own `window.__TEST__` structure ```javascript // In GameScene.js window.__TEST__ = { /* GameScene-specific */ }; // In MenuScene.js window.__TEST__ = { /* MenuScene-specific */ }; ``` ✅ **Correct**: Use TestManager + BaseScene for consistent structure ```javascript // All scenes extend BaseScene class GameScene extends BaseScene { getTestState() { return { player: { x: this.player.x, y: this.player.y } }; } } ``` ### Agent Workflow with Standardized Seams 1. **Skip DOM snapshots**: `agent-browser snapshot -i` is unnecessary 2. **Go directly to test seam**: `agent-browser eval "window.__TEST__.ready"` 3. **Use commands**: `agent-browser eval "window.__TEST__.commands.goToScene('GameScene')"` 4. **Check state**: `agent-browser eval "window.__TEST__.gameState()"` See `references/test-seam-standardization.md` for complete implementation guide. ## Recommended Test Seams (Legacy Pattern) For projects not yet using TestManager, the basic pattern still works: ```javascript 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: () => {}, }, }; ``` **Rule**: Expose IDs + essential fields, not raw Phaser/engine objects. **Note**: Prefer the TestManager pattern above for new projects. ## Anti-Patterns to Avoid ❌ **Testing the wrong layer**: E2E tests for pure logic _Why tempting_: "Let's just test everything through the browser" _Better_: Unit tests for logic; reserve E2E for integration contracts ❌ **Testing implementation details**: Asserting DOM structure/classnames _Why tempting_: Easy to assert what you can see in DevTools _Better_: Assert user-meaningful outputs (text, score, HP changes) ❌ **Sleep-driven tests**: `wait 2s then click` _Why tempting_: Simple and "works on my machine" _Better_: Wait on explicit readiness (DOM marker, `window.__TEST__.ready`) ❌ **Uncontrolled randomness**: RNG/time in assertions _Why tempting_: "The game uses random, so the test should too" _Better_: Seed RNG (`?seed=42`), freeze time, assert stable invariants ❌ **Pixel snapshots without determinism**: Canvas screenshots that flake _Why tempting_: "I'll catch visual bugs automatically" _Better_: Deterministic mode first; then screenshot at known stable frames ❌ **Retries as a strategy**: "Just bump retries to 3" _Why tempting_: Quick fix that makes CI green _Better_: Fix the flake source; retries hide real problems ## Debugging Failed Tests When a test fails, gather evidence in this order: 1. **Console errors**: `agent-browser errors` or `agent-browser console` 2. **Network failures**: `agent-browser network requests` → check for non-2xx 3. **Screenshot**: `agent-browser screenshot failure-state.png` → visual state at failure 4. **App state**: `agent-browser eval "window.__TEST__.state()"`
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen