feat: add persistent responsive color themes
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import AxeBuilder from "@axe-core/playwright";
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
test("persists an explicit color scheme through the storage contract", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
const selector = page.getByRole("combobox", { name: "색상 테마" });
|
||||
|
||||
await selector.selectOption("dark");
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||
await expect(page.locator("html")).toHaveCSS("color-scheme", "dark");
|
||||
const results = await new AxeBuilder({ page })
|
||||
.withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"])
|
||||
.analyze();
|
||||
expect(
|
||||
results.violations.filter((violation) =>
|
||||
["critical", "serious"].includes(violation.impact ?? ""),
|
||||
),
|
||||
).toEqual([]);
|
||||
|
||||
await page.reload();
|
||||
await expect(selector).toHaveValue("dark");
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||
});
|
||||
|
||||
test("tracks operating-system changes while system preference is selected", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.emulateMedia({ colorScheme: "dark" });
|
||||
await page.goto("/");
|
||||
const selector = page.getByRole("combobox", { name: "색상 테마" });
|
||||
await selector.selectOption("system");
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||
|
||||
await page.emulateMedia({ colorScheme: "light" });
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "light");
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
normalizeColorSchemePreference,
|
||||
resolveColorScheme,
|
||||
} from "../../src/application/policies/color-scheme.js";
|
||||
import { initializeColorScheme } from "../../src/bootstrap/initialize-color-scheme.js";
|
||||
|
||||
describe("color scheme policy", () => {
|
||||
it("normalizes unknown persisted values to the safe system default", () => {
|
||||
expect(normalizeColorSchemePreference("sepia")).toBe("system");
|
||||
expect(normalizeColorSchemePreference("dark")).toBe("dark");
|
||||
});
|
||||
|
||||
it("resolves system and explicit preferences deterministically", () => {
|
||||
expect(resolveColorScheme("system", true)).toBe("dark");
|
||||
expect(resolveColorScheme("system", false)).toBe("light");
|
||||
expect(resolveColorScheme("light", true)).toBe("light");
|
||||
});
|
||||
|
||||
it("applies a persisted preference before application paint", () => {
|
||||
const storage = {
|
||||
read: () => ({ ok: true, value: "system" }),
|
||||
write: () => ({ ok: true }),
|
||||
remove: () => ({ ok: true }),
|
||||
};
|
||||
|
||||
const result = initializeColorScheme(storage, {
|
||||
documentElement: document.documentElement,
|
||||
matchMedia: () =>
|
||||
/** @type {MediaQueryList} */ ({ matches: true }),
|
||||
});
|
||||
|
||||
expect(result).toEqual({ preference: "system", resolved: "dark" });
|
||||
expect(document.documentElement).toHaveAttribute("data-theme", "dark");
|
||||
expect(document.documentElement).toHaveAttribute(
|
||||
"data-theme-preference",
|
||||
"system",
|
||||
);
|
||||
expect(document.documentElement.style.colorScheme).toBe("dark");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user