import { render, screen, cleanup } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import assert from "node:assert";
import {
describe, test, mock, afterEach,
} from "node:test";
import { Label } from "./index";
describe("Label", () => {
afterEach(() => {
cleanup();
});
/* COMMON */
test("renders without crashing", () => {
render();
const label = document.querySelector("label");
assert.notStrictEqual(label, null);
});
test("renders label text", () => {
render();
assert.notStrictEqual(screen.queryByText("Username"), null);
});
test("renders children instead of label", () => {
render(
);
assert.notStrictEqual(screen.queryByTestId("child"), null);
assert.strictEqual(screen.queryByText("Should not appear"), null);
});
test("passes htmlFor attribute", () => {
render();
const label = document.querySelector("label");
assert.strictEqual(label?.getAttribute("for"), "username-input");
});
test("passes title attribute", () => {
render();
const label = document.querySelector("label");
assert.strictEqual(label?.getAttribute("title"), "Field label");
});
test("passes extra attributes", () => {
render(
);
const label = document.querySelector("label");
assert.strictEqual(label?.getAttribute("data-testid"), "custom-label");
assert.strictEqual(label?.getAttribute("aria-label"), "Username field");
});
test("applies base class", () => {
render();
const label = document.querySelector("label");
assert.strictEqual(label?.className.includes("customLabel"), true);
});
test("applies extra classes", () => {
render(
);
const label = document.querySelector("label");
const classNames = label?.className || "";
assert.strictEqual(classNames.includes("large"), true);
assert.strictEqual(classNames.includes("bold"), true);
assert.strictEqual(classNames.includes("hidden"), false);
});
/* REQUIRED STATE */
test("shows isRequired modifier when isRequired=true", () => {
render();
const label = document.querySelector("label");
assert.strictEqual(label?.className.includes("isRequired"), true);
});
test("does not show isRequired modifier when isRequired=false", () => {
render();
const label = document.querySelector("label");
assert.strictEqual(label?.className.includes("isRequired"), false);
});
test("updates isRequired modifier when prop changes", () => {
const { rerender } = render();
let label = document.querySelector("label");
assert.strictEqual(label?.className.includes("isRequired"), false);
rerender();
label = document.querySelector("label");
assert.strictEqual(label?.className.includes("isRequired"), true);
});
/* INTERACTIONS */
test("calls onClick when clicked", async () => {
const onClick = mock.fn();
const user = userEvent.setup();
render();
await user.click(screen.getByText("Click me"));
assert.strictEqual(onClick.mock.calls.length, 1);
});
/* INTEGRATION */
test("focuses associated input when clicked", async () => {
const user = userEvent.setup();
render(
<>
>
);
await user.click(screen.getByText("Test field"));
const input = screen.getByTestId("test-input");
assert.strictEqual(document.activeElement, input);
});
/* EDGE CASES */
test("handles empty label", () => {
render();
const span = document.querySelector("span");
assert.strictEqual(span?.textContent, "");
});
test("handles no props", () => {
render();
const label = document.querySelector("label");
assert.notStrictEqual(label, null);
const span = document.querySelector("span");
assert.notStrictEqual(span, null);
});
test("handles long text", () => {
const longText = "Very long label text that should still render properly without any issues or truncation";
render();
assert.notStrictEqual(screen.queryByText(longText), null);
});
});