54 lines
2 KiB
TypeScript
54 lines
2 KiB
TypeScript
/**
|
|
* @vitest-environment jsdom
|
|
* "Restart to update" banner — appears once, apply fires the opt-in,
|
|
* Later removes it. Pure DOM: no SW, no storage, no network.
|
|
*/
|
|
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import { showUpdateBanner } from "../../src/ui/components/update-banner.js";
|
|
|
|
beforeEach(() => {
|
|
document.body.replaceChildren();
|
|
});
|
|
|
|
function root(): HTMLElement {
|
|
const el = document.createElement("div");
|
|
document.body.append(el);
|
|
return el;
|
|
}
|
|
|
|
describe("update banner", () => {
|
|
it("renders banner with apply and dismiss once (idempotent)", () => {
|
|
const host = root();
|
|
showUpdateBanner(host, () => undefined);
|
|
showUpdateBanner(host, () => undefined);
|
|
expect(document.querySelectorAll(".update-banner").length).toBe(1);
|
|
expect(host.textContent).toContain("new version");
|
|
expect(host.querySelector(".update-banner__apply")?.textContent).toBe("Restart to update");
|
|
});
|
|
|
|
it("apply invokes the opt-in callback exactly once per click", () => {
|
|
const host = root();
|
|
const onApply = vi.fn();
|
|
showUpdateBanner(host, onApply);
|
|
host.querySelector(".update-banner__apply")?.dispatchEvent(new MouseEvent("click"));
|
|
expect(onApply).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("Later removes the banner without calling apply", () => {
|
|
const host = root();
|
|
const onApply = vi.fn();
|
|
showUpdateBanner(host, onApply);
|
|
host.querySelector(".update-banner__dismiss")?.dispatchEvent(new MouseEvent("click"));
|
|
expect(document.querySelector(".update-banner")).toBeNull();
|
|
expect(onApply).not.toHaveBeenCalled();
|
|
// Re-show after dismiss is allowed (a later update can re-offer).
|
|
showUpdateBanner(host, onApply);
|
|
expect(document.querySelectorAll(".update-banner").length).toBe(1);
|
|
});
|
|
|
|
it("renders no raw HTML from anywhere (textContent-only)", () => {
|
|
const host = root();
|
|
showUpdateBanner(host, () => undefined);
|
|
expect(host.querySelector(".update-banner")?.innerHTML).not.toMatch(/<img|<script/);
|
|
});
|
|
});
|