Files

74 lines
3.2 KiB
TypeScript
Raw Permalink Normal View History

2026-11-08 15:10:12 -05:00
import { describe, expect, test } from "bun:test";
import { THEMES, THEME_COLORS, isTheme } from "../src/client/theme.ts";
const html = await Bun.file("src/client/index.html").text();
const css = await Bun.file("src/client/styles.css").text();
const manifest = await Bun.file("src/client/manifest.webmanifest").json();
/** Runs the inline startup script from index.html with a fake browser. */
function startup(saved: Record<string, string>) {
const script = html.match(/<script>([\s\S]*?)<\/script>/)![1]!;
const storage = new Map(Object.entries(saved));
const root = { dataset: {} as Record<string, string> };
let themeColor = "";
const localStorage = {
getItem: (key: string) => storage.get(key) ?? null,
setItem: (key: string, value: string) => { storage.set(key, value); },
};
const document = {
documentElement: root,
querySelector: () => ({ setAttribute: (_: string, value: string) => { themeColor = value; } }),
};
new Function("localStorage", "document", script)(localStorage, document);
return { theme: root.dataset.theme, themeColor, saved: storage.get("timelog-theme") };
}
describe("startup theme", () => {
test("a device with no saved theme gets Nord", () => {
expect(startup({})).toMatchObject({ theme: "nord", themeColor: THEME_COLORS.nord });
});
test("a device that saved Mocha changes to Nord one time", () => {
expect(startup({ "timelog-theme": "mocha" })).toEqual({ theme: "nord", themeColor: THEME_COLORS.nord, saved: "nord" });
});
test("Mocha stays when the user selects it after the change to Nord", () => {
expect(startup({ "timelog-theme": "mocha", "timelog-theme-nord": "1" }))
.toMatchObject({ theme: "mocha", themeColor: THEME_COLORS.mocha });
});
test("Latte stays Latte", () => {
expect(startup({ "timelog-theme": "latte" })).toMatchObject({ theme: "latte", themeColor: THEME_COLORS.latte });
});
test("an unknown saved value gets Nord", () => {
expect(startup({ "timelog-theme": "solarized" })).toMatchObject({ theme: "nord", themeColor: THEME_COLORS.nord });
});
});
describe("theme colors", () => {
test("Nord is first in the picker", () => {
expect(THEMES[0]).toBe("nord");
expect(isTheme("nord") && isTheme("mocha") && isTheme("latte")).toBe(true);
expect(isTheme("solarized")).toBe(false);
});
test("the startup script uses the same colors as the app", () => {
for (const theme of THEMES) expect(html).toContain(`${theme}: "${THEME_COLORS[theme]}"`);
});
test("the CSS has Nord as the base and a block for each other theme", () => {
const base = css.match(/:root \{([\s\S]*?)\}/)![1]!;
expect(base).toContain(`--bg: ${THEME_COLORS.nord};`);
for (const theme of THEMES.filter(t => t !== "nord")) {
const block = css.match(new RegExp(`:root\\[data-theme="${theme}"\\] \\{([\\s\\S]*?)\\}`))?.[1];
expect(block).toContain(`--bg: ${THEME_COLORS[theme]};`);
}
});
test("the first paint and the installed app use Nord", () => {
expect(html).toContain(`<meta name="theme-color" content="${THEME_COLORS.nord}" />`);
expect(manifest.theme_color).toBe(THEME_COLORS.nord);
expect(manifest.background_color).toBe(THEME_COLORS.nord);
});
});