// What the refresh spinner shows: on at once, off only after a minimum time. import assert from "node:assert/strict"; import { test } from "node:test"; import { createBusyHold } from "../src/ui/polled/busy-hold.ts"; // A clock and a timer the test moves by hand. function rig() { let t = 0; const timers = []; const shown = []; const hold = createBusyHold({ show: (s) => shown.push(s), minMs: 400, now: () => t, after: (fn, ms) => { const timer = { fn, at: t + ms, live: true }; timers.push(timer); return timer; }, cancel: (timer) => { timer.live = false; }, }); const advance = (ms) => { t += ms; for (const timer of timers) { if (timer.live && timer.at <= t) { timer.live = false; timer.fn(); } } }; return { hold, shown, advance }; } test("it turns on at once and, for a quick answer, off only after the minimum", () => { const { hold, shown, advance } = rig(); hold.busy(true); assert.deepEqual(shown, [true]); advance(50); hold.busy(false); assert.deepEqual(shown, [true]); advance(349); assert.deepEqual(shown, [true]); advance(1); assert.deepEqual(shown, [true, false]); }); test("a slow answer turns it off as soon as it arrives", () => { const { hold, shown, advance } = rig(); hold.busy(true); advance(900); hold.busy(false); assert.deepEqual(shown, [true, false]); }); test("a new request while it is held keeps it on and cancels the pending off", () => { const { hold, shown, advance } = rig(); hold.busy(true); advance(100); hold.busy(false); hold.busy(true); advance(1000); assert.deepEqual(shown, [true]); hold.busy(false); assert.deepEqual(shown, [true, false]); }); test("stop drops a pending off, and busy(false) with nothing shown does nothing", () => { const { hold, shown, advance } = rig(); hold.busy(false); hold.busy(true); hold.busy(false); hold.stop(); advance(1000); assert.deepEqual(shown, [true]); });