mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-14 14:57:00 +10:00
b321e01658
# Conflicts: # packages/ui/src/components/input-group.test.tsx
177 lines
5.1 KiB
TypeScript
177 lines
5.1 KiB
TypeScript
import { fireEvent, render, screen } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { describe, expect, it, test } from "vitest";
|
|
import { createPortal } from "react-dom";
|
|
import {
|
|
InputGroup,
|
|
InputGroupAddon,
|
|
InputGroupButton,
|
|
InputGroupInput,
|
|
InputGroupText,
|
|
InputGroupTextarea,
|
|
} from "./input-group";
|
|
|
|
function PortaledInput() {
|
|
return createPortal(<input aria-label="Portaled input" />, document.body);
|
|
}
|
|
|
|
describe("InputGroup", () => {
|
|
it("renders a fieldset with data-slot='input-group'", () => {
|
|
render(<InputGroup data-testid="g" />);
|
|
const g = screen.getByTestId("g");
|
|
expect(g.tagName).toBe("FIELDSET");
|
|
expect(g).toHaveAttribute("data-slot", "input-group");
|
|
});
|
|
|
|
it("merges custom className", () => {
|
|
render(<InputGroup data-testid="g" className="my-class" />);
|
|
expect(screen.getByTestId("g")).toHaveClass("my-class");
|
|
});
|
|
});
|
|
|
|
describe("InputGroupAddon", () => {
|
|
it("defaults align to 'inline-start'", () => {
|
|
render(<InputGroupAddon data-testid="addon" />);
|
|
expect(screen.getByTestId("addon")).toHaveAttribute("data-align", "inline-start");
|
|
});
|
|
|
|
it.each(["inline-start", "inline-end", "block-start", "block-end"] as const)("supports align=%s", (align) => {
|
|
render(<InputGroupAddon data-testid="addon" align={align} />);
|
|
expect(screen.getByTestId("addon")).toHaveAttribute("data-align", align);
|
|
});
|
|
|
|
it("uses data-slot='input-group-addon'", () => {
|
|
render(<InputGroupAddon data-testid="addon" />);
|
|
expect(screen.getByTestId("addon")).toHaveAttribute("data-slot", "input-group-addon");
|
|
});
|
|
|
|
it("focuses sibling input on click outside of buttons", () => {
|
|
render(
|
|
<InputGroup>
|
|
<InputGroupAddon data-testid="addon">addon</InputGroupAddon>
|
|
<InputGroupInput data-testid="i" />
|
|
</InputGroup>,
|
|
);
|
|
|
|
const addon = screen.getByTestId("addon");
|
|
fireEvent.click(addon);
|
|
expect(document.activeElement).toBe(screen.getByTestId("i"));
|
|
});
|
|
|
|
it("focuses sibling input on Enter key", () => {
|
|
render(
|
|
<InputGroup>
|
|
<InputGroupAddon data-testid="addon">addon</InputGroupAddon>
|
|
<InputGroupInput data-testid="i" />
|
|
</InputGroup>,
|
|
);
|
|
|
|
const addon = screen.getByTestId("addon");
|
|
fireEvent.keyDown(addon, { key: "Enter" });
|
|
expect(document.activeElement).toBe(screen.getByTestId("i"));
|
|
});
|
|
|
|
it("focuses sibling input on Space key", () => {
|
|
render(
|
|
<InputGroup>
|
|
<InputGroupAddon data-testid="addon">addon</InputGroupAddon>
|
|
<InputGroupInput data-testid="i" />
|
|
</InputGroup>,
|
|
);
|
|
|
|
const addon = screen.getByTestId("addon");
|
|
fireEvent.keyDown(addon, { key: " " });
|
|
expect(document.activeElement).toBe(screen.getByTestId("i"));
|
|
});
|
|
|
|
it("ignores unrelated keys", () => {
|
|
render(
|
|
<InputGroup>
|
|
<InputGroupAddon data-testid="addon">addon</InputGroupAddon>
|
|
<InputGroupInput data-testid="i" />
|
|
</InputGroup>,
|
|
);
|
|
|
|
const addon = screen.getByTestId("addon");
|
|
fireEvent.keyDown(addon, { key: "a" });
|
|
expect(document.activeElement).not.toBe(screen.getByTestId("i"));
|
|
});
|
|
|
|
test("does not redirect focus from controls rendered through a portal", async () => {
|
|
const user = userEvent.setup();
|
|
|
|
render(
|
|
<InputGroup>
|
|
<InputGroupAddon align="inline-end">
|
|
<span>Addon</span>
|
|
<PortaledInput />
|
|
</InputGroupAddon>
|
|
|
|
<InputGroupInput aria-label="Outer input" />
|
|
</InputGroup>,
|
|
);
|
|
|
|
const portaledInput = screen.getByLabelText("Portaled input");
|
|
const outerInput = screen.getByLabelText("Outer input");
|
|
|
|
await user.click(portaledInput);
|
|
|
|
expect(document.activeElement).toBe(portaledInput);
|
|
expect(document.activeElement).not.toBe(outerInput);
|
|
});
|
|
});
|
|
|
|
describe("InputGroupButton", () => {
|
|
it("defaults to type='button' and variant='ghost'", () => {
|
|
render(<InputGroupButton data-testid="b">x</InputGroupButton>);
|
|
const button = screen.getByTestId("b");
|
|
expect(button).toHaveAttribute("type", "button");
|
|
});
|
|
|
|
it("respects type override", () => {
|
|
render(
|
|
<InputGroupButton data-testid="b" type="submit">
|
|
x
|
|
</InputGroupButton>,
|
|
);
|
|
expect(screen.getByTestId("b")).toHaveAttribute("type", "submit");
|
|
});
|
|
|
|
it("applies data-size for size variants", () => {
|
|
render(
|
|
<InputGroupButton data-testid="b" size="sm">
|
|
x
|
|
</InputGroupButton>,
|
|
);
|
|
expect(screen.getByTestId("b")).toHaveAttribute("data-size", "sm");
|
|
});
|
|
});
|
|
|
|
describe("InputGroupText", () => {
|
|
it("renders as a span", () => {
|
|
render(<InputGroupText>label</InputGroupText>);
|
|
expect(screen.getByText("label").tagName).toBe("SPAN");
|
|
});
|
|
|
|
it("merges custom className", () => {
|
|
render(<InputGroupText className="my-class">x</InputGroupText>);
|
|
expect(screen.getByText("x")).toHaveClass("my-class");
|
|
});
|
|
});
|
|
|
|
describe("InputGroupInput", () => {
|
|
it("uses data-slot='input-group-control'", () => {
|
|
render(<InputGroupInput data-testid="i" />);
|
|
expect(screen.getByTestId("i")).toHaveAttribute("data-slot", "input-group-control");
|
|
});
|
|
});
|
|
|
|
describe("InputGroupTextarea", () => {
|
|
it("uses data-slot='input-group-control' and renders textarea", () => {
|
|
render(<InputGroupTextarea data-testid="t" />);
|
|
const t = screen.getByTestId("t");
|
|
expect(t.tagName).toBe("TEXTAREA");
|
|
expect(t).toHaveAttribute("data-slot", "input-group-control");
|
|
});
|
|
});
|