import { expect, fn, userEvent, within } from "storybook/test"; import type { Meta, StoryObj } from "@storybook/react-vite"; import type { ReactNode } from "react"; import { Story } from "../story-components/Story"; import { StoryGrid } from "../story-components/StoryGrid"; import { InputPassword, type InputPasswordProps } from "./InputPassword"; type ThisStory = StoryObj; type ForcedState = NonNullable; type InputState = ForcedState | "disabled" | "invalid"; function StateCol({ state, ...props }: Pick & { state: InputState | undefined; }): ReactNode { if (state === "disabled") { return ( ); } if (state === "invalid") { return ( ); } return ( ); } function StateRow( props: Pick, ): ReactNode { return ( ); } export default { title: "alouette/Inputs/InputPassword", component: InputPassword, parameters: { componentSubtitle: "Password field with an eye toggle in its end slot to show what was typed.", }, argTypes: { placeholder: { control: "text" }, disabled: { control: "boolean" }, defaultVisible: { control: "boolean" }, toggleLabel: { control: "text" }, }, } satisfies Meta; export const InputPasswordPreviewStory: ThisStory = { name: "InputPassword Preview", parameters: { layout: "padded", chromatic: { disableSnapshot: true }, }, args: { placeholder: "Password" }, render: (args) => , }; export const InputPasswordVariantsStory: ThisStory = { name: "InputPassword Variants", render: () => ( ), }; function ControlledDemo({ onVisibleChange, }: Pick): ReactNode { return ( ); } export const InputPasswordTestsStory: ThisStory = { name: "InputPassword Tests", render: () => ( ), play: async ({ canvasElement }) => { const canvas = within(canvasElement); const input = canvas.getByLabelText("Password"); const toggle = canvas.getByRole("button", { name: "Show password" }); await expect(input).toHaveAttribute("type", "password"); await expect(input).toHaveAttribute("autocomplete", "current-password"); await expect(toggle).toHaveAttribute("aria-pressed", "false"); // react-native-web emits `type` only for a secure or typed entry: a plain // text input has none. await userEvent.click(toggle); await expect(input).not.toHaveAttribute("type"); await expect(input).toHaveValue("hunter2"); await expect(toggle).toHaveAttribute("aria-pressed", "true"); await userEvent.click(toggle); await expect(input).toHaveAttribute("type", "password"); await expect(toggle).toHaveAttribute("aria-pressed", "false"); // Disabled: the toggle is disabled with the field. const disabledToggle = canvas.getByRole("button", { name: "Show disabled password", }); await expect(disabledToggle).toHaveAttribute("aria-disabled", "true"); await expect(canvas.getByLabelText("Disabled password")).toBeDisabled(); // Controlled: the press only reports, the field stays hidden. const controlled = canvas.getByLabelText("Controlled"); const controlledToggle = canvas.getByRole("button", { name: "Show controlled password", }); await userEvent.click(controlledToggle); await expect(controlled).toHaveAttribute("type", "password"); await expect(controlledToggle).toHaveAttribute("aria-pressed", "false"); }, };