Files
gods-eye-view/src/data/vesselLabels.test.mjs
T
0251c74109 feat(weather): add globe wind, observed weather and cyclone context (#617)
Wind (NOAA GFS and ECMWF IFS: animated particles, colour field, a reading at map centre), observed weather (NOAA MRMS radar, GOES and NESDIS infrared clouds, lightning density) on one shared history timeline, NHC and CPHC cyclone advisories with tracks and cones, and a WEATHER panel in the right rail. On 3D Tiles the observed products render as raised shells with a sharper window around the view.

Co-authored-by: Gustavo Beneduzi <[email protected]>
Co-authored-by: Daniel Slay <[email protected]>
Co-authored-by: Rehaan Delmotra <[email protected]>
Co-authored-by: Cursor Agent <[email protected]>
2026-09-22 17:45:39 -05:00

97 lines
4.2 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(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}`);
}
});