Fix e2e specs for fixed world clock: idle-pause expiry window, scale-1 motion settle, self-heal (ISS-117)
CI / build + unit + e2e (pull_request) Successful in 12m44s
CI / build + unit + e2e (pull_request) Successful in 12m44s
This commit is contained in:
+35
-1
@@ -4,6 +4,8 @@ import { test, expect, type Page } from '@playwright/test';
|
||||
// The panes render from the shell's single /api/state poll (lib/useGameState.ts).
|
||||
|
||||
const WORLD = 24; // the fixed world rate (ISS-117) — must match lib/worldClock.ts
|
||||
const SCALE = 1000; // test rate for fast-forwarding legs (self-heal only)
|
||||
const HUB = 'EDDF'; // must match HUB_ICAO in lib/game/seed.ts
|
||||
const STARTER = 'plane-starter';
|
||||
|
||||
interface StateBody {
|
||||
@@ -51,6 +53,34 @@ async function deactivateWorld(page: Page): Promise<void> {
|
||||
.toBe('available');
|
||||
}
|
||||
|
||||
// Self-heal helper (same pattern as e2e/actions.spec.ts): let any in-flight leg finish and
|
||||
// reposition plane-starter home via the API — an interrupted earlier run can leave it mid-flight,
|
||||
// and repairPlane 409s on non-available planes, which would break activateWorld.
|
||||
async function flyHomeViaApi(page: Page): Promise<void> {
|
||||
// v0.39.0 (ISS-069): wear accumulates across the shared CI DB — restore full health and clear any
|
||||
// active repair gate from an interrupted run before acting on the starter.
|
||||
expect((await page.request.post('/api/test/set-health', { data: { planeId: STARTER, health: 100, repairUntilMs: 0 } })).status()).toBe(200);
|
||||
let s = await getState(page); // ticks — a shortened gate flips the plane back to available here
|
||||
let plane = (s.planes.find((p) => p.id === STARTER) ?? {}) as { status?: string; locationIcao?: string };
|
||||
if (plane.status === 'flying' || plane.locationIcao !== HUB) {
|
||||
// Fast-forward any leftover leg / repositioning flight (~20 s real time worst case at 1000×).
|
||||
await setScale(page, SCALE);
|
||||
}
|
||||
if (plane.status === 'flying') {
|
||||
// While flying, locationIcao stays at the DEPARTURE airport — re-read state after landing.
|
||||
await expect.poll(async () => ((await getState(page)).planes.find((p) => p.id === STARTER)?.status ?? ''), { timeout: 240_000 }).toBe('available');
|
||||
s = await getState(page);
|
||||
plane = (s.planes.find((p) => p.id === STARTER) ?? {}) as { status?: string; locationIcao?: string };
|
||||
}
|
||||
if (plane.locationIcao !== HUB) {
|
||||
// Make sure the world rate is back at SCALE so the return leg fast-forwards.
|
||||
await setScale(page, SCALE);
|
||||
const res = await page.request.post(`/api/planes/${STARTER}/fly`, { data: { destIcao: HUB } });
|
||||
expect(res.ok()).toBeTruthy(); // repositioning needs no package (v0.12.0 manual flight)
|
||||
await expect.poll(async () => ((await getState(page)).planes.find((p) => p.id === STARTER)?.locationIcao ?? ''), { timeout: 240_000 }).toBe(HUB);
|
||||
}
|
||||
}
|
||||
|
||||
// Leave the live instance in a sane state for the other specs (the fixed world rate) — same
|
||||
// pattern as e2e/sim.spec.ts.
|
||||
test.afterEach(async ({ page }) => {
|
||||
@@ -111,7 +141,11 @@ test('left pane renders wallet, reputation and the starter fleet at Frankfurt',
|
||||
});
|
||||
|
||||
test('sim clock ticks smoothly between polls at the fixed world rate (ISS-007, ISS-117)', async ({ page }) => {
|
||||
test.setTimeout(60_000);
|
||||
test.setTimeout(300_000); // self-heal (worst case ~260 s at 1000×) + clock sampling
|
||||
// Self-heal first: an interrupted earlier run can leave the starter mid-flight, and repairPlane
|
||||
// 409s on non-available planes — it must be grounded before activateWorld.
|
||||
await flyHomeViaApi(page);
|
||||
await setScale(page, WORLD); // self-heal may have left the fast test rate behind
|
||||
// Idle-pause freezes a grounded fleet — put the starter in repair so the clock advances.
|
||||
await activateWorld(page);
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user