import { describe, it, expect } from 'vitest'; import { InMemoryStateStore } from '../src/store.js'; import type { UniverseSnapshot } from '@kerbal-rt/shared-types'; function makeSnapshot(ut: number, vesselId = 'v-1'): UniverseSnapshot { return { ut, capturedAt: new Date().toISOString(), activeVesselId: vesselId, bodies: [ { id: 'kerbin', name: 'Kerbin', kind: 'planet', parentId: 'kerbol', radius: 600_000, sphereOfInfluence: 84_159_286, gravitationalParameter: 3.5316e12, rotationPeriod: 21_600, axialTilt: 0, orbit: { semiMajorAxis: 13_599_840_256, eccentricity: 0, inclination: 0, longitudeOfAscendingNode: 0, argumentOfPeriapsis: 0, meanAnomalyAtEpoch: 0, epoch: 0, }, }, ], vessels: [ { id: vesselId, name: 'Test', type: 'Probe', owner: 'KASA', situation: 'ORBITING', status: 'ACTIVE', orbit: { semiMajorAxis: 7e6, eccentricity: 0, inclination: 0, longitudeOfAscendingNode: 0, argumentOfPeriapsis: 0, meanAnomalyAtEpoch: 0, epoch: 0, }, referenceBodyId: 'kerbin', createdAt: '2026-01-01T00:00:00Z', retiredAt: null, }, ], groundStations: [], }; } describe('InMemoryStateStore', () => { it('starts empty', async () => { const store = new InMemoryStateStore(); expect(await store.latestSnapshot()).toBeNull(); expect(await store.listVessels()).toEqual([]); }); it('stores and returns snapshots', async () => { const store = new InMemoryStateStore(); await store.applySnapshot(makeSnapshot(100)); const snap = await store.latestSnapshot(); expect(snap).not.toBeNull(); expect(snap!.ut).toBe(100); }); it('looks up vessels by id', async () => { const store = new InMemoryStateStore(); await store.applySnapshot(makeSnapshot(1, 'kasa-1')); const v = await store.getVessel('kasa-1'); expect(v?.name).toBe('Test'); expect(await store.getVessel('missing')).toBeNull(); }); it('overwrites on subsequent snapshots', async () => { const store = new InMemoryStateStore(); await store.applySnapshot(makeSnapshot(1)); await store.applySnapshot(makeSnapshot(2)); expect((await store.latestSnapshot())!.ut).toBe(2); }); it('notifies subscribers when a snapshot is applied', async () => { const store = new InMemoryStateStore(); const seen: number[] = []; const unsub = await store.subscribe((snap) => seen.push(snap.ut)); await store.applySnapshot(makeSnapshot(1)); // allow microtask to flush await new Promise((r) => setTimeout(r, 10)); await store.applySnapshot(makeSnapshot(2)); await new Promise((r) => setTimeout(r, 10)); expect(seen).toEqual([1, 2]); await unsub(); await store.applySnapshot(makeSnapshot(3)); await new Promise((r) => setTimeout(r, 10)); expect(seen).toEqual([1, 2]); // unsub'd }); });