Something went wrong. Try again.
I will pick a better name later.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138import { beforeEach, describe, expect, it, vi } from "vitest";import { COLOR_THEMES, COLOR_THEME_COOKIE, DEFAULT_COLOR_THEME, DEFAULT_THEME_PREFERENCE, THEME_COOKIE, applyColorTheme, applyThemePreference, colorThemeFromCookieHeader, effectiveTheme, parseColorTheme, parseThemePreference, serializeColorThemeCookie, serializeThemePreferenceCookie, themeInitScript, themePreferenceFromCookieHeader,} from "~/lib/theme";
describe("theme preferences", () => { beforeEach(() => { vi.restoreAllMocks(); document.documentElement.className = ""; document.documentElement.removeAttribute("style"); document.documentElement.removeAttribute("data-color-theme"); document.cookie = `${THEME_COOKIE}=; Path=/; Max-Age=0`; document.cookie = `${COLOR_THEME_COOKIE}=; Path=/; Max-Age=0`; });
it("validates supported theme preferences and defaults to auto", () => { expect(parseThemePreference("auto")).toBe("auto"); expect(parseThemePreference("light")).toBe("light"); expect(parseThemePreference("dark")).toBe("dark"); expect(parseThemePreference("system")).toBe(DEFAULT_THEME_PREFERENCE); expect(parseThemePreference(null)).toBe(DEFAULT_THEME_PREFERENCE); });
it("reads and serializes the theme preference cookie", () => { expect(themePreferenceFromCookieHeader("later_theme=dark; other=value")).toBe("dark"); expect(themePreferenceFromCookieHeader("later_theme=invalid")).toBe("auto"); expect(themePreferenceFromCookieHeader(null)).toBe("auto"); expect(serializeThemePreferenceCookie("light")).toContain("later_theme=light"); });
it("provides and validates color themes", () => { expect(COLOR_THEMES.map((theme) => theme.id)).toEqual(["black-white", "catppuccin", "gruvbox", "ayu", "everforest", "nord", "rose-pine", "vesper"]); expect(parseColorTheme("black-white")).toBe("black-white"); expect(parseColorTheme("catppuccin")).toBe("catppuccin"); expect(parseColorTheme("gruvbox")).toBe("gruvbox"); expect(parseColorTheme("ayu")).toBe("ayu"); expect(parseColorTheme("everforest")).toBe("everforest"); expect(parseColorTheme("nord")).toBe("nord"); expect(parseColorTheme("rose-pine")).toBe("rose-pine"); expect(parseColorTheme("vesper")).toBe("vesper"); expect(parseColorTheme("unknown")).toBe(DEFAULT_COLOR_THEME); expect(parseColorTheme(null)).toBe(DEFAULT_COLOR_THEME); expect(COLOR_THEMES.every((theme) => theme.swatches.length > 0)).toBe(true); });
it("reads and serializes the color theme cookie", () => { expect(colorThemeFromCookieHeader("later_color_theme=gruvbox; other=value")).toBe("gruvbox"); expect(colorThemeFromCookieHeader("later_color_theme=invalid")).toBe(DEFAULT_COLOR_THEME); expect(colorThemeFromCookieHeader(null)).toBe(DEFAULT_COLOR_THEME); expect(serializeColorThemeCookie("catppuccin")).toContain("later_color_theme=catppuccin"); });
it("resolves auto from the system theme", () => { expect(effectiveTheme("auto", "dark")).toBe("dark"); expect(effectiveTheme("auto", "light")).toBe("light"); expect(effectiveTheme("dark", "light")).toBe("dark"); expect(effectiveTheme("light", "dark")).toBe("light"); });
it("applies explicit and automatic themes to the document", () => { let matches = true; let changeListener: (() => void) | undefined; const mediaQuery = { get matches() { return matches; }, media: "(prefers-color-scheme: dark)", onchange: null, addListener: vi.fn(), removeListener: vi.fn(), addEventListener: vi.fn((_event: "change", listener: () => void) => { changeListener = listener; }), removeEventListener: vi.fn(), dispatchEvent: vi.fn(), }; vi.spyOn(window, "matchMedia").mockReturnValue(mediaQuery as unknown as MediaQueryList);
applyThemePreference("auto"); expect(document.documentElement).toHaveClass("dark"); expect(document.documentElement.style.colorScheme).toBe("dark");
matches = false; changeListener?.(); expect(document.documentElement).not.toHaveClass("dark"); expect(document.documentElement.style.colorScheme).toBe("light");
applyThemePreference("dark"); expect(document.documentElement).toHaveClass("dark"); });
it("applies color themes to the document", () => { applyColorTheme("vesper"); expect(document.documentElement.dataset.colorTheme).toBe("vesper");
applyColorTheme("black-white"); expect(document.documentElement.dataset.colorTheme).toBe(DEFAULT_COLOR_THEME); });
it("initializes appearance and color theme from cookies before hydration", () => { vi.spyOn(window, "matchMedia").mockReturnValue({ matches: false } as MediaQueryList); document.cookie = `${THEME_COOKIE}=dark; Path=/`; document.cookie = `${COLOR_THEME_COOKIE}=gruvbox; Path=/`;
eval(themeInitScript);
expect(document.documentElement).toHaveClass("dark"); expect(document.documentElement.style.colorScheme).toBe("dark"); expect(document.documentElement.dataset.colorTheme).toBe("gruvbox"); });
it("defaults invalid init-script cookies", () => { vi.spyOn(window, "matchMedia").mockReturnValue({ matches: false } as MediaQueryList); document.cookie = `${THEME_COOKIE}=bad; Path=/`; document.cookie = `${COLOR_THEME_COOKIE}=bad; Path=/`;
eval(themeInitScript);
expect(document.documentElement).not.toHaveClass("dark"); expect(document.documentElement.style.colorScheme).toBe("light"); expect(document.documentElement.dataset.colorTheme).toBe(DEFAULT_COLOR_THEME); });});