import React from "react"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Input } from "../Input"; describe("Input", () => { // Basic rendering tests describe("Rendering", () => { it("renders input with default props", () => { render(); const input = screen.getByRole("textbox"); expect(input).toBeInTheDocument(); expect(input).toHaveAttribute("type", "text"); }); it("renders with custom className", () => { render(); const input = screen.getByRole("textbox"); expect(input.parentElement?.parentElement).toHaveClass("custom-class"); }); it("renders with different input types", () => { const { rerender } = render(); let input = screen.getByRole("textbox"); expect(input).toHaveAttribute("type", "email"); rerender(); input = screen.getByDisplayValue("") as HTMLInputElement; expect(input).toHaveAttribute("type", "password"); rerender(); input = screen.getByRole("spinbutton"); expect(input).toHaveAttribute("type", "number"); }); it("renders with different sizes", () => { const { rerender } = render(); let input = screen.getByRole("textbox"); expect(input).toHaveClass("h-8"); rerender(); input = screen.getByRole("textbox"); expect(input).toHaveClass("h-10"); rerender(); input = screen.getByRole("textbox"); expect(input).toHaveClass("h-12"); }); }); // Props tests describe("Props", () => { it("handles placeholder", () => { render(); const input = screen.getByPlaceholderText("Enter text"); expect(input).toBeInTheDocument(); }); it("handles value and defaultValue", () => { const { unmount } = render( {}} /> ); let input = screen.getByDisplayValue("controlled"); expect(input).toBeInTheDocument(); unmount(); render(); input = screen.getByDisplayValue("uncontrolled"); expect(input).toBeInTheDocument(); }); it("handles disabled state", () => { render(); const input = screen.getByRole("textbox"); expect(input).toBeDisabled(); }); it("handles readOnly state", () => { render(); const input = screen.getByRole("textbox"); expect(input).toHaveAttribute("readonly"); }); it("handles required state", () => { render(); const input = screen.getByRole("textbox"); expect(input).toHaveAttribute("required"); }); it("handles error state", () => { render(); const input = screen.getByRole("textbox"); expect(input).toHaveClass("border-destructive"); expect(screen.getByText("Error message")).toBeInTheDocument(); }); }); // Label and help text tests describe("Label and Help Text", () => { it("renders with label", () => { render(); const label = screen.getByText("Username"); const input = screen.getByRole("textbox"); expect(label).toBeInTheDocument(); expect(input).toHaveAttribute("id"); expect(label).toHaveAttribute("for", input.getAttribute("id")); }); it("renders required indicator with label", () => { render(); expect(screen.getByText("*")).toBeInTheDocument(); }); it("renders help text", () => { render(); expect(screen.getByText("Enter your username")).toBeInTheDocument(); }); it("renders error message with proper ARIA", () => { render(); const errorElement = screen.getByText("Username is required"); expect(errorElement).toHaveAttribute("role", "alert"); expect(errorElement).toHaveAttribute("aria-live", "polite"); }); }); // Icon tests describe("Icons", () => { it("renders with left icon", () => { const icon = 🔍; render(); expect(screen.getByTestId("left-icon")).toBeInTheDocument(); }); it("renders with right icon", () => { const icon = ; render(); expect(screen.getByTestId("right-icon")).toBeInTheDocument(); }); }); // Password toggle tests describe("Password Toggle", () => { it("renders password toggle button", () => { render(); const toggleButton = screen.getByLabelText("Show password"); expect(toggleButton).toBeInTheDocument(); }); it("toggles password visibility", async () => { const user = userEvent.setup(); render(); const input = screen.getByRole("textbox"); const toggleButton = screen.getByLabelText("Show password"); expect(input).toHaveAttribute("type", "password"); await user.click(toggleButton); expect(input).toHaveAttribute("type", "text"); expect(screen.getByLabelText("Hide password")).toBeInTheDocument(); const hideButton = screen.getByLabelText("Hide password"); await user.click(hideButton); expect(input).toHaveAttribute("type", "password"); expect(screen.getByLabelText("Show password")).toBeInTheDocument(); }); }); // Interaction tests describe("Interactions", () => { it("calls onChange when value changes", async () => { const handleChange = jest.fn(); const user = userEvent.setup(); render(); const input = screen.getByRole("textbox"); await user.type(input, "hello"); expect(handleChange).toHaveBeenCalledTimes(5); // Called for each character }); it("calls onFocus when focused", async () => { const handleFocus = jest.fn(); const user = userEvent.setup(); render(); const input = screen.getByRole("textbox"); await user.click(input); expect(handleFocus).toHaveBeenCalledTimes(1); }); it("calls onBlur when blurred", async () => { const handleBlur = jest.fn(); const user = userEvent.setup(); render(); const input = screen.getByRole("textbox"); await user.click(input); await user.tab(); expect(handleBlur).toHaveBeenCalledTimes(1); }); }); // Accessibility tests describe("Accessibility", () => { it("has proper ARIA attributes for error state", () => { render(); const input = screen.getByRole("textbox"); expect(input).toHaveAttribute("aria-invalid", "true"); }); it("links help text with aria-describedby", () => { render(); const input = screen.getByRole("textbox"); const helpTextId = input.getAttribute("aria-describedby"); expect(helpTextId).toBeTruthy(); expect(screen.getByText("Help text")).toHaveAttribute("id", helpTextId); }); it("supports keyboard navigation", async () => { const user = userEvent.setup(); render(); const input = screen.getByRole("textbox"); await user.tab(); expect(input).toHaveFocus(); }); }); // Edge cases describe("Edge cases", () => { it("forwards ref correctly", () => { const ref = React.createRef(); render(); expect(ref.current).toBeInstanceOf(HTMLInputElement); }); it("handles multiple class names", () => { render(); const container = screen.getByRole("textbox").parentElement?.parentElement; expect(container).toHaveClass("class1", "class2"); }); }); });