///
import React from "react";
import { Checkbox } from "./index";
import { fireEvent, render, screen } from "@testing-library/react";
jest.mock("@shared/components/button", () => {
const MockButton = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes
>(({ children, ...props }, ref) => (
));
MockButton.displayName = "MockButton";
return { Button: MockButton };
});
jest.mock("@shared/utils", () => ({
cx: (...args: unknown[]) => args.filter(Boolean).join(" "),
}));
describe("Checkbox", () => {
describe("rendering", () => {
it("renders an unchecked checkbox by default", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).not.toBeChecked();
});
it("renders a checked checkbox when checked is true", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toBeChecked();
});
it("renders with the correct name attribute", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toHaveAttribute("name", "agreement");
});
it("renders with the correct value attribute", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toHaveAttribute("value", "yes");
});
it("applies displayName correctly", () => {
expect(Checkbox.displayName).toBe("Checkbox");
});
});
describe("label", () => {
it("renders a string label", () => {
render();
expect(screen.getByText("Accept terms")).toBeInTheDocument();
});
it("renders a ReactNode label", () => {
render(
Custom}
/>
);
expect(screen.getByTestId("custom-label")).toBeInTheDocument();
});
it("does not render label element when label is not provided", () => {
const { container } = render();
const labels = container.querySelectorAll("label");
// Only the icon label, no text label
expect(labels.length).toBe(1);
});
it("applies labelClassName to the label", () => {
render(
);
const label = screen.getByText("Label");
expect(label.className).toContain("custom-label");
});
it("applies error class to label when error is true", () => {
render();
const label = screen.getByText("Label");
expect(label.className).toContain("text-text-critical");
});
});
describe("interactive behavior", () => {
it("calls onChange with boolean when handler expects a parameter", () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const handleChange = jest.fn((_isChecked: boolean) => undefined);
render();
const input = screen.getByRole("checkbox");
fireEvent.click(input);
expect(handleChange).toHaveBeenCalledWith(true);
});
it("calls onChange without parameters for zero-arity handler", () => {
const handleChange = jest.fn();
// Override length to simulate zero-arity
Object.defineProperty(handleChange, "length", { value: 0 });
render();
const input = screen.getByRole("checkbox");
fireEvent.click(input);
expect(handleChange).toHaveBeenCalled();
});
it("does not call onChange when disabled", () => {
const handleChange = jest.fn();
render();
const input = screen.getByRole("checkbox");
fireEvent.click(input);
expect(handleChange).not.toHaveBeenCalled();
});
it("does not call onChange when state is disabled", () => {
const handleChange = jest.fn();
render();
const input = screen.getByRole("checkbox");
fireEvent.click(input);
expect(handleChange).not.toHaveBeenCalled();
});
});
describe("disabled state", () => {
it("sets disabled attribute when disabled prop is true", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toBeDisabled();
});
it("sets disabled attribute when state is disabled", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toBeDisabled();
});
it("applies disabled styling to unchecked icon", () => {
const { container } = render();
const rect = container.querySelector("rect");
expect(rect).toHaveClass("fill-checkbox-bg-surface-disabled");
});
it("applies disabled styling to checked icon", () => {
const { container } = render(
);
const rect = container.querySelector("rect");
expect(rect).toHaveClass("fill-checkbox-bg-surface-selected-disabled");
});
});
describe("focus state", () => {
it("applies focus outline class when state is focus", () => {
const { container } = render();
const label = container.querySelector("label");
expect(label?.className).toContain("outline");
});
});
describe("required", () => {
it("sets required attribute when required is true", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toBeRequired();
});
});
describe("id handling", () => {
it("uses provided id for input and label", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toHaveAttribute("id", "custom-id");
});
it("falls back to name when id is not provided", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toHaveAttribute("id", "fallback-name");
});
});
describe("data-cy attribute", () => {
it("passes data-cy to the input element", () => {
render();
const input = screen.getByRole("checkbox");
expect(input).toHaveAttribute("data-cy", "checkbox-cy");
});
});
describe("renderInfoIcon", () => {
it("renders info icon button when renderInfoIcon is provided", () => {
const onClick = jest.fn();
render(
);
expect(screen.getByTestId("info-btn")).toBeInTheDocument();
});
it("calls onClick when info icon is clicked", () => {
const onClick = jest.fn();
render(
);
fireEvent.click(screen.getByTestId("info-btn"));
expect(onClick).toHaveBeenCalledTimes(1);
});
it("does not render info icon when renderInfoIcon is not provided", () => {
const { container } = render();
const buttons = container.querySelectorAll("button");
expect(buttons.length).toBe(0);
});
it("applies the provided iconSize to the info icon SVG dimensions", () => {
const onClick = jest.fn();
render(
);
const svg = screen.getByTestId("info-btn").querySelector("svg");
expect(svg?.getAttribute("width")).toBe("20");
expect(svg?.getAttribute("height")).toBe("20");
});
it("defaults the info icon SVG dimensions to 24 when iconSize is not provided", () => {
const onClick = jest.fn();
render(
);
const svg = screen.getByTestId("info-btn").querySelector("svg");
expect(svg?.getAttribute("width")).toBe("24");
expect(svg?.getAttribute("height")).toBe("24");
});
});
describe("containerClassName", () => {
it("applies containerClassName to the wrapper div", () => {
const { container } = render(
);
const wrapper = container.firstChild as HTMLElement;
expect(wrapper.className).toContain("wrapper-class");
});
});
describe("checked icon rendering", () => {
it("renders checkmark SVG when checked", () => {
const { container } = render();
const paths = container.querySelectorAll("path");
// Checked state has a checkmark path
expect(paths.length).toBeGreaterThan(0);
});
it("renders empty box SVG when unchecked", () => {
const { container } = render();
const rects = container.querySelectorAll("rect");
// Unchecked state has border rects
expect(rects.length).toBeGreaterThan(0);
});
});
});