import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { expect, test, describe, vi } from "vitest";
import Input from "../../app/components/Input";
describe("Input Component", () => {
test("renders with default props", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toBeInTheDocument();
expect(input).toHaveAttribute("type", "text");
});
test("renders with label", () => {
render();
expect(screen.getByText("Test input")).toBeInTheDocument();
expect(screen.getByLabelText("Test input")).toBeInTheDocument();
});
test("renders with placeholder", () => {
render();
const input = screen.getByPlaceholderText("Enter text...");
expect(input).toBeInTheDocument();
});
test("renders with value", () => {
render();
const input = screen.getByDisplayValue("test value");
expect(input).toBeInTheDocument();
});
test("calls onChange when text is entered", () => {
const handleChange = vi.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.change(input, { target: { value: "new text" } });
expect(handleChange).toHaveBeenCalledWith(expect.any(Object));
});
test("calls onFocus when focused", () => {
const handleFocus = vi.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.focus(input);
expect(handleFocus).toHaveBeenCalledWith(expect.any(Object));
});
test("calls onBlur when blurred", () => {
const handleBlur = vi.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.blur(input);
expect(handleBlur).toHaveBeenCalledWith(expect.any(Object));
});
test("does not call onChange when disabled", () => {
const handleChange = vi.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.change(input, { target: { value: "new text" } });
expect(handleChange).not.toHaveBeenCalled();
});
test("does not call onFocus when disabled", () => {
const handleFocus = vi.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.focus(input);
expect(handleFocus).not.toHaveBeenCalled();
});
test("does not call onBlur when disabled", () => {
const handleBlur = vi.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.blur(input);
expect(handleBlur).not.toHaveBeenCalled();
});
test("applies disabled attributes when disabled", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toBeDisabled();
});
test("applies correct size classes", () => {
const { rerender } = render();
let input = screen.getByRole("textbox");
expect(input).toHaveClass("h-[32px]");
rerender();
input = screen.getByRole("textbox");
expect(input).toHaveClass("h-[36px]");
rerender();
input = screen.getByRole("textbox");
expect(input).toHaveClass("h-[40px]");
});
test("applies correct label variant classes", () => {
const { rerender } = render();
let container = screen.getByRole("textbox").closest("div").parentElement;
expect(container).toHaveClass("flex-col");
rerender();
container = screen.getByRole("textbox").closest("div").parentElement;
expect(container).toHaveClass("flex", "items-center");
});
test("applies error state classes", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveClass(
"border-[var(--color-border-default-utility-negative)]",
);
});
test("applies disabled state classes", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveClass("cursor-not-allowed");
expect(input).toHaveClass("bg-[var(--color-content-default-secondary)]");
});
test("applies focus state classes", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveClass(
"border-[var(--color-border-default-utility-info)]",
);
expect(input).toHaveClass("shadow-[0_0_5px_3px_#3281F8]");
});
test("applies hover state classes", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveClass("border-[var(--color-border-default-tertiary)]");
expect(input).toHaveClass(
"shadow-[0_0_0_2px_var(--color-border-default-tertiary)]",
);
});
test("applies active state classes", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveClass("border-[var(--color-border-default-tertiary)]");
});
test("applies default state classes", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveClass("border-[var(--color-border-default-tertiary)]");
expect(input).toHaveClass(
"hover:shadow-[0_0_0_2px_var(--color-border-default-tertiary)]",
);
});
test("applies custom className", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveClass("custom-class");
});
test("passes through additional props", () => {
render();
const input = screen.getByRole("textbox");
expect(input).toHaveAttribute("id", "test-input");
expect(input).toHaveAttribute("name", "test");
expect(input).toHaveAttribute("type", "email");
});
test("generates unique ID when not provided", () => {
render();
const input = screen.getByRole("textbox");
const label = screen.getByText("Test");
expect(input).toHaveAttribute("id");
expect(label).toHaveAttribute("for", input.id);
});
test("uses provided ID when given", () => {
render();
const input = screen.getByRole("textbox");
const label = screen.getByText("Test");
expect(input).toHaveAttribute("id", "custom-id");
expect(label).toHaveAttribute("for", "custom-id");
});
test("applies correct border radius style", () => {
const { rerender } = render();
let input = screen.getByRole("textbox");
expect(input).toHaveStyle("border-radius: var(--measures-radius-small)");
rerender();
input = screen.getByRole("textbox");
expect(input).toHaveStyle("border-radius: var(--measures-radius-medium)");
rerender();
input = screen.getByRole("textbox");
expect(input).toHaveStyle("border-radius: var(--measures-radius-large)");
});
test("applies opacity wrapper when disabled", () => {
render();
const wrapper = screen.getByRole("textbox").closest("div");
expect(wrapper).toHaveClass("opacity-40");
});
test("does not apply opacity wrapper when not disabled", () => {
render();
const wrapper = screen.getByRole("textbox").closest("div");
expect(wrapper).not.toHaveClass("opacity-40");
});
test("applies correct label styling", () => {
render();
const label = screen.getByText("Test label");
expect(label).toHaveClass("text-[12px]");
expect(label).toHaveClass("leading-[14px]");
expect(label).toHaveClass("font-medium");
expect(label).toHaveClass("text-[var(--color-content-default-secondary)]");
});
test("applies correct input text styling for different sizes", () => {
const { rerender } = render();
let input = screen.getByRole("textbox");
expect(input).toHaveClass("text-[10px]");
rerender();
input = screen.getByRole("textbox");
expect(input).toHaveClass("text-[14px]");
expect(input).toHaveClass("leading-[20px]");
rerender();
input = screen.getByRole("textbox");
expect(input).toHaveClass("text-[16px]");
expect(input).toHaveClass("leading-[24px]");
});
test("handles keyboard navigation", () => {
const handleFocus = vi.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.keyDown(input, { key: "Tab" });
fireEvent.focus(input);
expect(handleFocus).toHaveBeenCalled();
});
test("forwards ref correctly", () => {
const ref = React.createRef();
render();
expect(ref.current).toBeInstanceOf(HTMLInputElement);
});
test("is memoized", () => {
expect(Input.$$typeof).toBe(Symbol.for("react.memo"));
});
});