import { expect, waitFor, within } from "storybook/test"; import type { Meta, StoryObj } from "@storybook/react-vite"; import { Story, neutralAndAccents } from "../story-components/Story"; import { StoryGrid, stateTitle } from "../story-components/StoryGrid"; import { Switch } from "./Switch"; type ThisStory = StoryObj; export default { title: "alouette/Inputs/Switch", component: Switch, parameters: { componentSubtitle: "Toggle switch with platform-native rendering on iOS/Android.", }, argTypes: { disabled: { control: "boolean" }, checked: { control: "boolean" }, }, } satisfies Meta; export const PreviewSwitchStory: ThisStory = { parameters: { layout: "padded", chromatic: { disableSnapshot: true }, }, render: (args) => , }; export const Variants: ThisStory = { render: () => ( {neutralAndAccents.map((accent) => [false, true].map((onAccentSurface) => ( {( [ undefined, "hover", "focus", "press", "disabled", "checked", "disabled:checked", ] as const ).map((state) => ( ))} )), )} ), }; export const Tests: StoryObj = { name: "Switch Tests", render() { return ( ); }, play: async ({ canvasElement }) => { const canvas = within(canvasElement); const uncontrolledSwitch = canvas.getByTestId("uncontrolled"); await expect(uncontrolledSwitch).toBeInTheDocument(); // react-native-web maps no element to the switch role: https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/modules/AccessibilityUtil/propsToAccessibilityComponent.js await expect(uncontrolledSwitch.tagName).toBe("DIV"); await expect(uncontrolledSwitch).toHaveAttribute("role", "switch"); await expect(uncontrolledSwitch).toHaveAttribute("aria-checked", "false"); uncontrolledSwitch.click(); await waitFor(() => expect(uncontrolledSwitch).toHaveAttribute("aria-checked", "true"), ); const uncheckedSwitch = canvas.getByTestId("unchecked"); await expect(uncheckedSwitch).toBeInTheDocument(); await expect(uncheckedSwitch).toHaveAttribute("role", "switch"); await expect(uncheckedSwitch).toHaveAttribute("aria-checked", "false"); uncheckedSwitch.click(); await expect(uncheckedSwitch).toHaveAttribute("aria-checked", "false"); const checkedSwitch = canvas.getByTestId("checked"); await expect(checkedSwitch).toBeInTheDocument(); await expect(checkedSwitch).toHaveAttribute("role", "switch"); await expect(checkedSwitch).toHaveAttribute("aria-checked", "true"); checkedSwitch.click(); await expect(checkedSwitch).toHaveAttribute("aria-checked", "true"); // Keyboard focus (focus-visible) rings the track, not the oversized // pressable that holds the focus. A programmatic focus() counts as // keyboard input for `:focus-visible`. const track = uncontrolledSwitch.firstElementChild; if (!(track instanceof HTMLElement)) throw new Error("No switch track"); uncontrolledSwitch.focus(); await expect(uncontrolledSwitch).toHaveFocus(); await expect(getComputedStyle(uncontrolledSwitch).outlineWidth).toBe("0px"); await expect(getComputedStyle(track).outlineWidth).toBe("2px"); await expect(getComputedStyle(track).outlineOffset).toBe("2px"); }, };