Files
Flight-Ops/lib/useSimClock.test.ts
2026-09-23 08:09:29 +00:00

47 lines
2.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from 'vitest';
import { advanceSimClock, type SimClockAnchor } from './useSimClock';
import { WORLD_TIME_SCALE } from './worldClock';
// ISS-007 (v0.16.1) — the pure extrapolation core of lib/useSimClock.ts. The hook itself is a
// thin setInterval + re-sync wrapper covered by e2e (panes.spec.ts "ticks smoothly between polls");
// this suite pins the math: game time advances real-time × WORLD_TIME_SCALE while something is
// flying or in repair, and stays frozen at the anchor value while fully grounded (#135).
const anchor = (over: Partial<SimClockAnchor> = {}): SimClockAnchor => ({
clockMs: 1_750_000_000_000,
at: 1_000_000,
advancing: true,
...over,
});
describe('advanceSimClock', () => {
it('advances by exactly elapsed real-time × WORLD_TIME_SCALE while running', () => {
expect(advanceSimClock(anchor(), 1_001_000)).toBe(1_750_000_000_000 + 1_000 * WORLD_TIME_SCALE);
// The e2e scenario: ~2.6 s real at the fixed world rate.
expect(advanceSimClock(anchor(), 1_002_600)).toBe(1_750_000_000_000 + 2_600 * WORLD_TIME_SCALE);
});
it('returns the anchor value exactly at zero elapsed', () => {
expect(advanceSimClock(anchor(), 1_000_000)).toBe(1_750_000_000_000);
});
it('stays exactly at the anchor value while grounded (frozen, #135)', () => {
const a = anchor({ advancing: false });
expect(advanceSimClock(a, 1_000_000)).toBe(1_750_000_000_000); // zero elapsed — the anchor value
expect(advanceSimClock(a, 1_001_000)).toBe(1_750_000_000_000); // a full second later — still frozen
});
it('clamps to the anchor value when nowMs is before the anchor (clock skew), never backwards', () => {
expect(advanceSimClock(anchor(), 999_999)).toBe(1_750_000_000_000);
expect(advanceSimClock(anchor({ advancing: false }), 999_999)).toBe(1_750_000_000_000);
});
it('mirrors the server tick model (tickOnce): advance = elapsed × WORLD_TIME_SCALE while actively polled', () => {
// lib/sim/engine.ts: clockMs += min(now − lastRealTickMs, MAX_TICK_ELAPSED_MS) × timeScale.
// For gaps under the 2 s clamp the client extrapolation is exactly the server's own formula.
for (const gap of [1, 250, 999, 1_999]) {
expect(advanceSimClock(anchor(), 1_000_000 + gap)).toBe(1_750_000_000_000 + gap * WORLD_TIME_SCALE);
}
});
});