初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
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/);
|
||||
});
|
||||
Reference in New Issue
Block a user