import { expect, test } from "bun:test"; import { followDarkReader, type ThemeDocument } from "../src/web/dark-reader"; type Fake = ThemeDocument & { attrs: Map; metas: string[]; fire(): void; disconnected: boolean }; function fakeDocument(scheme?: string): Fake { const attrs = new Map(); if (scheme) attrs.set("data-darkreader-scheme", scheme); const metas: string[] = []; let callback = () => {}; const doc: Fake = { attrs, metas, disconnected: false, fire: () => callback(), documentElement: { getAttribute: (name) => attrs.get(name) ?? null, setAttribute: (name, value) => void attrs.set(name, value), }, addLockMeta: () => void metas.push("darkreader-lock"), observeRoot: (onChange) => { callback = onChange; return () => { doc.disconnected = true; }; }, }; return doc; } test("Dark Reader already dark at start: our dark theme, and Dark Reader is told to stand down", () => { const doc = fakeDocument("dark"); followDarkReader(doc); expect(doc.attrs.get("data-theme")).toBe("dark"); expect(doc.metas).toEqual(["darkreader-lock"]); expect(doc.disconnected).toBe(true); }); test("Dark Reader turning on after load is followed once", () => { const doc = fakeDocument(); followDarkReader(doc); expect(doc.attrs.has("data-theme")).toBe(false); doc.attrs.set("data-darkreader-scheme", "dark"); doc.fire(); expect(doc.attrs.get("data-theme")).toBe("dark"); expect(doc.disconnected).toBe(true); doc.fire(); expect(doc.metas).toEqual(["darkreader-lock"]); }); test("no Dark Reader, or its dimmed (light) scheme: the page keeps following the system", () => { for (const doc of [fakeDocument(), fakeDocument("dimmed")]) { followDarkReader(doc); doc.fire(); expect(doc.attrs.has("data-theme")).toBe(false); expect(doc.metas).toEqual([]); expect(doc.disconnected).toBe(false); } }); test("the forced dark theme uses exactly the system dark tokens", async () => { const css = await Bun.file("src/web/styles.css").text(); const block = (start: string) => { const at = css.indexOf(start); expect(at).toBeGreaterThan(-1); const open = css.indexOf("{", css.indexOf(".mbseed-page", at)); return css.slice(open + 1, css.indexOf("}", open)).replace(/\s+/g, " ").trim(); }; const system = block("@media (prefers-color-scheme: dark)"); expect(system).toContain("--mb-page: #2a2520;"); expect(block(':root[data-theme="dark"]')).toBe(system); });