import React from "react";
import { render, fireEvent, screen } from "@testing-library/react";
import TextArea from "../TextArea";
import { axe } from "jest-axe";
import userEvent from "@testing-library/user-event";
describe("TextArea", () => {
it("should render TextArea with default props", () => {
render();
expect(screen.getByRole("textbox")).toBeInTheDocument();
});
it("should render TextArea with a label if provided", () => {
const labelText = "Example Label";
render();
expect(screen.getByLabelText(labelText)).toBeInTheDocument();
});
it("should display help text when provided", () => {
const helpText = "This is some helpful information.";
render();
expect(screen.getByText(helpText)).toBeInTheDocument();
});
it("should render TextArea with different sizes and adjust rows accordingly", () => {
const { rerender } = render();
expect(screen.getByRole("textbox")).toHaveAttribute("rows", "3");
rerender();
expect(screen.getByRole("textbox")).toHaveAttribute("rows", "4");
});
it("should render TextArea with a custom rows count", () => {
render();
expect(screen.getByRole("textbox")).toHaveAttribute("rows", "10");
});
it("should render TextArea as disabled", () => {
render();
expect(screen.getByRole("textbox")).toBeDisabled();
});
it("should render TextArea as readOnly", () => {
render();
expect(screen.getByRole("textbox")).toHaveAttribute("readOnly");
});
it("should show an error state", () => {
render();
expect(screen.getByRole("textbox")).toHaveAttribute("aria-invalid", "true");
});
it("should add required attribute when provided", () => {
render();
expect(screen.getByRole("textbox")).toHaveAttribute("required");
});
it("should handle value updates correctly", () => {
const handleChange = jest.fn();
const { rerender } = render();
expect(screen.getByRole("textbox")).toHaveValue("initial");
fireEvent.change(screen.getByRole("textbox"), { target: { value: "updated" } });
expect(handleChange).toHaveBeenCalledTimes(1);
rerender();
expect(screen.getByRole("textbox")).toHaveValue("updated");
});
it("should call onChange when typing in the TextArea", () => {
const handleChange = jest.fn();
render();
const input = screen.getByRole("textbox");
fireEvent.change(input, { target: { value: "new text" } });
expect(handleChange).toHaveBeenCalledTimes(1);
});
describe("TextArea accessibility", () => {
it("TextArea should be accessible", async () => {
const { container } = render();
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it("should set aria-label attribute correctly", () => {
const ariaLabel = "Test Aria Label";
render();
const textarea = screen.getByRole("textbox");
expect(textarea).toHaveAttribute("aria-label", ariaLabel);
});
it("should set aria-describedby attribute to reference help text ID when help text is provided", () => {
const helpText = "This is some helpful information.";
render();
const textarea = screen.getByRole("textbox");
expect(textarea).toHaveAttribute("aria-describedby", "help-text-textarea-help-text");
});
});
describe("TextArea character count and limit", () => {
it("should not show limit when character limit is not provided", () => {
render();
expect(screen.queryByText("0/")).not.toBeInTheDocument();
});
it("it only shows character count with showCharCount and no MaxLength", () => {
render();
expect(screen.queryByText("0")).toBeInTheDocument();
});
it("should not show character count when only maxLength is provided", () => {
render();
expect(screen.queryByText("0/5")).not.toBeInTheDocument();
});
it("should prevent typing when character limit is reached", () => {
const handleChange = jest.fn();
render();
const charCount = screen.getByText("0/5");
expect(charCount).toBeInTheDocument();
const input = screen.getByRole("textbox");
userEvent.type(input, "12345a");
expect(input).toHaveValue("12345");
expect(charCount).toHaveTextContent("5/5");
expect(handleChange).toHaveBeenCalledTimes(5);
});
it("should allow typing when limit is allowed to be exceeded", () => {
render();
const charCount = screen.getByText("0/10");
expect(charCount).toBeInTheDocument();
const input = screen.getByRole("textbox");
userEvent.type(input, "12345678910");
expect(input).toHaveValue("12345678910");
expect(charCount).toHaveTextContent("11/10");
expect(input).toHaveAttribute("aria-invalid", "true");
});
it("should allow text removal when character limit is exceeded", () => {
render();
const input = screen.getByRole("textbox");
userEvent.type(input, "12345");
// Attempt to add more characters (should be prevented)
userEvent.type(input, "a");
expect(input).toHaveValue("12345");
// Remove a character (should be allowed)
userEvent.type(input, "{backspace}");
userEvent.type(input, "4");
expect(input).toHaveValue("12344");
});
});
});