v0.62.0: fixed 24x world clock — frozen when fully grounded (#135)
CI / build + unit + e2e (pull_request) Successful in 14m3s
CI / build + unit + e2e (pull_request) Successful in 14m3s
This commit is contained in:
+9
-21
@@ -1,15 +1,14 @@
|
||||
import { test, expect, type Page } from '@playwright/test';
|
||||
|
||||
// v0.52.0 (ISS-117) fixed world clock against the live origin: a fully grounded fleet slowing to
|
||||
// real time instead of freezing (ISS-128), background-tick advance at a raised rate while
|
||||
// something is active, package expiry via the FLIGHT_TEST_HOOKS hooks (enabled in docker-compose.yml),
|
||||
// and market top-up.
|
||||
// v0.52.0 (ISS-117), finalized in #135: fixed world clock against the live origin — a fully
|
||||
// grounded fleet freezes the clock, background-tick advance at a raised rate while something is
|
||||
// active, package expiry via the FLIGHT_TEST_HOOKS hooks (enabled in docker-compose.yml), and
|
||||
// market top-up.
|
||||
|
||||
// Must match lib/sim/engine.ts — kept in sync manually (same pattern as MIN_ZOOM/MAX_ZOOM in map.spec.ts).
|
||||
const MAX_TICK_ELAPSED_MS = 2_000;
|
||||
const SCALE = 1000; // test rate for fast-forwarding legs
|
||||
const WORLD = 24; // the fixed world rate (ISS-117) — must match lib/worldClock.ts
|
||||
const IDLE = 1; // the idle real-time rate (ISS-128) — must match IDLE_WORLD_TIME_SCALE in lib/worldClock.ts (= WORLD / 24)
|
||||
const MAX_DELTA_PER_TICK = MAX_TICK_ELAPSED_MS * SCALE; // 2_000_000 game ms per tick at scale 1000
|
||||
// Must match MARKET_TARGET_OPEN_PACKAGES in lib/game/seed.ts.
|
||||
const MARKET_TARGET = 10;
|
||||
@@ -48,10 +47,9 @@ async function setHealth(page: Page, planeId: string, fields: Record<string, unk
|
||||
expect(res.status()).toBe(200);
|
||||
}
|
||||
|
||||
// A fully grounded fleet only advances at the idle real-time rate (ISS-128) — put the starter in
|
||||
// repair so the clock runs at FULL scale for tests that need fast-forwarding. The €1.5k repair
|
||||
// cost is irrelevant to every spec's relative cash assertions; deactivateWorld restores full health
|
||||
// and no gate afterwards.
|
||||
// A fully grounded fleet freezes the world clock (#135) — put the starter in repair so the clock
|
||||
// runs at FULL scale for tests that need fast-forwarding. The €1.5k repair cost is irrelevant to
|
||||
// every spec's relative cash assertions; deactivateWorld restores full health and no gate afterwards.
|
||||
async function activateWorld(page: Page): Promise<void> {
|
||||
await setHealth(page, STARTER, { health: 50 });
|
||||
expect((await page.request.post(`/api/planes/${STARTER}/repair`)).status()).toBe(200);
|
||||
@@ -73,25 +71,15 @@ test.afterEach(async ({ page }) => {
|
||||
await setScale(page, WORLD);
|
||||
});
|
||||
|
||||
test('a fully grounded fleet slows the clock to real time instead of freezing it (ISS-128)', async ({ page }) => {
|
||||
test('a fully grounded fleet freezes the world clock (#135)', async ({ page }) => {
|
||||
const s = await getState(page);
|
||||
expect(s.planes.every((p) => p.status === 'available'), 'fleet should be grounded at spec start').toBe(true);
|
||||
|
||||
const t0 = Date.now();
|
||||
const c0 = s.simState.clockMs;
|
||||
await sleep(2_500); // ~2.5 s of real idleness — several background ticks plus the reads below
|
||||
const after = await getState(page);
|
||||
const elapsedReal = Date.now() - t0;
|
||||
|
||||
const delta = after.simState.clockMs - c0;
|
||||
expect(delta, 'the idle clock must advance (no longer frozen)').toBeGreaterThan(0);
|
||||
// ≈ real time: each tick counts min(gap, MAX_TICK_ELAPSED_MS) × IDLE rate, so the total can only fall
|
||||
// short of the wall span when a tick gap was clamped — worst case is one clamped idle-rate tick.
|
||||
expect(delta).toBeGreaterThanOrEqual(Math.min(elapsedReal * IDLE * 0.5, MAX_TICK_ELAPSED_MS * IDLE));
|
||||
// …and never more than the wall span itself (plus one clamp of pre-read downtime for slow boxes)…
|
||||
expect(delta).toBeLessThanOrEqual(elapsedReal + MAX_TICK_ELAPSED_MS);
|
||||
// …which is clearly below the full world rate: at ×24 this window would be ≥ ~60 game seconds.
|
||||
expect(delta).toBeLessThan(elapsedReal * WORLD);
|
||||
expect(after.simState.clockMs - c0, 'the grounded clock must stay frozen').toBe(0);
|
||||
});
|
||||
|
||||
test('timeScale 1000 advances the clock by roughly real-time × 1000 between polls', async ({ page }) => {
|
||||
|
||||
Reference in New Issue
Block a user