import assert from 'node:assert/strict'; import test from 'node:test'; import { TimerSessionStore } from './timerSessionStore'; import { clampSessionTimerLayout, formatSessionTimerMs, getSessionTimerRemainingMs, parseSessionTimerDurationInput, } from '../../shared/types/sessionTimer'; void test('getSessionTimerRemainingMs: paused uses remainingMs', () => { const store = new TimerSessionStore(); const s = store.getState(); assert.equal(getSessionTimerRemainingMs(s, 1_000_000), s.remainingMs); }); void test('start pause start preserves remaining', () => { const store = new TimerSessionStore(); const t0 = 1_000_000; store.dispatch({ kind: 'setDuration', durationMs: 60_000 }, t0); store.dispatch({ kind: 'start' }, t0); store.dispatch({ kind: 'pause' }, t0 + 10_000); const afterPause = store.getState(); assert.equal(afterPause.running, false); assert.equal(afterPause.remainingMs, 50_000); store.dispatch({ kind: 'start' }, t0 + 20_000); assert.equal(getSessionTimerRemainingMs(store.getState(), t0 + 25_000), 45_000); }); void test('reset restores duration', () => { const store = new TimerSessionStore(); store.dispatch({ kind: 'setDuration', durationMs: 90_000 }); store.dispatch({ kind: 'start' }, 0); store.dispatch({ kind: 'pause' }, 30_000); store.dispatch({ kind: 'reset' }); assert.equal(store.getState().remainingMs, 90_000); assert.equal(store.getState().running, false); }); void test('setVisibleToPlayers and layout.set', () => { const store = new TimerSessionStore(); store.dispatch({ kind: 'setVisibleToPlayers', visible: true }); assert.equal(store.getState().visibleToPlayers, true); store.dispatch({ kind: 'layout.set', layout: { cx: 0.2, cy: 0.3, scale: 2, rotationDeg: 45 }, }); assert.equal(store.getState().layout.cx, 0.2); assert.equal(store.getState().layout.scale, 2); assert.equal(store.getState().layout.rotationDeg, 45); }); void test('settleIfExpired stops at zero', () => { const store = new TimerSessionStore(); store.dispatch({ kind: 'setDuration', durationMs: 5_000 }, 0); store.dispatch({ kind: 'start' }, 0); store.settleIfExpired(10_000); assert.equal(store.getState().running, false); assert.equal(store.getState().remainingMs, 0); }); void test('clampSessionTimerLayout / format / parse', () => { const clamped = clampSessionTimerLayout({ cx: 9, cy: -9, scale: 100, rotationDeg: 370 }); assert.ok(clamped.cx <= 1.2); assert.ok(clamped.cy >= -0.2); assert.ok(clamped.scale <= 8); assert.equal(clamped.rotationDeg, 10); assert.equal(formatSessionTimerMs(65_000), '01:05'); assert.equal(formatSessionTimerMs(3_661_000), '1:01:01'); assert.equal(parseSessionTimerDurationInput('5:00'), 300_000); assert.equal(parseSessionTimerDurationInput('1:02:03'), 3723_000); assert.equal(parseSessionTimerDurationInput('bad'), null); }); void test('clear restores defaults', () => { const store = new TimerSessionStore(); store.dispatch({ kind: 'setVisibleToPlayers', visible: true }); store.dispatch({ kind: 'start' }, 0); store.clear(); assert.equal(store.getState().visibleToPlayers, false); assert.equal(store.getState().running, false); }); void test('dismiss on window close: pause + hide from players', () => { const store = new TimerSessionStore(); const t0 = 1_000_000; store.dispatch({ kind: 'setDuration', durationMs: 60_000 }, t0); store.dispatch({ kind: 'setVisibleToPlayers', visible: true }); store.dispatch({ kind: 'start' }, t0); store.dispatch({ kind: 'pause' }, t0 + 5_000); store.dispatch({ kind: 'setVisibleToPlayers', visible: false }); assert.equal(store.getState().running, false); assert.equal(store.getState().visibleToPlayers, false); assert.equal(store.getState().remainingMs, 55_000); });