import React from "react"; import { Select } from "./index"; import { SelectOption } from "./types"; import * as utils from "../../utils"; import { fireEvent, render, screen } from "@testing-library/react"; // Mock react-select to simplify testing jest.mock("react-select", () => { // eslint-disable-next-line @typescript-eslint/no-require-imports const { forwardRef } = require("react"); // eslint-disable-next-line react/display-name const MockSelect = forwardRef((props: any, ref: any) => { const { options, value, placeholder, onChange, className, classNames, ...rest } = props; // Call classNames functions to exercise them for coverage if (classNames) { classNames.control?.({ isFocused: false }); classNames.control?.({ isFocused: true }); classNames.indicatorSeparator?.(); classNames.dropdownIndicator?.({ selectProps: { value: null } }); classNames.dropdownIndicator?.({ selectProps: { value: "test" } }); classNames.singleValue?.(); classNames.menu?.(); classNames.option?.({ isFocused: false, isSelected: false, label: "A" }); classNames.option?.({ isFocused: true, isSelected: false, label: "A" }); classNames.option?.({ isFocused: false, isSelected: true, label: "A" }); classNames.placeholder?.(); classNames.input?.(); classNames.valueContainer?.(); } return ( ); }); return { __esModule: true, default: MockSelect, // eslint-disable-next-line @typescript-eslint/no-unused-vars createFilter: (filterConfig: any) => () => true, }; }); const defaultOptions: SelectOption[] = [ { label: "Option A", value: "a" }, { label: "Option B", value: "b" }, { label: "Option C", value: "c" }, ]; describe("Select", () => { it("renders with options", () => { render(); expect(screen.getByText("Pick one")).toBeInTheDocument(); }); it("appends * to placeholder when required", () => { render( ); fireEvent.change(screen.getByTestId("sel"), { target: { value: "b" } }); expect(onChange).toHaveBeenCalledWith( defaultOptions[1], expect.objectContaining({ action: "select-option" }) ); }); it("renders label when provided", () => { render( ); const label = screen.getByText("Label"); expect(label).toHaveClass("custom-class"); }); it("does not render label when not provided", () => { const { container } = render(); expect(screen.getByText("Required field")).toBeInTheDocument(); }); it("renders helperText when no error", () => { render( ); expect(screen.getByText("Error")).toBeInTheDocument(); expect(screen.queryByText("Choose wisely")).not.toBeInTheDocument(); }); it("renders unstyled variant without label/error wrapper", () => { const { container } = render( ); expect(screen.getByTestId("sm-select")).toBeInTheDocument(); expect( cxSpy.mock.calls.some(call => call[0] === "h-12 px-3 rounded-lg") ).toBe(true); cxSpy.mockRestore(); }); it("applies default (md) size classes", () => { const cxSpy = jest.spyOn(utils, "cx"); render( ); expect(screen.getByTestId("lg-select")).toBeInTheDocument(); expect( cxSpy.mock.calls.some(call => call[0] === "h-16 px-3 rounded-2xl") ).toBe(true); cxSpy.mockRestore(); }); it("falls back to md size classes when size is not provided", () => { const cxSpy = jest.spyOn(utils, "cx"); render( ); expect(screen.getByTestId("sv-select")).toBeInTheDocument(); }); it("passes singleValueClassName into the singleValue cx computation", () => { const cxSpy = jest.spyOn(utils, "cx"); render( ); expect(screen.getByTestId("custom-select")).toBeInTheDocument(); }); it("handles hasError prop", () => { render( ); expect(screen.getByTestId("filter-select")).toBeInTheDocument(); }); it("passes data-cy prop", () => { render( ); const select = screen.getByTestId("val-select") as HTMLSelectElement; expect(select.value).toBe("c"); }); it("has the correct displayName", () => { expect(Select.displayName).toBe("Select"); }); it("exercises option classNames with last option label", () => { // Ensures the last-option border logic is covered const opts = [ { label: "First", value: "1" }, { label: "Last", value: "2" }, ]; render(