import {
cleanup,
createEvent,
fireEvent,
render,
screen,
} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { createRef } from "react";
import assert from "node:assert";
import {
describe, test, mock, afterEach,
} from "node:test";
import { Input } from "./index";
import type { IInputRef } from "./index";
describe("Input", () => {
afterEach(() => {
cleanup();
});
/* COMMON */
test("renders input by default without crashing", () => {
render();
const element = screen.getByRole("textbox");
assert.notStrictEqual(element, null);
assert.strictEqual(element.tagName, "INPUT");
});
test("renders textarea when type is 'textarea'", () => {
render();
const element = screen.getByRole("textbox");
assert.notStrictEqual(element, null);
assert.strictEqual(element.tagName, "TEXTAREA");
});
test("renders with initial value", () => {
render();
assert.strictEqual(screen.getByRole("textbox").getAttribute("value"), "test-value");
});
test("has 'data-js-input-required' attribute when isRequired", () => {
render();
const input = screen.getByRole("textbox");
assert.notStrictEqual(input.getAttribute("data-js-input-required"), null);
});
test("is focused then autoFocus is true", () => {
render();
assert.strictEqual(document.activeElement, screen.getByRole("textbox"));
});
/* HANDLERS */
test("changes value on user input", async () => {
const user = userEvent.setup();
render();
const input = screen.getByRole("textbox") as HTMLInputElement;
await user.type(input, "foo-boo");
assert.strictEqual(input.value, "foo-boo");
});
test("calls onChange with stateActions when value is changed", async () => {
const user = userEvent.setup();
const onChange = mock.fn();
render();
await user.type(screen.getByRole("textbox"), "val");
assert.strictEqual(onChange.mock.calls.length, 3);
const args = onChange.mock.calls[0]?.arguments;
assert.ok(args && typeof args[0] === "object");
assert.ok("stateActions" in args[0]);
});
test("calls onFocus and onBlur with stateActions", async () => {
const user = userEvent.setup();
const onFocus = mock.fn();
const onBlur = mock.fn();
render();
const input = screen.getByRole("textbox");
await user.click(input);
await user.tab();
assert.strictEqual(onFocus.mock.calls.length, 1);
let args = onFocus.mock.calls[0]?.arguments;
assert.ok(args && typeof args[0] === "object");
assert.ok("stateActions" in args[0]);
assert.strictEqual(onBlur.mock.calls.length, 1);
args = onBlur.mock.calls[0]?.arguments;
assert.ok(args && typeof args[0] === "object");
assert.ok("stateActions" in args[0]);
});
test("does not allow typing when disabled", async () => {
const user = userEvent.setup();
render();
const input = screen.getByRole("textbox") as HTMLInputElement;
await user.type(input, "value");
assert.strictEqual(input.value, "");
});
test("does not change value when is readonly", async () => {
const user = userEvent.setup();
render();
const input = screen.getByRole("textbox") as HTMLInputElement;
await user.type(input, "value");
assert.strictEqual(input.value, "foo-");
});
test("calls onReset and resets value on reset", async () => {
const user = userEvent.setup();
const onReset = mock.fn((args) => {
args.stateActions.setValue("");
});
render();
const input = screen.getByRole("textbox") as HTMLInputElement;
await user.type(input, "boo");
assert.strictEqual(input.value, "boo");
fireEvent(input, createEvent("reset", input, { bubbles: true }));
assert.strictEqual(onReset.mock.calls.length, 1);
const args = onReset.mock.calls[0]?.arguments;
assert.ok(args && typeof args[0] === "object");
assert.ok("stateActions" in args[0]);
assert.strictEqual(typeof args[0].stateActions.setValue, "function");
assert.strictEqual(input.value, "");
});
/* CHECKBOX */
test("supports checkbox behavior", async () => {
const user = userEvent.setup();
render();
const checkbox = screen.getByRole("checkbox") as HTMLInputElement;
assert.strictEqual(checkbox.checked, false);
await user.click(checkbox);
assert.strictEqual(checkbox.checked, true);
});
/* REF */
test("exposes imperative ref API", async () => {
const ref = createRef();
render();
assert.ok(ref.current?.el instanceof HTMLElement);
assert.deepStrictEqual(ref.current?.getData(), {
value: "hello",
isChecked: false,
});
});
});