CI / build + unit + e2e (pull_request) Failing after 12m10s
The world always runs at WORLD_TIME_SCALE = 24 (lib/worldClock.ts). A server
background tick (instrumentation.ts -> startBackgroundTick, 1 s interval)
advances the sim with no open browser; idle-pause freezes the clock exactly
while no plane is flying or in repair. Fresh worlds start year 2000
(STARTING_CLOCK_MS in seed.ts).
- Removed: POST /api/sim + OpenAPI entry, applyTimeControls/clampTimeScale,
lib/timeScale.ts, LeftPane pause button + scale slider machinery,
ISS-057 slow-on-landing/resume in flyPlane.
- Snapshot simState is now { clockMs } only; client extrapolates at the fixed
rate between polls and freezes while idle (useSimClock).
- New test-only hook POST /api/test/set-timescale behind FLIGHT_TEST_HOOKS=1
(sibling of set-health); all e2e setScale helpers call it, afterEach restores
the world rate. E2E pause tests replaced by idle-pause assertions; sim.spec.ts
activates the world via set-health + /repair for advance/expiry tests.
48 lines
2.0 KiB
TypeScript
48 lines
2.0 KiB
TypeScript
import { setTestTimeScale } from '@/lib/sim/engine';
|
|
|
|
// TEST-ONLY hook (v0.52.0, ISS-117) — lets the e2e suite override the effective time scale now
|
|
// that there are no player-facing controls; without it every spec would run at the fixed world
|
|
// rate and a cross-Europe leg would take hours of real time. Disabled unless FLIGHT_TEST_HOOKS=1
|
|
// (set in docker-compose.yml for the e2e instance only); every other deployment 404s here.
|
|
// Sibling of /api/test/set-health — same gate, same conventions.
|
|
//
|
|
// POST /api/test/set-timescale
|
|
// body { timeScale: number } — a finite number in [1, 100_000] (400 otherwise).
|
|
// Ticks first so the write lands on current game state, under the sim lock.
|
|
// Returns { clockMs, timeScale } — the new effective scale for test assertions.
|
|
|
|
export async function POST(req: Request) {
|
|
if (process.env.FLIGHT_TEST_HOOKS !== '1') {
|
|
return Response.json({ error: 'test hooks disabled' }, { status: 404 });
|
|
}
|
|
|
|
let body: unknown = {};
|
|
try {
|
|
const text = await req.text();
|
|
body = text ? JSON.parse(text) : {};
|
|
} catch {
|
|
return Response.json({ error: 'invalid JSON body' }, { status: 400 });
|
|
}
|
|
if (typeof body !== 'object' || body === null || Array.isArray(body)) {
|
|
return Response.json({ error: 'body must be a JSON object' }, { status: 400 });
|
|
}
|
|
const input = body as Record<string, unknown>;
|
|
for (const key of Object.keys(input)) {
|
|
if (key !== 'timeScale') {
|
|
return Response.json({ error: `unknown field "${key}"` }, { status: 400 });
|
|
}
|
|
}
|
|
const timeScale = input.timeScale;
|
|
if (typeof timeScale !== 'number' || !Number.isFinite(timeScale) || timeScale < 1 || timeScale > 100_000) {
|
|
return Response.json({ error: 'timeScale must be a finite number in [1, 100000]' }, { status: 400 });
|
|
}
|
|
|
|
try {
|
|
const row = await setTestTimeScale(timeScale);
|
|
return Response.json({ clockMs: row.clockMs, timeScale: row.timeScale });
|
|
} catch (err) {
|
|
console.error('test hook failed', err);
|
|
return Response.json({ error: 'test hook failed' }, { status: 500 });
|
|
}
|
|
}
|