Pause on landing + auto-unpause on dispatch (ISS-041)
CI / build + unit + e2e (pull_request) Successful in 7m43s
CI / build + unit + e2e (pull_request) Successful in 7m43s
Replace the ISS-011 auto-slow with pause-on-landing: when the last plane
in flight lands, tickOnce sets sim_state.paused=true WITHOUT touching
timeScale (speed preserved). flyPlane() now clears paused before
persisting so starting a flight resumes a paused sim — inside runAction(),
tick + unpause + dispatch are atomic under the sim lock.
Tests: engine.test.ts auto-slow block rewritten for pause semantics; new
flyPlane test asserts dispatch clears paused with speed untouched. E2E:
auto-slow.spec.ts renamed to pause-on-landing.spec.ts asserting the new
behavior (paused=true AND timeScale still 1000 after landing; /fly clears
paused). Cross-cutting fix: every per-spec setScale helper now POSTs
{timeScale, paused:false} — a scale-only fast-forward after a landing would
otherwise leave the clock frozen. Deliberate mid-test pauses untouched.
This commit is contained in:
+17
-13
@@ -237,7 +237,7 @@ describe('deliverPackages (v0.12.0 arrival delivery)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('auto-slow to 1× when the last plane lands (ISS-011)', () => {
|
||||
describe('pause on landing when the last plane lands (ISS-041)', () => {
|
||||
const FROM = 'EDDF';
|
||||
const TO = 'LEMD';
|
||||
|
||||
@@ -259,19 +259,20 @@ describe('auto-slow to 1× when the last plane lands (ISS-011)', () => {
|
||||
return { inst, from, km, type };
|
||||
}
|
||||
|
||||
it('last plane lands → stored timeScale becomes 1', async () => {
|
||||
const { inst } = await setupLanding('autoslow-last.db', 1000);
|
||||
it('last plane lands → sim pauses and stored timeScale is UNCHANGED', async () => {
|
||||
const { inst } = await setupLanding('pause-last.db', 1000);
|
||||
vi.setSystemTime(T0 + 2_000); // one full clamped tick at scale 1000 → clock T0+2e6 ≥ arrival (T0)
|
||||
|
||||
const sim = await tickOnce(inst);
|
||||
|
||||
expect(sim.timeScale).toBe(1); // persisted on the sim_state row…
|
||||
expect((await inst.db.select().from(schema.simState))[0].timeScale).toBe(1); // …and visible to the next snapshot
|
||||
expect(sim.paused).toBe(true); // persisted on the sim_state row…
|
||||
expect((await inst.db.select().from(schema.simState))[0].paused).toBe(true); // …and visible to the next snapshot
|
||||
expect(sim.timeScale).toBe(1000); // speed preserved — no auto-slow anymore (ISS-041)
|
||||
expect((await inst.db.select().from(schema.planes))[0].status).toBe('available'); // landing itself unchanged
|
||||
});
|
||||
|
||||
it('a landing while another plane is still flying → no change', async () => {
|
||||
const { inst, from, type } = await setupLanding('autoslow-other.db', 1000);
|
||||
it('a landing while another plane is still flying → no pause', async () => {
|
||||
const { inst, from, type } = await setupLanding('pause-other.db', 1000);
|
||||
// A second plane on the same route departing at T0 — arrives far after this tick's clock.
|
||||
await inst.db.insert(schema.planes).values({
|
||||
id: 'p-b', model: 'atr72', status: 'flying', fuel: type.maxFuel, maxFuel: type.maxFuel,
|
||||
@@ -281,32 +282,35 @@ describe('auto-slow to 1× when the last plane lands (ISS-011)', () => {
|
||||
vi.setSystemTime(T0 + 2_000);
|
||||
const sim = await tickOnce(inst);
|
||||
|
||||
expect(sim.timeScale).toBe(1000); // p-b still in flight — no auto-slow
|
||||
expect(sim.paused).toBe(false); // p-b still in flight — no pause (nothing would auto-unpause it)
|
||||
expect(sim.timeScale).toBe(1000);
|
||||
const byId = new Map((await inst.db.select().from(schema.planes)).map((p) => [p.id, p.status]));
|
||||
expect(byId.get('plane-starter')).toBe('available'); // the starter did land…
|
||||
expect(byId.get('p-b')).toBe('flying'); // …but the fleet is not idle
|
||||
});
|
||||
|
||||
it('already at 1× → stays 1', async () => {
|
||||
const { inst } = await setupLanding('autoslow-one.db', 1);
|
||||
it('last plane lands at scale 1 → pauses anyway, scale untouched', async () => {
|
||||
const { inst } = await setupLanding('pause-one.db', 1);
|
||||
vi.setSystemTime(T0 + 2_000); // one tick at scale 1 advances 2e3 game ms — past the T0 arrival
|
||||
|
||||
const sim = await tickOnce(inst);
|
||||
|
||||
expect(sim.paused).toBe(true);
|
||||
expect(sim.timeScale).toBe(1);
|
||||
expect((await inst.db.select().from(schema.planes))[0].status).toBe('available');
|
||||
});
|
||||
|
||||
it('paused sim with all planes landed → no change', async () => {
|
||||
const inst = await freshDb('autoslow-paused.db');
|
||||
const inst = await freshDb('pause-paused.db');
|
||||
// The fleet is fully grounded (the seeded starter) — a paused tick must not touch the
|
||||
// scale even though "no plane in flight" holds: the trigger requires a landing this tick.
|
||||
// controls even though "no plane in flight" holds: the trigger requires a landing this tick.
|
||||
await inst.db.update(schema.simState).set({ timeScale: 1000, paused: true });
|
||||
|
||||
vi.setSystemTime(T0 + 5_000);
|
||||
const sim = await tickOnce(inst);
|
||||
|
||||
expect(sim.timeScale).toBe(1000); // no landing processed while paused → trigger never fires
|
||||
expect(sim.paused).toBe(true); // no landing processed while paused → trigger never fires
|
||||
expect(sim.timeScale).toBe(1000);
|
||||
expect((await inst.db.select().from(schema.planes))[0].status).toBe('available');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user