| name | stress-test-game |
| description | End-to-end stress test for City Tycoon game using Playwright. Tests placing roads, power plants, water towers, interacting with NPC proposals (accept/reject/counter), and verifying construction progress. Use when you need to QA test the game, verify game features work correctly, or run a smoke test after changes. |
Game Stress Test Skill
Overview
This skill performs end-to-end testing of the City Tycoon game using Playwright. It tests both UI interactions (clicking buttons, modals) and game logic (state changes, proposals).
Testing Philosophy
- Use Playwright clicks for all UI interactions (buttons, modals, canvas)
- Use Debug API for inspection (get state, get proposals) and time advancement
- This ensures both the UI and logic are working correctly together
Prerequisites
- Dev server running at
http://localhost:3000
- MCP Playwright plugin enabled
Debug API Reference
In development mode, window.__GAME_DEBUG__ provides:
getState(): GameState
getProposals(): Proposal[]
advanceTicks(n: number): void
setCash(amount: number): void
Test Workflow
Step 1: Setup & Navigation
-
Navigate to the game:
Use browser_navigate to go to http://localhost:3000
-
Take a snapshot to verify the game loaded:
Use browser_snapshot to capture the accessibility tree
-
Verify these elements are present:
- Cash display (e.g., "$10,000" or "$10.0K")
- Day counter (e.g., "Day 1")
- Speed control buttons (pause, 1x, 2x, 3x)
- Toolbar with tool buttons
-
Verify Debug API is available:
await page.evaluate(() => !!window.__GAME_DEBUG__);
Pass criteria: All UI elements visible, Debug API available
Step 2: Tool Selection & Tile Placement (UI Clicks)
Test that clicking toolbar buttons and canvas actually places tiles.
2.1 Place a Road (UI)
-
Get initial cash via Debug API:
await page.evaluate(() => window.__GAME_DEBUG__.getState().cash);
-
Click the Road tool button:
Use browser_click on the Road button (🛣️ Road $50)
-
Click on canvas to place road at a grass tile:
async (page) => {
const canvas = await page.locator('canvas').first();
const box = await canvas.boundingBox();
const centerX = box.width / 2;
const centerY = box.height / 2;
const gridX = 3, gridY = 12;
const screenX = (gridX - gridY) * 32 + centerX;
const screenY = (gridX + gridY) * 19.2 + centerY;
await page.mouse.click(box.x + screenX, box.y + screenY);
}
-
Verify cash decreased via Debug API:
await page.evaluate(() => window.__GAME_DEBUG__.getState().cash);
Pass criteria: Cash decreased by $50 after UI click
2.2 Place Power Plant (UI)
- Click Power Plant button (⚡ Power $500)
- Click canvas at tile (4, 12)
- Verify cash decreased by $500
2.3 Place Water Tower (UI)
- Click Water Tower button (💧 Water $300)
- Click canvas at tile (3, 13)
- Verify cash decreased by $300
Total spent: $850 ($50 + $500 + $300)
Step 3: Speed Controls (UI Clicks)
3.1 Test Pause Button
- Get current day via Debug API
- Click pause button (⏸️) via browser_click
- Wait 2 seconds
- Verify day hasn't changed
3.2 Test 3x Speed Button
- Note current day
- Click 3x speed button (▶▶▶) via browser_click
- Wait 3 seconds
- Verify day has advanced
Pass criteria: UI buttons control game speed correctly
Step 4: NPC Proposals (UI + Debug API)
4.1 Generate Proposals (Debug API for speed)
-
Advance time to generate proposals:
await page.evaluate(() => {
const debug = window.__GAME_DEBUG__;
debug.advanceTicks(100);
return debug.getProposals().length;
});
-
If no proposals, advance more ticks and retry
Pass criteria: At least one proposal exists
4.2 Open Proposal Modal (UI Click)
-
Get proposal info via Debug API:
await page.evaluate(() => {
const debug = window.__GAME_DEBUG__;
const proposals = debug.getProposals();
return proposals[0];
});
-
Click Select tool button via browser_click
-
Click on the proposal's tile on canvas:
async (page) => {
const canvas = await page.locator('canvas').first();
const box = await canvas.boundingBox();
const centerX = box.width / 2;
const centerY = box.height / 2;
const screenX = (gridX - gridY) * 32 + centerX;
const screenY = (gridX + gridY) * 19.2 + centerY;
await page.mouse.click(box.x + screenX, box.y + screenY);
}
-
Take snapshot - verify ProposalModal appears with Accept/Counter/Reject buttons
Pass criteria: Modal opens showing proposal details
4.3 Test Accept Button (UI Click)
- Get cash before via Debug API
- Click "Accept" button in modal via browser_click
- Take snapshot - verify modal closed
- Get cash after via Debug API
- Verify cash increased by offer amount
- Verify building placed on grid:
await page.evaluate(() => {
const debug = window.__GAME_DEBUG__;
const state = debug.getState();
});
Pass criteria: Accept button works, cash increases, building placed
4.4 Test Reject Button (UI Click) - Optional
If another proposal exists:
- Open modal by clicking on proposal tile
- Click "Reject" button via browser_click
- Verify modal closes
- Verify proposal removed from pending list
4.5 Test Counter Flow (UI Click) - Optional
If another proposal exists:
- Open modal by clicking on proposal tile
- Click "Counter" button via browser_click
- Take snapshot - verify counter UI appears (slider, Send Offer button)
- Adjust slider if possible
- Click "Send Offer" button
- Verify outcome (accepted or rejected)
Step 5: Construction Progress
-
Find a building under construction via Debug API:
await page.evaluate(() => {
const debug = window.__GAME_DEBUG__;
const state = debug.getState();
for (let y = 0; y < state.gridSize; y++) {
for (let x = 0; x < state.gridSize; x++) {
const tile = state.grid[y][x];
if (tile.building && tile.building.constructionProgress < 100) {
return { x, y, progress: tile.building.constructionProgress };
}
}
}
return null;
});
-
Advance time via Debug API:
await page.evaluate(() => window.__GAME_DEBUG__.advanceTicks(100));
-
Check progress increased:
-
Continue until building completes (100%)
-
Take screenshot to verify completed building icon visible
Pass criteria: Construction progresses and completes
Results Summary
## Stress Test Results
### Step 1: Setup & Navigation
- [ ] Game loaded successfully
- [ ] All UI elements present
- [ ] Debug API available
### Step 2: Tool Placement (UI Clicks)
- [ ] Road button click works
- [ ] Road placed on canvas click ($50 deducted)
- [ ] Power Plant placed ($500 deducted)
- [ ] Water Tower placed ($300 deducted)
### Step 3: Speed Controls (UI Clicks)
- [ ] Pause button works
- [ ] 3x speed button works
### Step 4: NPC Proposals (UI + Debug)
- [ ] Proposals generate (debug API)
- [ ] Clicking proposal tile opens modal (UI)
- [ ] Accept button works (UI)
- [ ] Reject button works (UI) - optional
- [ ] Counter flow works (UI) - optional
### Step 5: Construction
- [ ] Building progresses over time
- [ ] Building completes at 100%
### Overall: X/Y tests passed
Coordinate Formula
For canvas clicks, use this isometric conversion:
const screenX = (gridX - gridY) * 32 + centerX;
const screenY = (gridX + gridY) * 19.2 + centerY;
Where:
centerX = canvasWidth / 2
centerY = canvasHeight / 2
- Known grass tiles: (3,12), (4,12), (3,13), (2,11), (5,11)
Troubleshooting
Canvas clicks not placing tiles
- Ensure correct tool is selected first (click tool button)
- Try different grass tile coordinates
- Verify tile isn't water via screenshot
Proposal modal not opening
- Use Debug API to get exact proposal tile coordinates
- Ensure Select tool is active
- Click directly on the proposal's tile position
Debug API not available
- Ensure
bun run dev (development mode)
- Check console for "[GameContext] Debug API available"