Dark Reader marks <html data-darkreader-scheme="dark">; the page then sets data-theme="dark" and adds <meta name="darkreader-lock"> so Dark Reader removes its generated styles. Co-Authored-By: Claude Opus 5.5 <[email protected]>
73 lines
2.5 KiB
TypeScript
73 lines
2.5 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { followDarkReader, type ThemeDocument } from "../src/web/dark-reader";
|
|
|
|
type Fake = ThemeDocument & { attrs: Map<string, string>; metas: string[]; fire(): void; disconnected: boolean };
|
|
|
|
function fakeDocument(scheme?: string): Fake {
|
|
const attrs = new Map<string, string>();
|
|
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);
|
|
});
|