import { describe, it, expect, afterEach, vi } from "vitest";
import "@testing-library/jest-dom/vitest";
import { render, cleanup, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { Spoiler } from "./Spoiler";
afterEach(cleanup);
describe("wrapper element customization", () => {
it("renders a span wrapper by default", () => {
const { container } = render(Hello!);
const element = container.firstElementChild!;
expect(element).toBeInTheDocument();
expect(element.tagName).toBe("SPAN");
});
it("passes standard props to the element", () => {
const { container } = render(
Hello!
);
const element = container.firstElementChild!;
expect(element).toHaveClass("custom");
expect(element).toHaveAttribute("dir", "rtl");
});
it("can customize wrapper's tag via `tagName` prop", () => {
const { container } = render(
);
const divElement = container.firstElementChild!;
expect(divElement).toBeInTheDocument();
expect(divElement).toContainHTML('
');
});
it("attaches directly to the element given as children when `asChild` prop is used", () => {
const { getByLabelText } = render(
);
expect(getByLabelText("hello")).toBeInTheDocument();
expect(getByLabelText("hello").tagName).toBe("BLOCKQUOTE");
});
});
describe("controlled/uncontrolled Spoiler Component", () => {
it("calls onHiddenChange with false when clicked (default is hidden)", async () => {
const changeHandler = vi.fn();
const { getByText } = render(
Click me
);
await userEvent.click(getByText("Click me"));
await waitFor(() => expect(changeHandler).toHaveBeenCalledWith(false));
});
it("calls onChange with true when clicked (defaultHidden is false)", async () => {
const changeHandler = vi.fn();
const { getByText } = render(
Click me
);
await userEvent.click(getByText("Click me"));
await waitFor(() => expect(changeHandler).toHaveBeenCalledWith(true));
});
it("controls Spoiler's visibility via `hidden` prop", () => {
const { container, rerender } = render(Always hidden);
expect(container.firstElementChild!).toHaveAttribute("aria-expanded", "false");
rerender(Always visible);
expect(container.firstElementChild!).not.toHaveAttribute("aria-expanded", "false");
});
});
describe("Spoiler options", () => {
it("accepts custom spoiler painter options", () => {
Hey;
// @ts-expect-error - This should error in TypeScript due to unknown prop
Hey;
});
});
describe("content transitions via `transition` keyword", () => {
it('renders one wrapper element when it is falsey or "none"', () => {
const { getByText } = render(
Spoiler Alert: Dumbledore joins Voldemort
);
const element = getByText(/Voldemort/);
expect(element).toBeInTheDocument();
expect(element.tagName).toBe("SPAN");
expect(element.parentElement?.tagName).not.toBe("SPAN");
});
it("renders with specified transition", () => {
const { getByText } = render(
Spoiler Alert: Frodo keeps the Ring
);
const element = getByText(/Frodo/);
expect(element).toBeInTheDocument();
// should be span within a span
expect(element.tagName).toBe("SPAN");
expect(element.parentElement?.tagName).toBe("SPAN");
});
});