import React from "react"; import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { expect, test, describe, it, vi } from "vitest"; import { axe, toHaveNoViolations } from "jest-axe"; import Select from "../../app/components/Select"; expect.extend(toHaveNoViolations); describe("Select Component", () => { const defaultProps = { label: "Test Select", placeholder: "Select an option", options: [ { value: "option1", label: "Option 1" }, { value: "option2", label: "Option 2" }, { value: "option3", label: "Option 3" }, ], }; describe("Rendering", () => { it("renders with default props", () => { render(, ); expect(screen.queryByText("Test Select")).not.toBeInTheDocument(); expect(screen.getByText("Select an option")).toBeInTheDocument(); }); it("renders with horizontal label variant", () => { render(); const container = screen.getByText("Test Select").closest("div"); expect(container).toHaveClass("flex", "flex-col"); }); }); describe("Size Variants", () => { it("renders small size correctly", () => { render(); const selectButton = screen.getByRole("button"); expect(selectButton).toHaveClass("h-[36px]"); }); it("renders large size correctly", () => { render(, ); const selectButton = screen.getByRole("button"); expect(selectButton).toHaveClass("h-[30px]"); }); it("applies correct height for small default label", () => { render(); const selectButton = screen.getByRole("button"); expect(selectButton).toHaveClass( "border-[var(--color-border-default-tertiary)]", ); }); it("renders hover state", () => { render(); const selectButton = screen.getByRole("button"); expect(selectButton).toHaveClass( "border-[var(--color-border-default-utility-info)]", ); expect(selectButton).toHaveClass("shadow-[0_0_5px_3px_#3281F8]"); }); it("renders error state", () => { render(); const selectButton = screen.getByRole("button"); expect(selectButton).toHaveClass("cursor-not-allowed"); expect(selectButton).toHaveClass("opacity-40"); }); }); describe("Interaction", () => { it("opens dropdown when clicked", async () => { const user = userEvent.setup(); render(); const selectButton = screen.getByRole("button"); await user.click(selectButton); await waitFor(() => { expect(screen.getByText("Option 1")).toBeInTheDocument(); }); await user.click(selectButton); await waitFor(() => { expect(screen.queryByText("Option 1")).not.toBeInTheDocument(); }); }); it("selects an option when clicked", async () => { const user = userEvent.setup(); const onChange = vi.fn(); render(); const selectButton = screen.getByRole("button"); await user.click(selectButton); await waitFor(() => { expect(screen.getByText("Option 1")).toBeInTheDocument(); }); await user.click(screen.getByText("Option 1")); await waitFor(() => { expect(screen.queryByText("Option 2")).not.toBeInTheDocument(); }); }); it("does not open when disabled", async () => { const user = userEvent.setup(); render(); const selectButton = screen.getByRole("button"); selectButton.focus(); await user.keyboard("{Enter}"); await waitFor(() => { expect(screen.getByText("Option 1")).toBeInTheDocument(); }); }); it("opens dropdown with Space key", async () => { const user = userEvent.setup(); render(); const selectButton = screen.getByRole("button"); await user.click(selectButton); await waitFor(() => { expect(screen.getByText("Option 1")).toBeInTheDocument(); }); await user.keyboard("{Escape}"); await waitFor(() => { expect(screen.queryByText("Option 1")).not.toBeInTheDocument(); }); }); it("does not respond to keyboard when disabled", async () => { const user = userEvent.setup(); render(
Outside element
, ); const selectButton = screen.getByRole("button"); await user.click(selectButton); await waitFor(() => { expect(screen.getByText("Option 1")).toBeInTheDocument(); }); await user.click(screen.getByTestId("outside")); await waitFor(() => { expect(screen.queryByText("Option 1")).not.toBeInTheDocument(); }); }); }); describe("Value Display", () => { it("shows placeholder when no value selected", () => { render(); const selectButton = screen.getByRole("button"); await user.click(selectButton); await waitFor(() => { expect(screen.getByText("Option 1")).toBeInTheDocument(); }); await user.click(screen.getByText("Option 1")); expect(screen.getByText("Option 1")).toBeInTheDocument(); expect(screen.queryByText("Select an option")).not.toBeInTheDocument(); }); it("shows selected value when value prop is provided", () => { render(); const results = await axe(container); expect(results).toHaveNoViolations(); }); it("has proper ARIA attributes", () => { render(); const selectButton = screen.getByRole("button"); await user.click(selectButton); await waitFor(() => { expect(selectButton).toHaveAttribute("aria-expanded", "true"); }); }); it("associates label with select button", () => { render(); const selectButton = screen.getByRole("button"); await user.tab(); expect(selectButton).toHaveFocus(); expect(selectButton).toHaveClass( "focus-visible:border-[var(--color-border-default-utility-info)]", ); }); it("does not enter focus state when clicked", async () => { const user = userEvent.setup(); render(