// @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"]); }); });