Files
gods-eye-view/src/layers/transit/vocabulary.test.mjs
T
Aditya 812cdf6be7 fix(transit): show a reported 359.6° bearing as hdg 0°, not hdg 360°
The selected-vehicle card rounded the operator's reported bearing without
wrapping, so a GTFS-Realtime vehicle heading 359.5° or more read
"reported hdg 360°". The card now wraps after rounding: 359.6° reads
"reported hdg 0°", 359.4° still reads "reported hdg 359°".
2026-10-28 15:09:27 +05:30

89 lines
3.7 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import {
buildTransitSelectionCopy,
transitDetectionClass,
transitDetectionId,
transitDetectionMetric,
transitModeAbbr,
transitModeWord,
} from './policy.js';
import { getTransitFeed } from '../../data/transitFeeds.js';
const ttc = () => getTransitFeed('ttc-toronto');
const hsl = () => getTransitFeed('hsl-helsinki');
test('an operator that names its own vehicles overrides the shared mode word', () => {
// A Toronto 501 is a streetcar. A Helsinki 1010 is a tram. Both are the
// `tram` mode, so the word a reader sees has to come from the operator,
// not from the mode.
assert.equal(transitModeWord('tram', ttc()), 'Streetcar');
assert.equal(transitModeAbbr('tram', ttc()), 'STREETCAR');
assert.equal(transitModeWord('tram', hsl()), 'Tram');
assert.equal(transitModeAbbr('tram', hsl()), 'TRAM');
});
test('an override renames one mode, never the rest of the feed', () => {
assert.equal(transitModeWord('bus', ttc()), 'Bus');
assert.equal(transitModeWord('subway', ttc()), 'Subway');
assert.equal(transitModeAbbr('bus', ttc()), 'BUS');
});
test('a missing feed or unknown mode falls back to the shared table', () => {
assert.equal(transitModeWord('tram', null), 'Tram');
assert.equal(transitModeWord('spaceship', ttc()), 'Transit vehicle');
assert.equal(transitModeAbbr('spaceship', ttc()), 'TRANSIT');
assert.equal(transitModeWord('tram', { name: 'No override' }), 'Tram');
});
test('the selection card calls a Toronto 501 a streetcar', () => {
const record = { id: '4400', routeId: '501', timestamp: 0 };
const copy = buildTransitSelectionCopy(ttc(), record, 'tram', 0, null, null);
assert.match(copy.details.join(' | '), /Streetcar · TTC/);
assert.doesNotMatch(copy.details.join(' | '), /Tram/);
});
test('the selection card reads a bearing that rounds to north as hdg 0°', () => {
const hdg = (bearing) =>
buildTransitSelectionCopy(
ttc(),
{ id: '4400', routeId: '501', timestamp: 0, bearing },
'tram',
0,
).details.find((line) => line.includes('hdg'));
assert.equal(hdg(359.4), 'reported hdg 359°');
assert.equal(hdg(359.6), 'reported hdg 0°');
});
test('detection labels carry the operator vocabulary within the field width', () => {
const klass = transitDetectionClass('tram', ttc());
assert.equal(klass, 'STREETCAR TTC');
assert.ok(klass.length <= 20, 'fits the detection class field');
assert.equal(transitDetectionClass('tram', hsl()), 'TRAM HSL');
const metric = transitDetectionMetric({ mode: 'tram' }, 'tram', 0, ttc());
assert.match(metric, /^STREETCAR/);
});
test('a Guelph vehicle is labelled with the number on the bus, not the database key', () => {
const guelph = getTransitFeed('guelph-transit');
const record = { id: '196', routeId: '2991', timestamp: 0 };
const copy = buildTransitSelectionCopy(guelph, record, 'bus', 0, null, null);
assert.match(copy.title, /Route 1\b/);
assert.doesNotMatch(copy.title, /2991/);
assert.equal(transitDetectionId(record, guelph), '1');
});
test('a feed that already speaks rider route numbers is untouched', () => {
const record = { id: '4400', routeId: '501', timestamp: 0 };
assert.equal(transitDetectionId(record, ttc()), '501');
const copy = buildTransitSelectionCopy(ttc(), record, 'tram', 0, null, null);
assert.match(copy.title, /Route 501/);
// No feed at all still renders the raw route rather than throwing.
assert.equal(transitDetectionId(record), '501');
});
test('a vehicle with no route still falls back to its fleet number', () => {
const guelph = getTransitFeed('guelph-transit');
assert.equal(transitDetectionId({ id: '196', label: '196' }, guelph), '196');
});