Files
gods-eye-view/src/data/vesselLabels.test.mjs
T
Said TurkseverandClaude Opus 5.5 4c383214f7 fix(tools): average aircraft speed over airborne aircraft only
aircraft_in_area stats summarized altitude over airborne aircraft but
speed over every match, so parked aircraft pulled the mean speed toward
zero. Both figures now use the same airborne subset, and the on-ground
fixture is stationary so the test can tell the difference.

Reserved AIS ship-type codes 100 to 255 now read as unknown, as type 0
does, instead of showing up in the breakdown as their own type.

Adds tests for an area where every aircraft is on the ground and for
find_vessel type and destination normalization, and notes in the
changelog fragment that every vessel answer is now normalized.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-19 14:29:11 +01:00

99 lines
4.3 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import {
accentForVesselType,
applyVesselOverlayPolicy,
normalizeVesselType,
vesselOverlayCohortLimit,
vesselTypeCss,
} from './vesselLabels.js';
test('normalizeVesselType maps numeric AIS codes to type families', () => {
assert.equal(normalizeVesselType('30'), 'FISHING');
assert.equal(normalizeVesselType('31'), 'TOWING');
assert.equal(normalizeVesselType('35'), 'MILITARY');
assert.equal(normalizeVesselType('36'), 'SAILING');
assert.equal(normalizeVesselType('37'), 'PLEASURE');
assert.equal(normalizeVesselType('40'), 'HIGH-SPEED');
assert.equal(normalizeVesselType('50'), 'PILOT');
assert.equal(normalizeVesselType('51'), 'SAR');
assert.equal(normalizeVesselType('52'), 'TUG');
assert.equal(normalizeVesselType('60'), 'PASSENGER');
assert.equal(normalizeVesselType('71'), 'CARGO');
assert.equal(normalizeVesselType('84'), 'TANKER');
assert.equal(normalizeVesselType('90'), 'OTHER');
});
test('normalizeVesselType preserves text and degrades unknown codes', () => {
assert.equal(normalizeVesselType('Crude Oil Tanker'), 'Crude Oil Tanker');
assert.equal(normalizeVesselType('0'), '');
assert.equal(normalizeVesselType('25'), 'OTHER');
assert.equal(normalizeVesselType('100'), '');
assert.equal(normalizeVesselType('255'), '');
assert.equal(normalizeVesselType(undefined), '');
});
test('vessel type CSS and card accents stay paired', () => {
assert.equal(vesselTypeCss('Crude Oil Tanker'), '#ffb347');
assert.equal(vesselTypeCss('Container Ship'), '#39d5ff');
assert.equal(vesselTypeCss('Passenger/Ferry'), '#ff7adf');
assert.equal(vesselTypeCss('Fishing'), '#7cff9b');
assert.equal(vesselTypeCss('Tug'), '#f7f0a3');
assert.equal(accentForVesselType('Tanker'), '255, 179, 71');
assert.equal(accentForVesselType('Cargo'), '57, 213, 255');
assert.equal(accentForVesselType('Passenger'), '255, 122, 223');
assert.equal(accentForVesselType('Fishing'), '124, 255, 155');
assert.equal(accentForVesselType('Pilot Vessel'), '247, 240, 163');
assert.equal(accentForVesselType('Dredger'), '57, 213, 255');
assert.equal(accentForVesselType('84'), '255, 179, 71');
assert.equal(vesselTypeCss('62'), '#ff7adf');
});
test('vessel viewport cohort preserves the shipped 118px grid density', () => {
assert.equal(vesselOverlayCohortLimit(1600, 900), 112);
assert.equal(vesselOverlayCohortLimit(1920, 1080), 170);
assert.equal(vesselOverlayCohortLimit(1920, 1080, 80), 80);
assert.equal(vesselOverlayCohortLimit(10000, 10000), 900, 'the shipped row ceiling remains absolute');
assert.equal(vesselOverlayCohortLimit(0, 1080), 0);
assert.equal(vesselOverlayCohortLimit(1920, 1080, 0), 0);
});
test('vessel host policy uses always-on shared fade and protected selected lane', () => {
const position = { x: 1, y: 2, z: 3 };
const ambient = applyVesselOverlayPolicy({
id: 'vessel:1', position, title: 'AMBIENT', gapPx: 10, selected: false,
});
assert.equal(ambient.variant, 'card');
assert.equal(ambient.protected, false);
assert.equal(ambient.collisionGroup, 'ambient-card');
assert.equal(ambient.edgeFade, 'keyhole');
assert.equal(ambient.maxDistance, 5_000_000);
assert.equal(ambient.distanceFadeStartRatio, 0.7);
assert.equal(ambient.cardStyle, 'tactical');
assert.equal(ambient.verticalOnly, true);
const selected = applyVesselOverlayPolicy({
id: 'vessel:2', position, title: 'SELECTED', gapPx: 12, selected: true,
});
assert.equal(selected.variant, 'selected');
assert.equal(selected.verticalOnly, false, 'selected detail can clear panels on either side');
assert.equal(selected.protected, true);
assert.equal(selected.collisionGroup, 'ambient-card');
assert.equal(selected.maxDistance, Number.POSITIVE_INFINITY);
});
test('vesselLabels cannot resurrect a dedicated renderer', async () => {
const source = await readFile(new URL('./vesselLabels.js', import.meta.url), 'utf8');
for (const forbidden of [
'document.createElement',
"createElement('canvas')",
'postRender.addEventListener',
'worldToWindowCoordinates',
'requestAnimationFrame',
"id = 'vessel-labels'",
]) {
assert.equal(source.includes(forbidden), false, `dedicated renderer token returned: ${forbidden}`);
}
});