db1168a46c
Отдельное окно countdown с «Показать игрокам»; на превью — move/resize/rotate, на презентации тот же layout. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
3.1 KiB
TypeScript
84 lines
3.1 KiB
TypeScript
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);
|
|
});
|