import { test } from 'node:test'; import assert from 'node:assert/strict'; import { f1, fInt, fmm, markerPos, barHeights, wmoIcon, trendLabel, formatDate, formatTime, dayAbbr, monthName, isOlderThan, msUntil, } from '../../public/format.js'; const TZ = 'Europe/Berlin'; test('f1 uses a decimal comma and one decimal', () => { assert.equal(f1(16.4), '16,4'); assert.equal(f1(0), '0,0'); assert.equal(f1(19.75), '19,8'); assert.equal(f1(null), '–'); assert.equal(f1(undefined), '–'); }); test('fInt rounds to whole degrees', () => { assert.equal(fInt(18.3), '18'); assert.equal(fInt(9.5), '10'); assert.equal(fInt(null), '–'); }); test('fmm shows "0 mm" for zero', () => { assert.equal(fmm(0), '0 mm'); assert.equal(fmm(0.4), '0,4 mm'); assert.equal(fmm(8.25), '8,3 mm'); assert.equal(fmm(null), '–'); }); test('markerPos interpolates and clamps', () => { assert.ok(Math.abs(markerPos(16.4, 9.2, 19.8) - 67.92) < 0.01); assert.equal(markerPos(5, 9.2, 19.8), 0); assert.equal(markerPos(25, 9.2, 19.8), 100); assert.equal(markerPos(10, 10, 10), 50); assert.equal(markerPos(null, 1, 2), 50); }); test('barHeights scales to the tallest bar with a 2px floor', () => { const h = barHeights([1.2, 6.8, 0, 2.4]); assert.ok(Math.abs(h[0] - 12.35) < 0.01); assert.equal(h[1], 70); assert.equal(h[2], 2); assert.ok(Math.abs(h[3] - 24.7) < 0.01); assert.deepEqual(barHeights([0, 0, 0, 0]), [2, 2, 2, 2]); assert.deepEqual(barHeights([null, 0, undefined, 0]), [2, 2, 2, 2]); assert.deepEqual(barHeights([null, 5]), [2, 70]); }); test('wmoIcon maps every documented code', () => { assert.equal(wmoIcon(0), 'sun'); assert.equal(wmoIcon(1), 'partly'); assert.equal(wmoIcon(2), 'partly'); assert.equal(wmoIcon(3), 'cloud'); assert.equal(wmoIcon(45), 'fog'); assert.equal(wmoIcon(48), 'fog'); assert.equal(wmoIcon(51), 'drizzle'); assert.equal(wmoIcon(57), 'drizzle'); assert.equal(wmoIcon(61), 'rain'); assert.equal(wmoIcon(67), 'rain'); assert.equal(wmoIcon(80), 'showers'); assert.equal(wmoIcon(82), 'showers'); assert.equal(wmoIcon(71), 'snow'); assert.equal(wmoIcon(77), 'snow'); assert.equal(wmoIcon(85), 'snow'); assert.equal(wmoIcon(86), 'snow'); assert.equal(wmoIcon(95), 'thunder'); assert.equal(wmoIcon(99), 'thunder'); assert.equal(wmoIcon(42), 'cloud'); assert.equal(wmoIcon(null), 'cloud'); }); test('trendLabel', () => { assert.equal(trendLabel('up'), '↗ stijgend'); assert.equal(trendLabel('down'), '↘ dalend'); assert.equal(trendLabel('stable'), '→ stabiel'); assert.equal(trendLabel(null), ''); }); test('formatDate gives a capitalised Dutch date in the station timezone', () => { assert.equal(formatDate(new Date('2026-09-11T12:32:05Z'), TZ), 'Vrijdag 11 september'); // 23:30 UTC is al de volgende dag in Berlijn assert.equal(formatDate(new Date('2026-09-11T23:30:00Z'), TZ), 'Zaterdag 12 september'); }); test('formatTime uses HH:MM in the station timezone', () => { assert.equal(formatTime('2026-09-11T06:10:00+02:00', TZ), '06:10'); assert.equal(formatTime('2026-09-11T22:05:00Z', TZ), '00:05'); assert.equal(formatTime(null, TZ), '–'); assert.equal(formatTime('kapot', TZ), '–'); }); test('dayAbbr gives two-letter Dutch weekday', () => { assert.equal(dayAbbr('2026-09-12', TZ), 'Za'); assert.equal(dayAbbr('2026-09-13', TZ), 'Zo'); assert.equal(dayAbbr('2026-09-14', TZ), 'Ma'); assert.equal(dayAbbr('2026-09-15', TZ), 'Di'); assert.equal(dayAbbr('2026-09-16', TZ), 'Wo'); assert.equal(dayAbbr('2026-09-17', TZ), 'Do'); assert.equal(dayAbbr('2026-09-18', TZ), 'Vr'); }); test('monthName', () => { assert.equal(monthName(new Date('2026-09-11T12:00:00Z'), TZ), 'September'); }); test('isOlderThan', () => { const now = new Date('2026-09-11T12:32:00Z'); assert.equal(isOlderThan('2026-09-11T12:10:00Z', now, 30), false); assert.equal(isOlderThan('2026-09-11T11:50:00Z', now, 30), true); assert.equal(isOlderThan(null, now, 30), true); }); test('msUntil computes the wait until the next local time', () => { const now = new Date('2026-09-11T12:32:05.500Z'); // 14:32:05 in Berlijn assert.equal(msUntil(now, TZ, 0), ((24 - 14) * 3600 - 32 * 60 - 5) * 1000 - 500); assert.equal(msUntil(now, TZ, 4), ((24 - 14 + 4) * 3600 - 32 * 60 - 5) * 1000 - 500); assert.equal(msUntil(now, TZ, 15), (28 * 60 - 5) * 1000 - 500); assert.equal(msUntil(new Date('2026-09-11T22:00:00.000Z'), TZ, 0), 86400000, 'precies op het moment zelf: pas morgen weer'); });