Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/frontend/packages/swarm-ui/test/answer-cache.test.mjs
iris fd51cbd19d swarm-ui: pages that only display start from the answer they last saw, then refresh behind it
usePolled takes a cache key: it saves each answer in localStorage and starts
from the saved one, so opening the agents, alerts, builds, review runs or hives
view shows the last data at once and the refresh spinner marks the update. A
saved answer is dropped after a day, when it was saved by another build of the
UI, at log out (a new onLogout of the shared user menu) and when the gateway
ends the login (a new onSessionEnded of the session guard). Pages with an
editor (schedules, notification flows, broadcast) do not use it.
2026-11-05 23:14:25 +01:00

80 lines
2.6 KiB
JavaScript

// The saved last answer of a polled request: what is shown from a past visit,
// and when it is not.
import assert from "node:assert/strict";
import { test } from "node:test";
import {
clearAnswers,
MAX_AGE_MS,
readAnswer,
writeAnswer,
} from "../src/ui/polled/answer-cache.ts";
// A `Storage` that lives in a map.
function fakeStorage() {
const m = new Map();
return {
m,
getItem: (k) => (m.has(k) ? m.get(k) : null),
setItem: (k, v) => void m.set(k, v),
removeItem: (k) => void m.delete(k),
key: (i) => [...m.keys()][i] ?? null,
get length() {
return m.size;
},
};
}
const NOW = 1_800_000_000_000;
test("an answer written is read back, and nothing is read before one is written", () => {
const storage = fakeStorage();
assert.equal(readAnswer("a", { storage, now: NOW, build: "b1" }), null);
writeAnswer("a", [{ name: "iris" }], { storage, now: NOW, build: "b1" });
assert.deepEqual(readAnswer("a", { storage, now: NOW + 5000, build: "b1" }), [
{ name: "iris" },
]);
});
test("an answer from another build, or older than a day, is not shown", () => {
const storage = fakeStorage();
writeAnswer("a", { x: 1 }, { storage, now: NOW, build: "b1" });
assert.equal(readAnswer("a", { storage, now: NOW, build: "b2" }), null);
assert.deepEqual(
readAnswer("a", { storage, now: NOW + MAX_AGE_MS, build: "b1" }),
{ x: 1 },
);
assert.equal(
readAnswer("a", { storage, now: NOW + MAX_AGE_MS + 1, build: "b1" }),
null,
);
});
test("a value that does not parse, or is not an entry, is no answer", () => {
const storage = fakeStorage();
storage.setItem("swarm-ui:answer:a", "{not json");
assert.equal(readAnswer("a", { storage, now: NOW, build: "b1" }), null);
storage.setItem(
"swarm-ui:answer:a",
JSON.stringify({ at: NOW, build: "b1" }),
);
assert.equal(readAnswer("a", { storage, now: NOW, build: "b1" }), null);
storage.setItem("swarm-ui:answer:a", "7");
assert.equal(readAnswer("a", { storage, now: NOW, build: "b1" }), null);
});
test("a write that fails (over quota) is dropped without an error", () => {
const storage = {
setItem() {
throw new Error("QuotaExceededError");
},
};
writeAnswer("a", { x: 1 }, { storage, now: NOW, build: "b1" });
});
test("clearing forgets the answers and leaves every other key alone", () => {
const storage = fakeStorage();
writeAnswer("a", 1, { storage, now: NOW, build: "b1" });
writeAnswer("b", 2, { storage, now: NOW, build: "b1" });
storage.setItem("swarm-ui:term-groups", "[]");
clearAnswers(storage);
assert.deepEqual([...storage.m.keys()], ["swarm-ui:term-groups"]);
});