import { act, assertEquals, cleanup, fireEvent, render } from "./setup.ts"; import ThemeToggle from "../../islands/ThemeToggle.tsx"; function resetState() { document.documentElement.classList.remove("dark"); localStorage.removeItem("theme"); } Deno.test({ name: "ThemeToggle - renders moon icon in light mode by default", fn() { resetState(); const { container } = render(); const icon = container.querySelector("i")!; assertEquals(icon.classList.contains("bi-moon-stars"), true); assertEquals(icon.classList.contains("bi-sun"), false); cleanup(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - renders sun icon when dark class is present", fn() { resetState(); document.documentElement.classList.add("dark"); let container: HTMLElement; act(() => { ({ container } = render()); }); const icon = container!.querySelector("i")!; assertEquals(icon.classList.contains("bi-sun"), true); assertEquals(icon.classList.contains("bi-moon-stars"), false); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - click adds dark class to documentElement", fn() { resetState(); const { container } = render(); const icon = container.querySelector("i")!; act(() => { fireEvent.click(icon); }); assertEquals(document.documentElement.classList.contains("dark"), true); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - click toggles icon from moon to sun", fn() { resetState(); const { container } = render(); const icon = container.querySelector("i")!; assertEquals(icon.classList.contains("bi-moon-stars"), true); act(() => { fireEvent.click(icon); }); const updatedIcon = container.querySelector("i")!; assertEquals(updatedIcon.classList.contains("bi-sun"), true); assertEquals(updatedIcon.classList.contains("bi-moon-stars"), false); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - second click removes dark class", fn() { resetState(); const { container } = render(); const icon = container.querySelector("i")!; act(() => { fireEvent.click(icon); }); assertEquals(document.documentElement.classList.contains("dark"), true); act(() => { fireEvent.click(container.querySelector("i")!); }); assertEquals(document.documentElement.classList.contains("dark"), false); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - click persists 'dark' to localStorage", fn() { resetState(); const { container } = render(); act(() => { fireEvent.click(container.querySelector("i")!); }); assertEquals(localStorage.getItem("theme"), "dark"); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - second click persists 'light' to localStorage", fn() { resetState(); const { container } = render(); act(() => { fireEvent.click(container.querySelector("i")!); }); act(() => { fireEvent.click(container.querySelector("i")!); }); assertEquals(localStorage.getItem("theme"), "light"); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - click dispatches ThemeChange event", fn() { resetState(); let eventDetail: boolean | null = null; const listener = (e: Event) => { eventDetail = (e as CustomEvent).detail; }; document.addEventListener("ThemeChange", listener); const { container } = render(); act(() => { fireEvent.click(container.querySelector("i")!); }); assertEquals(eventDetail, true); document.removeEventListener("ThemeChange", listener); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - has hover classes for both themes", fn() { resetState(); const { container } = render(); const icon = container.querySelector("i")!; assertEquals(icon.className.includes("hover:text-blue-600"), true); assertEquals(icon.className.includes("dark:hover:text-blue-400"), true); cleanup(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - has correct title attribute in light mode", fn() { resetState(); const { container } = render(); const icon = container.querySelector("i")!; assertEquals(icon.getAttribute("title"), "Switch to dark mode"); cleanup(); }, sanitizeResources: false, sanitizeOps: false, }); Deno.test({ name: "ThemeToggle - has correct title attribute in dark mode", fn() { resetState(); document.documentElement.classList.add("dark"); let container: HTMLElement; act(() => { ({ container } = render()); }); const icon = container!.querySelector("i")!; assertEquals(icon.getAttribute("title"), "Switch to light mode"); cleanup(); resetState(); }, sanitizeResources: false, sanitizeOps: false, });