// The request discipline of a polled page. Run by `npm test`, which Node runs // with its built-in test runner and type stripping, so the `.ts` module is // imported as it is. import assert from "node:assert/strict"; import { test } from "node:test"; import { createPoller } from "../src/ui/polled/poller.ts"; // A fetch whose answers the test settles by hand, in any order. function manualFetch() { const calls = []; const fetch = (signal) => new Promise((resolve, reject) => { calls.push({ signal, resolve, reject }); }); return { calls, fetch }; } // Lets the promise callbacks of a settled request run. const flush = () => new Promise((resolve) => setImmediate(resolve)); function collect() { const seen = { data: [], error: [] }; return { seen, onData: (d) => seen.data.push(d), onError: (e) => seen.error.push(e), }; } test("a tick while a request is in flight asks for nothing", async () => { const { calls, fetch } = manualFetch(); const sink = collect(); const poller = createPoller({ fetch, ...sink }); poller.tick(); poller.tick(); assert.equal(calls.length, 1); calls[0].resolve("one"); await flush(); assert.deepEqual(sink.seen.data, ["one"]); poller.tick(); assert.equal(calls.length, 2); }); test("a refetch drops the request in flight, so an older answer never lands", async () => { const { calls, fetch } = manualFetch(); const sink = collect(); const poller = createPoller({ fetch, ...sink }); poller.tick(); poller.refetch(); assert.equal(calls.length, 2); assert.equal(calls[0].signal.aborted, true); calls[1].resolve("new"); calls[0].resolve("old"); await flush(); assert.deepEqual(sink.seen.data, ["new"]); }); test("a stopped poller aborts the request and ignores its answer", async () => { const { calls, fetch } = manualFetch(); const sink = collect(); const poller = createPoller({ fetch, ...sink }); poller.tick(); poller.stop(); assert.equal(calls[0].signal.aborted, true); calls[0].resolve("late"); await flush(); assert.deepEqual(sink.seen.data, []); poller.tick(); assert.equal(calls.length, 2); }); test("a failed request reports the error and frees the next tick", async () => { const { calls, fetch } = manualFetch(); const sink = collect(); const poller = createPoller({ fetch, ...sink }); poller.tick(); const boom = new Error("boom"); calls[0].reject(boom); await flush(); assert.deepEqual(sink.seen.error, [boom]); poller.tick(); assert.equal(calls.length, 2); }); test("the answer of a dropped request that fails is not reported", async () => { const { calls, fetch } = manualFetch(); const sink = collect(); const poller = createPoller({ fetch, ...sink }); poller.tick(); poller.refetch(); calls[0].reject(new Error("aborted")); await flush(); assert.deepEqual(sink.seen.error, []); });