import assert from "node:assert/strict"; import { readFile } from "node:fs/promises"; import test from "node:test"; import { CURRENT_DISPLAY_SPEEDS, LatestSeekDispatcher, formatPlaybackTime, projectPlaybackPosition, } from "../app/static/current-display-playback.js"; const staticRoot = new URL("../app/static/", import.meta.url); test("formats and projects looping playback without moving paused content", () => { assert.deepEqual(CURRENT_DISPLAY_SPEEDS, [0.5, 1, 1.5, 2]); assert.equal(formatPlaybackTime(65032), "1:05.03"); assert.equal(projectPlaybackPosition({ active: true, position_ms: 900, total_duration_ms: 1000, paused: false, speed: 2, }, 100), 100); assert.equal(projectPlaybackPosition({ active: true, position_ms: 450, total_duration_ms: 1000, paused: true, speed: 2, }, 100), 450); }); test("seek dispatcher keeps one request in flight and flushes the newest position", async () => { let now = 0; let releaseFirst; const sent = []; const timers = new Map(); let timerSequence = 0; const dispatcher = new LatestSeekDispatcher((position) => { sent.push(position); if (sent.length === 1) return new Promise((resolve) => { releaseFirst = resolve; }); return Promise.resolve(); }, { now: () => now, setTimer: (callback) => { const id = ++timerSequence; timers.set(id, callback); return id; }, clearTimer: (id) => timers.delete(id), }); dispatcher.enqueue(10); await Promise.resolve(); await Promise.resolve(); dispatcher.enqueue(20); dispatcher.enqueue(30); dispatcher.enqueue(40, { flush: true }); assert.deepEqual(sent, [10]); releaseFirst(); await new Promise((resolve) => setImmediate(resolve)); assert.deepEqual(sent, [10, 40]); assert.equal(timers.size, 0); }); test("topbar current display dialog exposes static close and animation controls", async () => { const [html, device, style] = await Promise.all([ readFile(new URL("index.html", staticRoot), "utf8"), readFile(new URL("views/device.js", staticRoot), "utf8"), readFile(new URL("style.css", staticRoot), "utf8"), ]); assert.match(html, /id="topbar-current-content"[^>]*type="button"[^>]*aria-controls="current-display-dialog"/); assert.match(html, /id="current-display-dialog"[^>]*aria-labelledby="current-display-dialog-title"/); assert.match(html, /id="current-display-preview-image"/); assert.match(html, /id="current-display-progress"[^>]*type="range"/); assert.equal((html.match(/data-playback-speed=/g) || []).length, 4); assert.match(device, /event\.target === currentDisplayDialog/); assert.match(device, /currentDisplayPlaybackControls\.hidden/); assert.match(device, /intervalMs: 100/); assert.match(device, /currentDisplayFinalSeekPosition/); assert.match(device, /document\.visibilityState === "visible"/); assert.match(style, /\.current-display-preview-surface[\s\S]*aspect-ratio:\s*1/); assert.match(style, /@media \(max-width: 30rem\)[\s\S]*\.current-display-playback-actions[\s\S]*grid-template-columns:\s*1fr/); });