A build from before the change renders history rows as text; an object there crashed its Notifications page after a rollback. The old key is read once while the new one does not exist, and never written.
89 lines
3.5 KiB
TypeScript
89 lines
3.5 KiB
TypeScript
// @vitest-environment jsdom
|
|
//
|
|
// The notification and hints stores read the account's localStorage when they are imported, which is
|
|
// before BootGate knows the account, so they read as nobody's; they must read again on the claim. The
|
|
// notification store used to keep its empty, nobody's history, and the tab's first notice replaced the
|
|
// account's stored history with it.
|
|
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { raw, sayNotif, type NotifText } from "./notifications";
|
|
|
|
const entry = (id: number, message: string) => ({
|
|
id,
|
|
level: "info",
|
|
message: raw(message),
|
|
ts: 1,
|
|
read: true,
|
|
dismissed: true,
|
|
transient: false,
|
|
repeat: 1,
|
|
requiresInteraction: false,
|
|
});
|
|
const storedMessages = () =>
|
|
(
|
|
JSON.parse(localStorage.getItem("siftlode.notifHistory") ?? "[]") as {
|
|
message: NotifText;
|
|
}[]
|
|
).map((n) => sayNotif(n.message));
|
|
|
|
// Warm the transform cache once (see verifyEntry.dom.test.tsx): the first cold import costs ~0.8 s
|
|
// alone and outran the 5 s case timeout under a full coverage run. Transformed code outlives
|
|
// vi.resetModules, so each case still gets fresh module instances, only faster.
|
|
beforeAll(async () => {
|
|
await import("./notifications");
|
|
await import("./hints");
|
|
await import("./storage");
|
|
}, 60_000);
|
|
|
|
// Warm or not, each case still loads and evaluates the modules it imports afresh after its module
|
|
// reset: tens of ms idle, but the same reload put sibling suites past 5 s when the full suite's
|
|
// workers share a busy machine.
|
|
const CASE_BUDGET = 30_000;
|
|
|
|
beforeEach(() => {
|
|
localStorage.clear();
|
|
sessionStorage.clear();
|
|
vi.resetModules(); // both stores load at import: each test needs a fresh one
|
|
});
|
|
|
|
describe("stores read at import, before the account is known", { timeout: CASE_BUDGET }, () => {
|
|
it("keep the account's notification history and settings once it is claimed", async () => {
|
|
localStorage.setItem("siftlode.owner", "5");
|
|
localStorage.setItem("siftlode.notifHistory", JSON.stringify([entry(7, "older")]));
|
|
localStorage.setItem("siftlode.notifSettings", JSON.stringify({ durationMs: 0 }));
|
|
const notifications = await import("./notifications");
|
|
const { claimLocalData } = await import("./storage");
|
|
|
|
notifications.notify({ message: raw("before the claim") }); // e.g. a failed boot probe
|
|
claimLocalData(5);
|
|
notifications.notify({ message: raw("after the claim") });
|
|
|
|
expect(storedMessages()).toEqual(["older", "before the claim", "after the claim"]);
|
|
expect(notifications.getNotifSettings().durationMs).toBe(0);
|
|
});
|
|
|
|
it("read the account's hints choice once it is claimed", async () => {
|
|
localStorage.setItem("siftlode.owner", "5");
|
|
localStorage.setItem("siftlode.hints", "0");
|
|
const hints = await import("./hints");
|
|
const { claimLocalData } = await import("./storage");
|
|
|
|
expect(hints.hintsEnabled()).toBe(true); // nobody's: the default
|
|
claimLocalData(5);
|
|
expect(hints.hintsEnabled()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("a browser that held another account's state", { timeout: CASE_BUDGET }, () => {
|
|
it("starts the new account's notices from an empty history", async () => {
|
|
localStorage.setItem("siftlode.owner", "4");
|
|
localStorage.setItem("siftlode.notifHistory", JSON.stringify([entry(7, "four's")]));
|
|
const notifications = await import("./notifications");
|
|
const { claimLocalData } = await import("./storage");
|
|
|
|
claimLocalData(5);
|
|
notifications.notify({ message: raw("as five") });
|
|
|
|
expect(storedMessages()).toEqual(["as five"]);
|
|
});
|
|
});
|