// @vitest-environment jsdom // // E28 audit: the Switch was a bare 36×20 track — under the 24 floor on a mouse, never the 44 touch box // DESIGN.md A3 lists it under, and its name was optional, so the Plex-sync switch shipped nameless. import { afterEach, describe, expect, it, vi } from "vitest"; import { cleanup, fireEvent, render, screen } from "@testing-library/react"; import { Switch, SwitchRow } from "./form"; afterEach(cleanup); describe("Switch", () => { it("is a named switch whose own box meets the 24 floor and grows to the touch target", () => { const onChange = vi.fn(); render(); const sw = screen.getByRole("switch", { name: "Dark mode" }); expect(sw.getAttribute("aria-checked")).toBe("false"); expect(sw.className).toContain("h-6"); expect(sw.className).toContain("pointer-coarse:min-h-(--touch-target)"); fireEvent.click(sw); expect(onChange).toHaveBeenCalledWith(true); }); it("cannot be rendered without a name", () => { // @ts-expect-error — `label` is required: a switch has no text of its own to be named by. render( {}} />); expect(screen.getByRole("switch")).toBeTruthy(); }); }); describe("SwitchRow", () => { // Owner decision F12: a settings row toggles from its whole surface, as on iOS and in Material. it("toggles from its text as well as from the switch, once per click", () => { const onChange = vi.fn(); render( , ); fireEvent.click(screen.getByText("Dark mode")); expect(onChange).toHaveBeenCalledTimes(1); fireEvent.click(screen.getByRole("switch", { name: "Dark mode" })); expect(onChange).toHaveBeenCalledTimes(2); expect(onChange).toHaveBeenLastCalledWith(true); }); it("does nothing from its text while disabled", () => { const onChange = vi.fn(); render(); fireEvent.click(screen.getByText("Sync")); expect(onChange).not.toHaveBeenCalled(); }); });