Files
gods-eye-view/src/data/satellitesTrackedRefresh.test.mjs
T
Bilawal Sidhu b6da93b8ac release: v0.1.0 — one-click install, keyless boot, in-app Provider Settings (#142)
The first formal release.

- One-click install via Pinokio; keyless boot lands on a live Esri World
  Imagery satellite globe with keyless terrain, with automatic OSM fallback
  and graceful degradation when terrain is unavailable.
- Provider Settings (the POWER UP panel): add, replace, or remove API keys
  inside the app; credential files made owner-only before any secret is
  written; external keys shown read-only; the panel refuses shared or proxied
  servers.
- Keyless capability responses for the optional HUD summary and place search.
- Aircraft-identity voice answers cover operator, type, and route, and say so
  plainly when enrichment is unavailable.
- README rewritten keyless-first; concise 0.1.0 changelog section; CI
  workflow included.

Gates: 2,672 unit tests pass / 0 fail, build clean, tracking regression
108/108, map-source tray QA pass, setup doctor ready.
2026-08-31 17:49:45 -05:00

341 lines
13 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import * as Cesium from 'cesium';
import { twoline2satrec } from 'satellite.js';
import {
ISS_OVERLAY_SOURCE_OPTIONS,
_applyPendingSatelliteTrackingRestoreForTest,
_clearSatelliteLabelLifecycleForTest,
_pendingSatelliteTrackingRestoreForTest,
_removeSatelliteTrackingCandidateForTest,
_runSatellitePreRenderForTest,
_setSatelliteLabelLifecycleStateForTest,
_setSatelliteTrackingRefreshOutcomeForTest,
_setTrackedSatelliteRefreshStateForTest,
_trackedFrameCartesianForTest,
_trackIssForTest,
createIssOverlayEntry,
} from './satellites.js';
import satellitesLayer from './satellites.js';
import { createTrackedOverlayEntry } from './trackedReadout.js';
const L1 = '1 25544U 98067A 08264.51782528 -.00002182 00000-0 -11606-4 0 2927';
const L2 = '2 25544 51.6416 247.4627 0006703 130.5360 325.0288 15.72125391563537';
test('partial and dense catalogs do not make an early false missing decision', async () => {
_setSatelliteTrackingRefreshOutcomeForTest({
status: 'partial',
failedGroups: ['stations.txt'],
});
const partial = await satellitesLayer.resolveTrackingRestoreTarget(987654);
assert.equal(partial.status, 'source-unavailable');
assert.match(partial.reason, /partial CelesTrak catalog/);
let releaseDense;
const densePromise = new Promise((resolve) => { releaseDense = resolve; });
_setSatelliteTrackingRefreshOutcomeForTest({
status: 'accepted',
catalog: 'dense',
densePromise,
});
let settled = false;
const resolution = satellitesLayer.resolveTrackingRestoreTarget(987654)
.then((result) => { settled = true; return result; });
await Promise.resolve();
assert.equal(settled, false, 'dense absence must wait for the dense catalog');
releaseDense({ status: 'ready' });
assert.equal((await resolution).status, 'missing');
_setSatelliteTrackingRefreshOutcomeForTest({ status: 'accepted', catalog: 'core' });
});
test('satellite first update aborts every parallel catalog request', async () => {
const realFetch = globalThis.fetch;
const observedSignals = [];
globalThis.fetch = (_url, options = {}) => new Promise((_resolve, reject) => {
observedSignals.push(options.signal);
options.signal?.addEventListener('abort', () => {
reject(new DOMException('aborted', 'AbortError'));
}, { once: true });
});
try {
const controller = new AbortController();
const work = satellitesLayer.update({}, { signal: controller.signal });
await Promise.resolve();
assert.ok(observedSignals.length > 1);
controller.abort();
await assert.rejects(work, { name: 'AbortError' });
assert.equal(observedSignals.every((signal) => signal?.aborted), true);
} finally {
globalThis.fetch = realFetch;
}
});
test('selected satellite params survive delayed arrival and yield to newer explicit intent', () => {
const point = {
position: Cesium.Cartesian3.fromDegrees(-97.7, 30.2, 420_000),
show: true,
pixelSize: 12,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
disableDepthTestDistance: 0,
};
const viewer = {
entities: new Cesium.EntityCollection(),
trackedEntity: undefined,
scene: {
frameState: { frameNumber: 1 },
primitives: { remove() {} },
},
};
_setSatelliteLabelLifecycleStateForTest({
viewer,
satrec: twoline2satrec(L1, L2),
point,
});
try {
assert.doesNotThrow(() => satellitesLayer.setParams({ selectedSatTrackingId: 25544 }));
assert.equal(satellitesLayer.getParams().selectedSatTrackingId, 25544);
assert.equal(viewer.trackedEntity?.gevTrackedId, 'satellites:25544');
satellitesLayer.stopTracking();
_removeSatelliteTrackingCandidateForTest(25544);
satellitesLayer.setParams(
{ selectedSatTrackingId: 25544 },
{ origin: 'share-restore' },
);
assert.equal(_pendingSatelliteTrackingRestoreForTest(), 25544);
_setSatelliteLabelLifecycleStateForTest({
viewer,
satrec: twoline2satrec(L1, L2),
point,
preservePending: true,
});
assert.equal(_applyPendingSatelliteTrackingRestoreForTest(), true);
assert.equal(satellitesLayer.getParams().selectedSatTrackingId, 25544);
satellitesLayer.setParams(
{ selectedSatTrackingId: 99999 },
{ origin: 'share-restore' },
);
assert.equal(_pendingSatelliteTrackingRestoreForTest(), 99999);
assert.equal(satellitesLayer.trackById(25544, { origin: 'user' }), true);
assert.equal(_pendingSatelliteTrackingRestoreForTest(), null, 'new user selection cancels stale restore');
_applyPendingSatelliteTrackingRestoreForTest();
assert.equal(satellitesLayer.getParams().selectedSatTrackingId, 25544);
satellitesLayer.stopTracking();
_removeSatelliteTrackingCandidateForTest(25544);
satellitesLayer.setParams(
{ selectedSatTrackingId: 25544 },
{ origin: 'local-restore' },
);
assert.equal(_pendingSatelliteTrackingRestoreForTest(), 25544);
satellitesLayer.stopTracking({ origin: 'user' });
assert.equal(_pendingSatelliteTrackingRestoreForTest(), null, 'explicit clear cancels stale restore');
_setSatelliteLabelLifecycleStateForTest({
viewer,
satrec: twoline2satrec(L1, L2),
point,
preservePending: true,
});
_applyPendingSatelliteTrackingRestoreForTest();
assert.equal(satellitesLayer.getParams().selectedSatTrackingId, null);
satellitesLayer.setParams(
{ selectedSatTrackingId: 50003 },
{ origin: 'share-restore' },
);
assert.equal(_pendingSatelliteTrackingRestoreForTest(), 50003);
satellitesLayer.setParams({ showPoints: true }, { origin: 'tool' });
assert.equal(
_pendingSatelliteTrackingRestoreForTest(),
null,
'a newer explicit non-selection option cancels stale restore',
);
_applyPendingSatelliteTrackingRestoreForTest();
assert.equal(satellitesLayer.getParams().selectedSatTrackingId, null);
} finally {
_clearSatelliteLabelLifecycleForTest();
}
});
test('a tracked docked cluster consolidates its companions onto one card', () => {
// ISS and everything berthed to it are separate real tracks at one position,
// so their ambient labels stack underneath the tracked card. Owner ruling:
// consolidate them as secondary info on that card, and suppress only those
// members — never unrelated satellites that merely happen to be nearby.
const entity = { gevLabelModel: { title: 'OLD', details: ['? km'] } };
const point = { position: new Cesium.Cartesian3() };
const viewer = { camera: null, scene: { frameState: { frameNumber: 1 } } };
let nowMs = Date.UTC(2008, 8, 20, 12, 30);
// The tracked satellite moves ~7.6 km/s, so neighbours are defined RELATIVE to
// wherever it is at scan time rather than pinned to a stale sample.
const near = (metres) => ({
get position() {
const tracked = _trackedFrameCartesianForTest();
return new Cesium.Cartesian3(tracked.x + metres, tracked.y, tracked.z);
},
});
_setTrackedSatelliteRefreshStateForTest({
noradId: 25544,
name: 'ISS (ZARYA)',
satrec: twoline2satrec(L1, L2),
entity,
point,
viewer,
now: () => nowMs,
neighbours: [
{ noradId: 55555, name: 'PROGRESS-MS 34', point: near(120) }, // berthed
{ noradId: 55556, name: 'SOYUZ-MS 12', point: near(-90) }, // berthed
{ noradId: 99999, name: 'UNRELATED SAT', point: near(50_000) }, // 50 km away
],
});
_runSatellitePreRenderForTest();
// The cluster scan is throttled, so advance past its interval before the frame
// that must observe the cluster.
nowMs += 2000;
viewer.scene.frameState.frameNumber = 2;
_runSatellitePreRenderForTest();
const details = entity.gevLabelModel.details;
// Class leads the detail block; the altitude line follows it, and the
// consolidated companions stay last.
assert.equal(details[0], 'STATION · ISS', 'the class line names what this is');
assert.match(details[1], /NORAD 25544$/, 'the altitude line is unchanged');
assert.equal(details[2], 'DOCKED · PROGRESS-MS 34 · +1',
'companions are consolidated, named, and counted on the tracked card');
// Scoping is encoded in that string: THREE neighbours were seeded but only two
// are counted (the named one plus "+1"). The satellite 50 km away is not part
// of the cluster and keeps its own identity and label — the owner's explicit
// constraint that unrelated nearby satellites are never suppressed.
assert.doesNotMatch(details[2], /UNRELATED/);
assert.doesNotMatch(details[2], /\+2/);
});
test('satellite pre-render refreshes the tracked altitude on each propagated frame', () => {
const entity = { gevLabelModel: { title: 'OLD', details: ['? km'] } };
const point = { position: new Cesium.Cartesian3() };
const viewer = {
camera: null,
scene: { frameState: { frameNumber: 1 } },
};
const epochs = [
Date.UTC(2008, 8, 20, 12, 30),
Date.UTC(2008, 8, 20, 13, 0),
];
let epochIndex = 0;
_setTrackedSatelliteRefreshStateForTest({
noradId: 25544,
name: 'ISS (ZARYA)',
satrec: twoline2satrec(L1, L2),
entity,
point,
viewer,
now: () => epochs[epochIndex],
});
_runSatellitePreRenderForTest();
assert.equal(entity.gevLabelModel.title, 'ISS (ZARYA)');
assert.equal(entity.gevLabelModel.details[0], 'STATION · ISS');
assert.equal(entity.gevLabelModel.details[1], '353 km · NORAD 25544');
epochIndex = 1;
viewer.scene.frameState.frameNumber = 2;
_runSatellitePreRenderForTest();
assert.equal(entity.gevLabelModel.details[1], '366 km · NORAD 25544');
assert.equal(entity.gevLabelModel.details[0], 'STATION · ISS',
'the class line survives an altitude-only republish');
});
test('ISS ambient and tracked lifecycle uses cached host entries with no native labels or duplicate text', () => {
const calls = [];
const overlayHost = {
setEntries: (...args) => calls.push(['entries', ...args]),
setVisible: (...args) => calls.push(['visible', ...args]),
clearSource: (...args) => calls.push(['clear', ...args]),
};
const point = {
position: Cesium.Cartesian3.fromDegrees(-97.7, 30.2, 420_000),
show: true,
pixelSize: 12,
color: Cesium.Color.RED,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 2,
disableDepthTestDistance: 0,
};
const viewer = {
entities: new Cesium.EntityCollection(),
trackedEntity: undefined,
scene: {
frameState: { frameNumber: 1 },
primitives: { remove() {} },
},
};
let cleaned = false;
_setSatelliteLabelLifecycleStateForTest({
viewer,
satrec: twoline2satrec(L1, L2),
point,
overlayHost,
});
try {
const ambientPublication = calls.find(([type]) => type === 'entries');
assert.ok(ambientPublication);
assert.equal(ambientPublication[1], 'satellites-iss');
assert.deepEqual(ambientPublication[3], ISS_OVERLAY_SOURCE_OPTIONS);
const ambient = ambientPublication[2][0];
assert.equal(ambient.title, 'ISS');
assert.equal(ambient.position(), point.position, 'ISS getter reads the existing point cache');
assert.equal(point.label, undefined, 'ISS point primitive carries no label graphic');
const trackedEntity = _trackIssForTest();
assert.ok(trackedEntity);
assert.equal(viewer.entities.values.length, 1, 'runtime guard requires a real tracked entity');
assert.equal(trackedEntity.label, undefined);
assert.ok(trackedEntity.point, 'tracked dot remains on the entity for camera framing');
const trackedEntry = createTrackedOverlayEntry(trackedEntity);
assert.ok(trackedEntry);
assert.equal(trackedEntry.id, 'satellites:25544');
assert.equal(trackedEntry.protected, true);
assert.equal(trackedEntry.paintLane, 'tracked');
assert.equal(
calls.filter(([type, sourceId]) => type === 'entries' && sourceId === 'satellites-iss').length,
2,
'tracking may refresh before ownership changes but must not publish a second ISS entry',
);
assert.deepEqual(calls.slice(-2), [
['clear', 'satellites-iss'],
['visible', 'satellites-iss', false],
], 'tracked ISS suppresses ambient text so the tracked card is the only text surface');
_clearSatelliteLabelLifecycleForTest();
cleaned = true;
assert.equal(viewer.entities.values.length, 0);
assert.equal(
calls.filter(([type, sourceId]) => type === 'entries' && sourceId === 'satellites-iss').length,
3,
'untracking republishes exactly one persistent ISS ambient entry before teardown',
);
} finally {
if (!cleaned) _clearSatelliteLabelLifecycleForTest();
}
});
test('ISS overlay entry retains the native distance scale and source text', () => {
const position = new Cesium.Cartesian3(1, 2, 3);
const entry = createIssOverlayEntry(() => position);
assert.equal(entry.title, 'ISS');
assert.equal(entry.position(), position);
assert.deepEqual(entry.distanceScale, {
near: 1_000_000,
nearValue: 1,
far: 30_000_000,
farValue: 0.4,
});
assert.equal(entry.edgeFade, 'keyhole');
assert.equal(entry.horizonCull, true);
});