import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, it, expect, vi } from "vitest";
import { DialogField } from "./DialogField";
describe("DialogField - visibility", () => {
it("returns null when showWhen is false", () => {
const { container } = render(
Content
);
expect(container.innerHTML).toBe("");
});
it("renders when showWhen is true (default)", () => {
const { container } = render(
Content
);
expect(container.innerHTML).not.toBe("");
});
});
describe("DialogField - content rendering", () => {
it("renders title when open", () => {
render(
Body
);
expect(screen.getByText("My Dialog")).toBeInTheDocument();
});
it("renders description when open", () => {
render(
Body
);
expect(screen.getByText("Some description")).toBeInTheDocument();
});
it("renders children content when open", () => {
render(
Dialog body content
);
expect(screen.getByText("Dialog body content")).toBeInTheDocument();
});
it("does not render dialog content when closed", () => {
render(
Hidden content
);
expect(screen.queryByText("Hidden")).not.toBeInTheDocument();
expect(screen.queryByText("Hidden content")).not.toBeInTheDocument();
});
});
describe("DialogField - close button", () => {
it("renders close button by default", () => {
render(
Content
);
expect(screen.getByRole("button", { name: "Close dialog" })).toBeInTheDocument();
});
it("hides close button when showCloseButton=false", () => {
render(
Content
);
expect(screen.queryByRole("button", { name: "Close dialog" })).not.toBeInTheDocument();
});
it("calls onOpenChange(false) when close button is clicked", async () => {
const user = userEvent.setup();
const onOpenChange = vi.fn();
render(
Content
);
await user.click(screen.getByRole("button", { name: "Close dialog" }));
expect(onOpenChange).toHaveBeenCalledWith(false);
});
it("calls onClose when close button is clicked", async () => {
const user = userEvent.setup();
const onClose = vi.fn();
render(
Content
);
await user.click(screen.getByRole("button", { name: "Close dialog" }));
expect(onClose).toHaveBeenCalledTimes(1);
});
});
describe("DialogField - trigger mode", () => {
it("renders trigger element", () => {
render(
Open} title="T">
Content
);
expect(screen.getByRole("button", { name: "Open" })).toBeInTheDocument();
});
it("opens dialog when trigger is clicked", async () => {
const user = userEvent.setup();
render(
Open} title="Triggered Dialog">
Dialog content
);
expect(screen.queryByText("Triggered Dialog")).not.toBeInTheDocument();
await user.click(screen.getByRole("button", { name: "Open" }));
expect(screen.getByText("Triggered Dialog")).toBeInTheDocument();
expect(screen.getByText("Dialog content")).toBeInTheDocument();
});
});
describe("DialogField - keyboard / outside click", () => {
it("closes on Escape key by default", async () => {
const user = userEvent.setup();
const onOpenChange = vi.fn();
render(
Content
);
await user.keyboard("{Escape}");
expect(onOpenChange).toHaveBeenCalledWith(false);
});
it("does not close on Escape when closeOnEscape=false", async () => {
const user = userEvent.setup();
const onOpenChange = vi.fn();
render(
Content
);
await user.keyboard("{Escape}");
expect(onOpenChange).not.toHaveBeenCalled();
});
});
describe("DialogField - width/height classes", () => {
// Radix Dialog renders into a portal (document.body), not container
const widthCases: Array<[string, string]> = [
["NARROW", "max-w-sm"],
["MEDIUM", "max-w-md"],
["MEDIUM_PLUS", "max-w-lg"],
["WIDE", "max-w-2xl"],
];
widthCases.forEach(([width, expectedClass]) => {
it(`width="${width}" applies ${expectedClass}`, () => {
render(
Content
);
const content = document.body.querySelector(`[class*="${expectedClass}"]`);
expect(content).toBeInTheDocument();
});
});
const heightCases: Array<[string, string]> = [
["SHORT", "h-[300px]"],
["MEDIUM", "h-[500px]"],
["TALL", "h-[700px]"],
];
heightCases.forEach(([height, expectedClass]) => {
it(`height="${height}" applies ${expectedClass}`, () => {
render(
Content
);
expect(document.body.innerHTML).toContain(expectedClass);
});
});
});