Files
wehub-resource-sync b3a7f98e5a
CI / E2E Cloudflare (4/8) (push) Failing after 0s
CI / E2E Cloudflare (8/8) (push) Failing after 1s
CI / Lint (push) Failing after 1s
Auto Extract / Extract (push) Failing after 4s
CI / Version Check (push) Failing after 9s
CI / Integration Tests (push) Failing after 1s
CI / E2E tests (1/8) (push) Failing after 1s
CI / E2E tests (2/8) (push) Failing after 2s
CI / E2E tests (3/8) (push) Failing after 2s
CI / Browser Tests (push) Failing after 1s
CI / E2E tests (5/8) (push) Failing after 1s
CI / E2E Cloudflare (2/8) (push) Failing after 2s
CI / Typecheck (push) Failing after 1s
CI / Changeset Validation (push) Failing after 2s
CI / E2E Cloudflare (5/8) (push) Failing after 1s
CI / E2E Cloudflare (6/8) (push) Failing after 1s
CI / E2E Cloudflare (7/8) (push) Failing after 1s
CodeQL / Analyze (javascript-typescript) (push) Failing after 1s
Format / Format (push) Failing after 0s
CodeQL / Analyze (actions) (push) Failing after 4s
CI / E2E tests (4/8) (push) Failing after 1s
CI / E2E tests (6/8) (push) Failing after 1s
CI / E2E tests (7/8) (push) Failing after 2s
CI / E2E tests (8/8) (push) Failing after 1s
CI / E2E Cloudflare (1/8) (push) Failing after 1s
CI / E2E Cloudflare (3/8) (push) Failing after 2s
Preview Releases / Publish Preview (push) Failing after 0s
zizmor / Run zizmor (push) Failing after 1s
Release / Release (push) Failing after 2s
CI / Smoke Tests (push) Failing after 5m36s
CI / Tests (push) Failing after 6m36s
Release / Sync Templates (push) Has been skipped
CI / E2E Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:23:53 +08:00

73 lines
2.6 KiB
TypeScript

import * as React from "react";
import { describe, it, expect, beforeEach } from "vitest";
import { ThemeProvider } from "../../src/components/ThemeProvider";
import { ThemeToggle } from "../../src/components/ThemeToggle";
import { render } from "../utils/render.tsx";
function TestThemeToggle({ defaultTheme = "system" as "system" | "light" | "dark" }) {
return (
<ThemeProvider defaultTheme={defaultTheme}>
<ThemeToggle />
</ThemeProvider>
);
}
describe("ThemeToggle", () => {
beforeEach(() => {
localStorage.clear();
document.documentElement.removeAttribute("data-theme");
});
// Kumo 2.x's <Button title="..."> wraps the button in a Tooltip popup
// rather than setting the native `title` attribute. The current theme is
// also exposed in `aria-label`, which is what these assertions read.
it("renders with system theme by default", async () => {
const screen = await render(<TestThemeToggle />);
const button = screen.getByRole("button");
await expect.element(button).toBeInTheDocument();
await expect.element(button).toHaveAttribute("aria-label", expect.stringContaining("System"));
});
it("cycles from system to light on click", async () => {
const screen = await render(<TestThemeToggle />);
const button = screen.getByRole("button");
await button.click();
await expect.element(button).toHaveAttribute("aria-label", expect.stringContaining("Light"));
});
it("cycles through system -> light -> dark -> system", async () => {
const screen = await render(<TestThemeToggle />);
const button = screen.getByRole("button");
// Start: system
await expect.element(button).toHaveAttribute("aria-label", expect.stringContaining("System"));
// Click 1: light
await button.click();
await expect.element(button).toHaveAttribute("aria-label", expect.stringContaining("Light"));
// Click 2: dark
await button.click();
await expect.element(button).toHaveAttribute("aria-label", expect.stringContaining("Dark"));
// Click 3: back to system
await button.click();
await expect.element(button).toHaveAttribute("aria-label", expect.stringContaining("System"));
});
it("persists theme to localStorage", async () => {
const screen = await render(<TestThemeToggle />);
const button = screen.getByRole("button");
await button.click(); // system -> light
expect(localStorage.getItem("emdash-theme")).toBe("light");
});
it("starts with light theme when defaultTheme is light", async () => {
const screen = await render(<TestThemeToggle defaultTheme="light" />);
const button = screen.getByRole("button");
await expect.element(button).toHaveAttribute("aria-label", expect.stringContaining("Light"));
});
});