1// @vitest-environment jsdom
2
3import { act, useState } from "react";
4import { createRoot, type Root } from "react-dom/client";
5import { afterEach, beforeEach, describe, expect, it, vi } from "vite-plus/test";
6
7import { Switch } from "./switch";
8
9let root: Root;
10let container: HTMLDivElement;
11
12beforeEach(() => {
13 vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
14 container = document.createElement("div");
15 document.body.append(container);
16 root = createRoot(container);
17});
18
19afterEach(async () => {
20 await act(async () => root.unmount());
21 container.remove();
22 vi.unstubAllGlobals();
23});
24
25function ControlledSwitch({
26 initialChecked,
27 initialMixed = false,
28}: {
29 initialChecked: boolean;
30 initialMixed?: boolean;
31}) {
32 const [checked, setChecked] = useState(initialChecked);
33 const [mixed, setMixed] = useState(initialMixed);
34
35 return (
36 <Switch
37 aria-label="Enable Claude Code"
38 checked={checked}
39 mixed={mixed}
40 onCheckedChange={(nextChecked) => {
41 setMixed(false);
42 setChecked(nextChecked);
43 }}
44 />
45 );
46}
47
48function switchRoot() {
49 const element = container.querySelector<HTMLElement>('[role="switch"]');
50 if (!element) throw new Error("Switch was not rendered");
51 return element;
52}
53
54async function clickSwitch() {
55 await act(async () => switchRoot().click());
56}
57
58async function renderSwitch(initialChecked: boolean, initialMixed = false) {
59 await act(async () => {
60 root.render(<ControlledSwitch {...{ initialChecked, initialMixed }} />);
61 });
62}
63
64describe("Switch accessibility", () => {
65 it.each([
66 { initialChecked: false, initialMixed: false, before: false, after: true },
67 { initialChecked: true, initialMixed: false, before: true, after: false },
68 { initialChecked: false, initialMixed: true, before: "mixed", after: true },
69 ])("exposes $before before activation and $after after activation", async (state) => {
70 await renderSwitch(state.initialChecked, state.initialMixed);
71 expect(switchRoot().getAttribute("aria-checked")).toBe(String(state.before));
72
73 await clickSwitch();
74
75 expect(switchRoot().getAttribute("aria-checked")).toBe(String(state.after));
76 expect(container.querySelector<HTMLInputElement>('input[type="checkbox"]')?.checked).toBe(
77 state.after,
78 );
79 });
80});