Extract instance-owned civil-flight components

This commit is contained in:
Sameh Khamis committed 2026-09-13 09:50:14 -07:00
1 parent cf149ecfc0
commit 7c7e83c9e3
33 files changed
+6190 -5284

No files matched your search

+4 -3
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
import { dispatchCockpitModeChanged, enter, exit, _adoptTrackedEntity } from '../ui/cockpitTrackingController.js';
import test from 'node:test';
import assert from 'node:assert/strict';
@@ -15,8 +16,8 @@ import militaryFlightsLayer, {
const SUBJECT = 'abc123';
const NEXT_SUBJECT = 'def456';
const FLIGHTS_SOURCE = readFileSync(new URL('./flights.js', import.meta.url), 'utf8');
const MILITARY_SOURCE = readFileSync(new URL('./militaryFlights.js', import.meta.url), 'utf8');
const FLIGHTS_SOURCE = readLayerSource(new URL('./flights.js', import.meta.url));
const MILITARY_SOURCE = readLayerSource(new URL('./militaryFlights.js', import.meta.url));
const LAYERS = [
{
@@ -108,7 +109,7 @@ test('Cockpit lifecycle publishes one normalized aircraft identity to both detec
['commercial', FLIGHTS_SOURCE],
['military', MILITARY_SOURCE],
]) {
const consumer = /function _applyCockpitState\(detail = \{\}\) \{[\s\S]*?\n\}/
const consumer = /function (?:parts\.\w+\.)?_applyCockpitState\(detail = \{\}\) \{[\s\S]*?\n\}/
.exec(source)?.[0];
assert.ok(consumer, `${name} Cockpit consumer is defined`);
assert.match(consumer, /detail\?\.subjectId/);
+18 -17
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
@@ -25,7 +26,7 @@ function numericConstant(source, name) {
}
for (const layer of LAYERS) {
const source = readFileSync(layer.path, 'utf8');
const source = readLayerSource(layer.path);
test(`${layer.name}: every GLB creation bypasses the tile-contended frame-spread queue`, () => {
const calls = [...source.matchAll(/Cesium\.Model\.fromGltfAsync\(\{([\s\S]*?)\}\)/g)];
@@ -37,11 +38,11 @@ for (const layer of LAYERS) {
});
test(`${layer.name}: Cockpit 3D obeys the shared Display toggle`, () => {
const regime = /function _modelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
const regime = /function (?:parts\.\w+\.)?_modelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.ok(regime, '_modelRegimeActive is defined');
assert.match(regime, /if \(!_models3dEnabled\) return false;/,
assert.match(regime, /if \(!(?:flightState\.)?_models3dEnabled\) return false;/,
'OFF must keep Cockpit AIR contacts in 2D');
assert.doesNotMatch(regime, /!_models3dEnabled\s*&&\s*!_cockpitContactMode/,
assert.doesNotMatch(regime, /!(?:flightState\.)?_models3dEnabled\s*&&\s*!(?:flightState\.)?_cockpitContactMode/,
'Cockpit must not bypass the owner-visible Display toggle');
});
@@ -51,13 +52,13 @@ for (const layer of LAYERS) {
// owns. The tracked regime is DEFAULT-ON by camera distance (2026-08-19), so
// it no longer routes through the toggle-gated `_modelRegimeActive` — the
// suppression is now an explicit early return.
const regime = /function _trackedModelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
const regime = /function (?:parts\.\w+\.)?_trackedModelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.ok(regime, '_trackedModelRegimeActive is defined');
assert.match(regime, /if \(!_trackedIcao \|\| _cockpitContactMode \|\|[\s\S]*?return false;/,
assert.match(regime, /if \(!(?:flightState\.)?_trackedIcao \|\| (?:flightState\.)?_cockpitContactMode \|\|[\s\S]*?return false;/,
'_trackedModelRegimeActive excludes cockpit');
const tracked = /function _updateTrackedModel\(\)[\s\S]*?\n if \(!active\)/.exec(source)?.[0];
const tracked = /function (?:parts\.\w+\.)?_updateTrackedModel\(\)[\s\S]*?\n if \(!active\)/.exec(source)?.[0];
assert.ok(tracked, '_updateTrackedModel is defined');
assert.match(tracked, /_trackedModelRegimeActive\(\)/,
assert.match(tracked, /(?:parts\.\w+\.)?_trackedModelRegimeActive\(\)/,
'the tracked-model driver uses the cockpit-aware predicate');
});
@@ -68,14 +69,14 @@ for (const layer of LAYERS) {
assert.equal(numericConstant(source, 'MODEL_ALL_KEEP_M'), 450_000);
assert.equal(numericConstant(source, 'COCKPIT_MODEL_MAX'), 60);
const add = /function _modelAddDistM\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
const keep = /function _modelKeepDistM\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.match(add, /_models3dMode === 'all' \? MODEL_ALL_ADD_M : MODEL_PROX_ADD_M/);
assert.match(keep, /_models3dMode === 'all' \? MODEL_ALL_KEEP_M : MODEL_PROX_KEEP_M/);
const add = /function (?:parts\.\w+\.)?_modelAddDistM\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
const keep = /function (?:parts\.\w+\.)?_modelKeepDistM\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.match(add, /(?:flightState\.)?_models3dMode === 'all' \? MODEL_ALL_ADD_M : MODEL_PROX_ADD_M/);
assert.match(keep, /(?:flightState\.)?_models3dMode === 'all' \? MODEL_ALL_KEEP_M : MODEL_PROX_KEEP_M/);
assert.doesNotMatch(add, /COCKPIT_MODEL_ADD_M/);
assert.doesNotMatch(keep, /COCKPIT_MODEL_KEEP_M/);
const cap = /function _modelCap\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
const cap = /function (?:parts\.\w+\.)?_modelCap\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.match(cap, /Math\.min\(COCKPIT_MODEL_MAX/,
'Cockpit keeps its 60-model performance ceiling');
});
@@ -92,15 +93,15 @@ for (const layer of LAYERS) {
'near contacts and model fallbacks retain the class-derived aircraft silhouette');
assert.match(source, /bb\.rotation = 0;/,
'far dots are reset to a rotation-free presentation');
assert.match(source, /\(!_cockpitContactMode \|\| isCockpitNear\) && \(doRotations \|\| revealed\)/,
assert.match(source, /\(!(?:flightState\.)?_cockpitContactMode \|\| isCockpitNear\) && \(doRotations \|\| revealed\)/,
'near 2D silhouettes continue to receive projected course');
assert.match(source, /if \(bb\.show\) bb\.show = false; \/\/ hand off ONLY once the model renders/,
'the gap-proof billboard-to-model handoff remains intact');
});
test(`${layer.name}: Cockpit exit clears near state before restoring map presentation`, () => {
const setMode = /function _setCockpitContactMode\([\s\S]*?\n\}/.exec(source)?.[0];
assert.match(setMode, /else _cockpitNearContacts = new Set\(\);/);
assert.match(setMode, /for \(const \[icao24, bb\] of _billboards\) _applyFleetBillboardPresentation\(icao24, bb\);/);
const setMode = /function (?:parts\.\w+\.)?_setCockpitContactMode\([\s\S]*?\n\}/.exec(source)?.[0];
assert.match(setMode, /else (?:flightState\.)?_cockpitNearContacts = new Set\(\);/);
assert.match(setMode, /for \(const \[icao24, bb\] of (?:flightState\.)?_billboards\) (?:parts\.\w+\.)?_applyFleetBillboardPresentation\(icao24, bb\);/);
});
}
+2 -1
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
// src/data/detectionRenderDemand.test.mjs
//
// Detection must not hold the render loop open — and must not drop work on the
@@ -427,7 +428,7 @@ test('the render-governor gate covers the parked case, with teeth on the painter
// promptness goes with them, silently. This test is where that shows up.
test('aircraft brackets stay prompt because the aircraft layers hold the render loop', async () => {
for (const file of ['./flights.js', './militaryFlights.js']) {
const source = await readFile(new URL(file, import.meta.url), 'utf8');
const source = readLayerSource(new URL(file, import.meta.url));
const enable = /\n enable\([\s\S]*?\n \},/.exec(source)?.[0];
assert.ok(enable, `${file}: enable() is still identifiable`);
assert.match(
+36 -5210
View File
File diff suppressed because it is too large. Load diff
+7 -6
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
@@ -365,21 +366,21 @@ test('a fresh boot starts 3D aircraft ON in proximity — codec, both layers, an
// first-run session actually boots from.
const { readFile } = await import('node:fs/promises');
for (const name of ['flights.js', 'militaryFlights.js']) {
const source = await readFile(new URL(`./${name}`, import.meta.url), 'utf8');
assert.match(source, /^let _models3dEnabled = true;$/m,
const source = readLayerSource(new URL(`./${name}`, import.meta.url));
assert.match(source, /^\s*(?:let |flightState\.)_models3dEnabled = true;$/m,
`${name}: the fleet starts armed, matching the codec default`);
assert.match(source, /^let _models3dMode = 'proximity';/m,
assert.match(source, /^\s*(?:let |flightState\.)_models3dMode = 'proximity';/m,
`${name}: and starts in proximity, matching the codec default`);
}
const ui = await readFile(new URL('../ui/applicationShell.js', import.meta.url), 'utf8');
assert.match(ui, /^\s*this\._models3dEnabled = true;$/m,
assert.match(ui, /^\s*this\.(?:flightState\.)?_models3dEnabled = true;$/m,
'ui.js: the DISPLAY rail believes 3D is on before any layer-state sync arrives');
assert.match(ui, /this\._models3dMode = 'proximity';/,
assert.match(ui, /this\.(?:flightState\.)?_models3dMode = 'proximity';/,
'ui.js: and believes the mode is proximity');
const html = await readFile(new URL('../../index.html', import.meta.url), 'utf8');
assert.match(html, /class="pp-toggle-btn active" id="models3d-toggle" aria-pressed="true"/,
'index.html: the 3D button paints lit on first paint, before ui.js runs — and says so');
assert.match(ui, /this\._models3dBtn\?\.setAttribute\(\s*'aria-pressed',\s*String\(this\._models3dEnabled\),?\s*\)/,
assert.match(ui, /this\._models3dBtn\?\.setAttribute\(\s*'aria-pressed',\s*String\(this\.(?:flightState\.)?_models3dEnabled\),?\s*\)/,
'ui.js: and keeps aria-pressed synchronized, so the lit state is not colour-only');
assert.match(html, /class="pp-slider-row visible" id="models3d-mode-row"/,
'index.html: and the Proximity/All row paints open with it');
+12 -11
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
import { test } from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
@@ -297,7 +298,7 @@ test('Contacts live repaint restores only stable identity and never retargets an
});
test('Contacts continuation target is the visible explanatory note', () => {
const source = fs.readFileSync(new URL('./militaryAwareness.js', import.meta.url), 'utf8');
const source = readLayerSource(new URL('./militaryAwareness.js', import.meta.url));
assert.match(
source,
/<p class="military-awareness-note" tabindex="-1" data-awareness-focus-continuation>Open-source mapped\/observed context\./,
@@ -1352,11 +1353,11 @@ test('hasContact declines while a layer is disabled, whatever its maps still hol
// disable() hides the collection but keeps the records, so a map lookup
// alone would report a preserved subject as FRESH from hidden stale data.
for (const [name, source, guard] of [
['flights', fs.readFileSync(new URL('./flights.js', import.meta.url), 'utf8'),
/hasContact\(icao24\) \{\s*\n\s*if \(!_billboardCollection \|\| !_billboardCollection\.show \|\| _billboards\.size === 0\) return null;/],
['militaryFlights', fs.readFileSync(new URL('./militaryFlights.js', import.meta.url), 'utf8'),
/hasContact\(icao24\) \{\s*\n\s*if \(!_billboardCollection \|\| !_billboardCollection\.show \|\| _billboards\.size === 0\) return null;/],
['aisLiveVessels', fs.readFileSync(new URL('./aisLiveVessels.js', import.meta.url), 'utf8'),
['flights', readLayerSource(new URL('./flights.js', import.meta.url)),
/hasContact\(icao24\) \{\s*\n\s*if \(!(?:flightState\.)?_billboardCollection \|\| !(?:flightState\.)?_billboardCollection\.show \|\| (?:flightState\.)?_billboards\.size === 0\) return null;/],
['militaryFlights', readLayerSource(new URL('./militaryFlights.js', import.meta.url)),
/hasContact\(icao24\) \{\s*\n\s*if \(!(?:flightState\.)?_billboardCollection \|\| !(?:flightState\.)?_billboardCollection\.show \|\| (?:flightState\.)?_billboards\.size === 0\) return null;/],
['aisLiveVessels', readLayerSource(new URL('./aisLiveVessels.js', import.meta.url)),
/hasContact\(mmsi\) \{\s*\n\s*if \(!state\.enabled \|\| !state\.vesselMap \|\| state\.vesselMap\.size === 0\) return null;/],
]) {
assert.match(source, guard, `${name}.hasContact must decline while the layer is disabled`);
@@ -1527,14 +1528,14 @@ test('a deliberate source clear still fully clears the subject', () => {
test('production eviction sites actually tag their clears', () => {
// The event contract above is worthless if the real cull paths never set the
// origin, so pin the three production call sites.
const flightsSource = fs.readFileSync(new URL('./flights.js', import.meta.url), 'utf8');
const militarySource = fs.readFileSync(new URL('./militaryFlights.js', import.meta.url), 'utf8');
const vesselsSource = fs.readFileSync(new URL('./aisLiveVessels.js', import.meta.url), 'utf8');
const flightsSource = readLayerSource(new URL('./flights.js', import.meta.url));
const militarySource = readLayerSource(new URL('./militaryFlights.js', import.meta.url));
const vesselsSource = readLayerSource(new URL('./aisLiveVessels.js', import.meta.url));
for (const [name, source] of [['flights', flightsSource], ['militaryFlights', militarySource]]) {
assert.match(
source,
/if \(icao24 === _trackedIcao\) \{\s*\n\s*_clearTracking\(false, \{ evicted: true \}\);/,
/if \(icao24 === (?:flightState\.)?_trackedIcao\) \{\s*\n\s*(?:parts\.\w+\.)?_clearTracking\(false, \{ evicted: true \}\);/,
`${name} must mark its aged-out cull as an eviction`,
);
assert.match(
@@ -1553,7 +1554,7 @@ test('production eviction sites actually tag their clears', () => {
// The tag alone is not enough — see the behavioral test in
// firmsInteraction.test.mjs. The clear must also run BEFORE renderCurrentLod,
// whose registration sweep deletes the record the clear needs to see.
const firmsSource = fs.readFileSync(new URL('./firmsHeatmap.js', import.meta.url), 'utf8');
const firmsSource = readLayerSource(new URL('./firmsHeatmap.js', import.meta.url));
const evictedClear = firmsSource.indexOf('clearSelectedEntityContextForLayer(id, { evicted: true });');
const lodRebuild = firmsSource.indexOf('renderCurrentLod(true);\n if (reselected) selectFire(reselected);');
assert.ok(evictedClear > 0, 'FIRMS must mark a refresh-vanished selection as an eviction');
+4 -3
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
// Regression test for the giant-military-jet bug: MODEL_SCALE must put every
// rendered aircraft at REAL-WORLD size, whatever the GLB's native scale is.
//
@@ -358,7 +359,7 @@ function nativeVisualCenter(file) {
// --- per-layer constants, read from source (see header) --------------------
function layerConstants(sourceFile) {
const src = fs.readFileSync(path.join(ROOT, sourceFile), 'utf8');
const src = readLayerSource(path.join(ROOT, sourceFile));
const scale = src.match(/\bconst MODEL_SCALE = ([\d.]+);/);
assert.ok(scale, `${sourceFile}: MODEL_SCALE not found`);
const belly = src.match(/\bconst MODEL_BELLY_OFFSET_NATIVE = ([\d.]+);/);
@@ -367,8 +368,8 @@ function layerConstants(sourceFile) {
}
function normalBillboardScaleByDistance(sourceFile) {
const src = fs.readFileSync(path.join(ROOT, sourceFile), 'utf8');
const fn = src.match(/function _normalBillboardScaleByDistance\(\) \{([\s\S]*?)\n\}/);
const src = readLayerSource(path.join(ROOT, sourceFile));
const fn = src.match(/function (?:parts\.\w+\.)?_normalBillboardScaleByDistance\(\) \{([\s\S]*?)\n\}/);
assert.ok(fn, `${sourceFile}: _normalBillboardScaleByDistance not found`);
const scalar = fn[1].match(/NearFarScalar\((\d+), ([\d.]+), (\d+), ([\d.]+)\)/);
assert.ok(scalar, `${sourceFile}: billboard NearFarScalar not found`);
+8 -7
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
// src/data/tr3bRegistry.test.mjs
// TR-3B conversion Easter egg: registry state, sprite-variant selection,
// class-label override, and the render-path invariants that keep a converted
@@ -227,7 +228,7 @@ test('a conversion survives a poll refresh, in both the billboard and the tracke
test('both flight layers keep a converted contact 2D and visible (render invariants)', async () => {
for (const name of ['flights.js', 'militaryFlights.js']) {
const source = await readFile(new URL(`./${name}`, import.meta.url), 'utf8');
const source = readLayerSource(new URL(`./${name}`, import.meta.url));
// 1. The 3D model handoff is SUPPRESSED for a converted contact — there is
// no TR-3B GLB, so the triangle billboard stays the visual.
@@ -237,13 +238,13 @@ test('both flight layers keep a converted contact 2D and visible (render invaria
// (2026-08-19), so the suppression moved from a conjunct on
// `_modelRegimeActive()` to an explicit early return. The invariant is
// unchanged: a converted contact never reaches the model handoff.
assert.match(source, /if \(!_trackedIcao \|\| _cockpitContactMode \|\| isTr3b\(_trackedIcao\)\) \{/,
assert.match(source, /if \(!(?:flightState\.)?_trackedIcao \|\| (?:flightState\.)?_cockpitContactMode \|\| isTr3b\((?:flightState\.)?_trackedIcao\)\) \{/,
`${name}: the standalone tracked model is suppressed for a converted contact`);
// 2. The billboard is never hidden by that suppression — it must keep
// satisfying the getNearby/getDetectableObjects visibility guards, so a
// converted contact still works in Contacts and Cockpit.
assert.match(source, /if \(bb && id !== _trackedIcao\) bb\.show = true;|if \(modelled && id !== _trackedIcao\) modelled\.show = true;/,
assert.match(source, /if \(bb && id !== (?:flightState\.)?_trackedIcao\) bb\.show = true;|if \(modelled && id !== (?:flightState\.)?_trackedIcao\) modelled\.show = true;/,
`${name}: converting restores the billboard the model handoff had hidden`);
// 3. Every aircraftIcon() CALL SITE routes through the kind resolver, so no
@@ -253,7 +254,7 @@ test('both flight layers keep a converted contact 2D and visible (render invaria
const callSites = code.match(/aircraftIcon\(\s*[^;]*?\)/g) || [];
assert.equal(callSites.length >= 4, true, `${name}: expected the known aircraftIcon call sites`);
for (const call of callSites) {
assert.match(call, /aircraftIcon\(\s*_iconKind\(/,
assert.match(call, /aircraftIcon\(\s*(?:parts\.rendering\.)?_iconKind\(/,
`${name}: ${call.replace(/\s+/g, ' ')} must resolve its sprite kind through _iconKind`);
}
@@ -271,7 +272,7 @@ test('conversions are session-scoped and no lifecycle path clears them', async (
// should still show the triangle. Only a page reload resets it — so no
// production code may clear the registry.
for (const name of ['flights.js', 'militaryFlights.js', '../ui/applicationShell.js']) {
const source = await readFile(new URL(`./${name}`, import.meta.url), 'utf8');
const source = readLayerSource(new URL(`./${name}`, import.meta.url));
assert.doesNotMatch(source, /clearTr3bRegistry/,
`${name}: teardown must not clear session conversions`);
}
@@ -406,10 +407,10 @@ test('a converted contact never consumes a 3D model CAP SLOT', async () => {
// in the fleet tick (no seam to drive headlessly), so this asserts the guard's
// POSITION rather than replaying the four-pass selection.
for (const name of ['flights.js', 'militaryFlights.js']) {
const source = await readFile(new URL(`./${name}`, import.meta.url), 'utf8');
const source = readLayerSource(new URL(`./${name}`, import.meta.url));
// Anchor on the MODEL-eligibility loop (keepDistSq), not the unrelated
// ambient-enrichment candidate loop that also builds a `cand`.
const loop = /const cand = \[\];\s*\n\s*for \(const \[icao, bb\] of _billboards\)[\s\S]*?cand\.push\(/.exec(source)?.[0];
const loop = /const cand = \[\];\s*\n\s*for \(const \[icao, bb\] of (?:flightState\.)?_billboards\)[\s\S]*?cand\.push\(/.exec(source)?.[0];
assert.ok(loop, `${name}: the model-eligibility candidate loop is present`);
assert.match(loop, /keepDistSq/, `${name}: matched the model-eligibility loop`);
assert.match(loop, /if \(isTr3b\(icao\)\) continue;/,
+11 -10
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
// src/data/trackedModelRegime.test.mjs
//
// Zoom-driven 2D↔3D for the TRACKED contact (owner directive 2026-08-19).
@@ -931,15 +932,15 @@ for (const fixture of LAYERS) {
test('both layers gate the tracked-model load and record its failures', async () => {
const { readFile } = await import('node:fs/promises');
for (const name of ['flights.js', 'militaryFlights.js']) {
const source = await readFile(new URL(`./${name}`, import.meta.url), 'utf8');
assert.match(source, /!_trackedModel && !_trackedModelLoading && _trackedModelLoadAllowed\(\)/,
const source = readLayerSource(new URL(`./${name}`, import.meta.url));
assert.match(source, /!(?:flightState\.)?_trackedModel && !(?:flightState\.)?_trackedModelLoading && (?:parts\.\w+\.)?_trackedModelLoadAllowed\(\)/,
`${name}: the driver asks permission before starting another tracked-model load`);
assert.match(source, /_noteTrackedModelLoadFailure\(trackedSpec\.url, err\)/,
assert.match(source, /(?:parts\.\w+\.)?_noteTrackedModelLoadFailure\(trackedSpec\.url, err\)/,
`${name}: a rejected load is recorded against this selection, not silently retried`);
// The reset must be reachable from the real teardown, not only a test seam.
assert.match(source, /_releaseTrackedModel\(\);\n _resetTrackedSelectionState\(\);/,
assert.match(source, /(?:parts\.\w+\.)?_releaseTrackedModel\(\);\n (?:parts\.\w+\.)?_resetTrackedSelectionState\(\);/,
`${name}: deselect clears the per-selection latches in the production path`);
assert.match(source, /_trackedIcao = icao24;\n _resetTrackedSelectionState\(\);/,
assert.match(source, /(?:flightState\.)?_trackedIcao = icao24;\n (?:parts\.\w+\.)?_resetTrackedSelectionState\(\);/,
`${name}: selecting a contact starts from a clean per-selection state`);
}
});
@@ -947,16 +948,16 @@ test('both layers gate the tracked-model load and record its failures', async ()
test('the tracked regime never consults the fleet models3d toggle', async () => {
const { readFile } = await import('node:fs/promises');
for (const name of ['flights.js', 'militaryFlights.js']) {
const source = await readFile(new URL(`./${name}`, import.meta.url), 'utf8');
const regime = /function _trackedModelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
const source = readLayerSource(new URL(`./${name}`, import.meta.url));
const regime = /function (?:parts\.\w+\.)?_trackedModelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.ok(regime, `${name}: _trackedModelRegimeActive is defined`);
assert.doesNotMatch(regime, /_models3dEnabled|_modelRegimeActive\(\)/,
assert.doesNotMatch(regime, /(?:flightState\.)?_models3dEnabled|(?:parts\.\w+\.)?_modelRegimeActive\(\)/,
`${name}: the tracked contact's handoff is default-on, not gated on the fleet toggle`);
assert.match(regime, /trackedModelZoomActive\(/,
`${name}: the tracked contact uses the shared hysteretic zoom policy`);
// The FLEET must still obey the toggle — the budget decision stays the operator's.
const fleet = /function _modelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.match(fleet, /if \(!_models3dEnabled\) return false;/,
const fleet = /function (?:parts\.\w+\.)?_modelRegimeActive\(\) \{[\s\S]*?\n\}/.exec(source)?.[0];
assert.match(fleet, /if \(!(?:flightState\.)?_models3dEnabled\) return false;/,
`${name}: the fleet regime still obeys the DISPLAY-rail 3D toggle`);
}
});
+5 -4
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
@@ -244,13 +245,13 @@ test('tracking layers write gevLabelModel and expose only their cached display p
'militaryFlights.js',
'satellites.js',
'militaryInstallations.js',
].map(async (name) => [name, await readFile(new URL(`./${name}`, import.meta.url), 'utf8')]));
].map(async (name) => [name, readLayerSource(new URL(`./${name}`, import.meta.url))]));
const sources = Object.fromEntries(files);
for (const [name, source] of files) {
assert.ok(source.includes('.gevLabelModel ='), `${name} writes the explicit model directly`);
assert.ok(source.includes('.gevDisplayPosition ='), `${name} exposes a display-position cache`);
}
assert.ok(sources['flights.js'].includes('gevDisplayPosition = _trackedDisplayCached'));
assert.match(sources['flights.js'], /gevDisplayPosition = parts\.motion\._trackedDisplayCached/);
assert.ok(sources['militaryFlights.js'].includes('gevDisplayPosition = _trackedDisplayCached'));
assert.ok(sources['satellites.js'].includes('gevDisplayPosition = _trackedDisplayCached'));
assert.equal(sources['flights.js'].includes('_trackedEntity.label.text'), false);
@@ -260,11 +261,11 @@ test('tracking layers write gevLabelModel and expose only their cached display p
test('civilian and military trail heads use the lower-centre model anchor and weak-texture tint', async () => {
const files = await Promise.all(['flights.js', 'militaryFlights.js'].map(async (name) => (
[name, await readFile(new URL(`./${name}`, import.meta.url), 'utf8')]
[name, readLayerSource(new URL(`./${name}`, import.meta.url))]
)));
for (const [name, source] of files) {
assert.ok(
source.includes('const head = _trackedTrailCached() || _trackedDisplayPosition(_trackedIcao);'),
(/const head = (?:parts\.motion\.)?_trackedTrailCached\(\) \|\| (?:parts\.motion\.)?_trackedDisplayPosition\((?:flightState\.)?_trackedIcao\);/).test(source),
`${name} trail head uses the dedicated lower-centre model anchor`,
);
assert.ok(source.includes('const MODEL_COLOR_BLEND_AMOUNT = 0.94;'),
+5 -4
View File
@@ -1,3 +1,4 @@
import { readLayerSource } from '../testSupport/readLayerSource.mjs';
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
@@ -110,16 +111,16 @@ test('slow clean sprite clicks select, while long presses and orbit nudges canno
test('civilian and military click handlers apply duration only at the deselect branch', () => {
const sources = [
readFileSync(new URL('./flights.js', import.meta.url), 'utf8'),
readFileSync(new URL('./militaryFlights.js', import.meta.url), 'utf8'),
readLayerSource(new URL('./flights.js', import.meta.url)),
readLayerSource(new URL('./militaryFlights.js', import.meta.url)),
];
for (const source of sources) {
assert.match(source, /isTrackingSelectionGesture\(gesture\)[\s\S]+scene\.pick/);
assert.match(source, /isTrackingClickGesture\(gesture\)[\s\S]+_clearTracking\([^)]*\{ origin: 'user' \}\)/);
assert.match(source, /isTrackingClickGesture\(gesture\)[\s\S]+(?:parts\.\w+\.)?_clearTracking\([^)]*\{ origin: 'user' \}\)/);
}
assert.doesNotMatch(
sources[0],
/_trackedEntity = _viewer\.entities\.add\(\{\s*id:/,
/(?:flightState\.)?_trackedEntity = (?:flightState\.)?_viewer\.entities\.add\(\{\s*id:/,
'civilian tracked entities must retain Cesium-generated GUIDs',
);
});