From 497abe902db02c9e41a4081528b3e8c23cf246fc Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Wed, 5 Feb 2025 15:58:04 +0000 Subject: [PATCH] chore: add storybook stories for combobox component (#16451) --- .../components/Combobox/Combobox.stories.tsx | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 site/src/components/Combobox/Combobox.stories.tsx diff --git a/site/src/components/Combobox/Combobox.stories.tsx b/site/src/components/Combobox/Combobox.stories.tsx new file mode 100644 index 0000000000..2786f35b0b --- /dev/null +++ b/site/src/components/Combobox/Combobox.stories.tsx @@ -0,0 +1,132 @@ +import type { Meta, StoryObj } from "@storybook/react"; +import { expect, screen, userEvent, waitFor, within } from "@storybook/test"; +import { useState } from "react"; +import { Combobox } from "./Combobox"; + +const options = ["Option 1", "Option 2", "Option 3", "Another Option"]; + +const ComboboxWithHooks = () => { + const [value, setValue] = useState(""); + const [open, setOpen] = useState(false); + const [inputValue, setInputValue] = useState(""); + + return ( + { + if (e.key === "Enter" && inputValue && !options.includes(inputValue)) { + setValue(inputValue); + setInputValue(""); + setOpen(false); + } + }} + /> + ); +}; + +const meta: Meta = { + title: "components/Combobox", + component: Combobox, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + render: () => , +}; + +export const OpenCombobox: Story = { + render: () => , + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button")); + + await waitFor(() => expect(screen.getByRole("dialog")).toBeInTheDocument()); + }, +}; + +export const SelectOption: Story = { + render: () => , + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button")); + await userEvent.click(screen.getByText("Option 1")); + + await waitFor(() => + expect(canvas.getByRole("button")).toHaveTextContent("Option 1"), + ); + }, +}; + +export const SearchAndFilter: Story = { + render: () => , + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button")); + await userEvent.type(screen.getByRole("combobox"), "Another"); + await userEvent.click( + screen.getByRole("option", { name: "Another Option" }), + ); + + await waitFor(() => { + expect( + screen.getByRole("option", { name: "Another Option" }), + ).toBeInTheDocument(); + expect( + screen.queryByRole("option", { name: "Option 1" }), + ).not.toBeInTheDocument(); + }); + }, +}; + +export const EnterCustomValue: Story = { + render: () => , + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button")); + await userEvent.type(screen.getByRole("combobox"), "Custom Value{enter}"); + + await waitFor(() => + expect(canvas.getByRole("button")).toHaveTextContent("Custom Value"), + ); + }, +}; + +export const NoResults: Story = { + render: () => , + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click(canvas.getByRole("button")); + await userEvent.type(screen.getByRole("combobox"), "xyz"); + + await waitFor(() => { + expect(screen.getByText("No results found")).toBeInTheDocument(); + expect(screen.getByText("Enter custom value")).toBeInTheDocument(); + }); + }, +}; + +export const ClearSelectedOption: Story = { + render: () => , + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + + await userEvent.click(canvas.getByRole("button")); + // First select an option + await userEvent.click(screen.getByRole("option", { name: "Option 1" })); + // Then clear it by selecting it again + await userEvent.click(screen.getByRole("option", { name: "Option 1" })); + + await waitFor(() => + expect(canvas.getByRole("button")).toHaveTextContent("Select option"), + ); + }, +};