Files
Clarium/src/ThemeToggle.test.tsx
mroberts 7f5d034a1f feat: auth by default, theme toggle, CoderPad startup, review fixes
- Require a session on every route; public routes opt out with @allow_anonymous
- Split password hashing and pepper loading into passwords.py
- Add a system/light/dark theme toggle backed by light-dark() colors
- Ignore stale 401s from an earlier session, PATCH only changed book fields,
  and block overlapping journal-entry saves
- Add bin/start and CoderPad Vite server settings for the pad's start/restart
- Rewrite README as a mise onboarding guide; expand .gitignore
- Include review-round fixes and tests
2026-10-02 16:49:14 -05:00

49 lines
1.7 KiB
TypeScript

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { ThemeToggle } from "./ThemeToggle";
const root = document.documentElement;
const stored = new Map<string, string>();
beforeEach(() => {
// Vitest's jsdom on Node 24 exposes no localStorage, so give it a minimal one.
vi.stubGlobal("localStorage", {
getItem: (key: string) => stored.get(key) ?? null,
setItem: (key: string, value: string) => stored.set(key, value),
removeItem: (key: string) => stored.delete(key),
});
});
afterEach(() => {
delete root.dataset.theme;
stored.clear();
});
describe("ThemeToggle", () => {
it("cycles system, light, dark and back to following the system", async () => {
render(<ThemeToggle />);
const button = screen.getByRole("button", { name: /^Theme: System/ });
expect(root.dataset.theme).toBeUndefined();
await userEvent.click(button);
expect(button).toHaveAccessibleName("Theme: Light. Switch to Dark");
expect(root.dataset.theme).toBe("light");
expect(localStorage.getItem("theme")).toBe("light");
await userEvent.click(button);
expect(root.dataset.theme).toBe("dark");
expect(localStorage.getItem("theme")).toBe("dark");
await userEvent.click(button);
expect(root.dataset.theme).toBeUndefined();
expect(localStorage.getItem("theme")).toBeNull();
});
it("starts from the theme index.html applied before first paint", () => {
root.dataset.theme = "dark";
render(<ThemeToggle />);
expect(screen.getByRole("button", { name: /^Theme: Dark/ })).toBeVisible();
});
});