Files
restitution/tests/e2e/combat-loop.spec.js
kaykayyali 804aec6a11 M2.4: combat loop e2e + unit data fields
- Unit.js: add health/armor to entity data
- CombatSystem.js: integration hooks for M2 combat loop
- EntityStateMachine.js: orchestrator.registerEntity refactor
- playwright.config.js: M2 e2e config
- tests/e2e/combat-loop.{spec,e2e}.js: M2 combat loop verification
- tests/e2e/milestone-2-combat-loop.spec.js: M2 acceptance test
- .gitignore: exclude debug scripts + screenshots from commits
2026-06-27 16:44:41 +00:00

103 lines
3.9 KiB
JavaScript

import { test, expect } from '@playwright/test';
test('M2 combat loop — spawn, auto-engage, projectiles, death', async ({ page }) => {
const url = process.env.RESTITUTION_URL || 'https://restitution.damascusfront.net';
// ── 1. Boot ──
await page.goto(url, { waitUntil: 'networkidle', timeout: 30000 });
await page.waitForTimeout(2000);
// Lobby: click CREATE GAME → wait for code → click Start Game
await page.click('button:has-text("CREATE GAME")');
await page.waitForTimeout(3000);
await page.waitForSelector('button:has-text("Start Game")', { timeout: 10000 });
await page.click('button:has-text("Start Game")');
// Wait for Phaser canvas
await page.waitForSelector('canvas', { timeout: 15000 });
await page.waitForTimeout(3000);
// ── 2. Spawn player unit (F) ──
await page.keyboard.press('KeyF');
await page.waitForTimeout(800);
// ── 3. Spawn enemy via evaluate near player ──
const enemySpawned = await page.evaluate(() => {
const scene = window.game?.scene?.getScene('Map_Player');
if (!scene) return { ok: false, reason: 'no_scene' };
// Get player position (team-A unit closest to camera center)
const tm = scene.teamManager;
const playerUnits = tm?.getTeamUnits('team-A');
const playerUnit = playerUnits ? Array.from(playerUnits)[0] : null;
if (!playerUnit) return { ok: false, reason: 'no_player_unit' };
// Spawn enemy infantry on team-B, 5 tiles east of player
const tileX = Math.round(playerUnit.x / 32) + 5;
const tileY = Math.round(playerUnit.y / 32);
const enemy = scene.unitFactory?.spawnInfantry({ x: tileX, y: tileY }, 'team-B');
return { ok: !!enemy, enemyId: enemy?.name || null, tileX, tileY };
});
expect(enemySpawned.ok, `Enemy spawn failed: ${enemySpawned.reason}`).toBe(true);
await page.waitForTimeout(1500);
// ── 4. Screenshot: units spawned ──
await page.screenshot({ path: '/root/restitution/e2e-screenshots/01_spawned.png', fullPage: false });
// ── 5. Verify both sides exist via TeamManager ──
const bothSides = await page.evaluate(() => {
const tm = window.game?.scene?.getScene('Map_Player')?.teamManager;
if (!tm) return false;
const all = tm.getAllUnitsGrouped();
let hasA = false, hasB = false;
for (const [teamId, set] of all) {
if (set.size > 0) {
if (teamId === 'team-A') hasA = true;
if (teamId === 'team-B') hasB = true;
}
}
return hasA && hasB;
});
expect(bothSides).toBe(true);
// ── 6. Wait for combat to tick, verify projectiles ──
await page.waitForTimeout(4000);
const projectilesExist = await page.evaluate(() => {
const combat = window.game?.scene?.getScene('Map_Player')?.orchestrator?.systems?.combat;
if (!combat) return false;
const count = combat.projectiles?.countActive?.() ?? 0;
return count > 0;
});
expect(projectilesExist).toBe(true);
// ── 7. Screenshot: mid-combat ──
await page.screenshot({ path: '/root/restitution/e2e-screenshots/02_mid_combat.png', fullPage: false });
// ── 8. Let combat run, wait for death ──
await page.waitForTimeout(10000);
const deathCheck = await page.evaluate(() => {
const tm = window.game?.scene?.getScene('Map_Player')?.teamManager;
if (!tm) return { ok: false, reason: 'no_tm' };
const all = tm.getAllUnitsGrouped();
let alive = 0, dead = 0;
const aliveNames = [], deadNames = [];
for (const [, set] of all) {
for (const u of set) {
const isDead = u.dead || (typeof u.isDead === 'function' && u.isDead());
if (isDead) { dead++; deadNames.push(u.name || 'unknown'); }
else { alive++; aliveNames.push(u.name || 'unknown'); }
}
}
return { alive, dead, aliveNames, deadNames };
});
expect(deathCheck.dead).toBeGreaterThanOrEqual(1);
// ── 9. Screenshot: post-death ──
await page.screenshot({ path: '/root/restitution/e2e-screenshots/03_post_death.png', fullPage: false });
});