import React from "react"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { Card, CardHeader, CardTitle, CardContent, CardFooter } from "../Card"; describe("Card", () => { // Basic rendering tests describe("Rendering", () => { it("renders card with children", () => { render(Card content); expect(screen.getByText("Card content")).toBeInTheDocument(); }); it("renders with custom className", () => { render(Content); const card = screen.getByText("Content").closest("div"); expect(card).toHaveClass("custom-class"); }); it("renders with different variants", () => { const { rerender } = render(Default); let card = screen.getByText("Default").closest("div"); expect(card).toHaveClass("bg-card", "border", "border-border"); rerender(Outline); card = screen.getByText("Outline").closest("div"); expect(card).toHaveClass("border-2", "border-border", "bg-background"); rerender(Elevated); card = screen.getByText("Elevated").closest("div"); expect(card).toHaveClass("bg-card", "shadow-md"); rerender(Ghost); card = screen.getByText("Ghost").closest("div"); expect(card).toHaveClass("bg-background"); }); it("renders with different padding", () => { const { rerender } = render(Small); let card = screen.getByText("Small").closest("div"); expect(card).toHaveClass("p-4"); rerender(Medium); card = screen.getByText("Medium").closest("div"); expect(card).toHaveClass("p-6"); rerender(Large); card = screen.getByText("Large").closest("div"); expect(card).toHaveClass("p-8"); rerender(None); card = screen.getByText("None").closest("div"); expect(card).not.toHaveClass("p-4", "p-6", "p-8"); }); }); // Props tests describe("Props", () => { it("handles hover prop", () => { render(Hover content); const card = screen.getByText("Hover content").closest("div"); expect(card).toHaveClass("hover:shadow-md"); }); it("handles clickable prop", () => { render(Clickable content); const card = screen.getByText("Clickable content").closest("div"); expect(card).toHaveClass("cursor-pointer", "hover:shadow-md"); }); it("makes card clickable when onClick is provided", () => { const handleClick = jest.fn(); render(Click me); const card = screen.getByText("Click me").closest("div"); expect(card).toHaveClass("cursor-pointer"); }); }); // Interaction tests describe("Interactions", () => { it("calls onClick when clicked", async () => { const handleClick = jest.fn(); const user = userEvent.setup(); render(Click me); await user.click(screen.getByText("Click me")); expect(handleClick).toHaveBeenCalledTimes(1); }); it("supports keyboard interaction when clickable", async () => { const handleClick = jest.fn(); const user = userEvent.setup(); render( Clickable ); const card = screen.getByText("Clickable").closest("div"); expect(card).toHaveAttribute("tabIndex", "0"); // Focus and press Enter card?.focus(); await user.keyboard("{Enter}"); expect(handleClick).toHaveBeenCalledTimes(1); // Press Space await user.keyboard(" "); expect(handleClick).toHaveBeenCalledTimes(2); }); }); // Edge cases describe("Edge cases", () => { it("forwards ref correctly", () => { const ref = React.createRef(); render(Content); expect(ref.current).toBeInstanceOf(HTMLDivElement); }); }); }); describe("CardHeader", () => { it("renders with children", () => { render(Header content); expect(screen.getByText("Header content")).toBeInTheDocument(); }); it("renders with custom className", () => { render(Header); const header = screen.getByText("Header"); expect(header).toHaveClass("custom-header"); }); it("has proper default styling", () => { render(Header); const header = screen.getByText("Header"); expect(header).toHaveClass("flex", "flex-col", "space-y-1.5", "p-6"); }); it("forwards ref correctly", () => { const ref = React.createRef(); render(Header); expect(ref.current).toBeInstanceOf(HTMLDivElement); }); }); describe("CardTitle", () => { it("renders with children", () => { render(Title content); expect(screen.getByText("Title content")).toBeInTheDocument(); }); it("renders with custom className", () => { render(Title); const title = screen.getByText("Title"); expect(title).toHaveClass("custom-title"); }); it("renders with different heading levels", () => { const { rerender } = render(Title); let title = screen.getByText("Title"); expect(title.tagName).toBe("H1"); rerender(Title); title = screen.getByText("Title"); expect(title.tagName).toBe("H2"); rerender(Title); title = screen.getByText("Title"); expect(title.tagName).toBe("H3"); }); it("defaults to h3", () => { render(Default Title); const title = screen.getByText("Default Title"); expect(title.tagName).toBe("H3"); }); it("forwards ref correctly", () => { const ref = React.createRef(); render(Title); expect(ref.current).toBeInstanceOf(HTMLHeadingElement); }); }); describe("CardContent", () => { it("renders with children", () => { render(Content here); expect(screen.getByText("Content here")).toBeInTheDocument(); }); it("renders with custom className", () => { render(Content); const content = screen.getByText("Content"); expect(content).toHaveClass("custom-content"); }); it("has proper default styling", () => { render(Content); const content = screen.getByText("Content"); expect(content).toHaveClass("p-6", "pt-0"); }); it("handles noPadding prop", () => { render(No padding); const content = screen.getByText("No padding"); expect(content).not.toHaveClass("p-6", "pt-0"); }); it("forwards ref correctly", () => { const ref = React.createRef(); render(Content); expect(ref.current).toBeInstanceOf(HTMLDivElement); }); }); describe("CardFooter", () => { it("renders with children", () => { render(Footer content); expect(screen.getByText("Footer content")).toBeInTheDocument(); }); it("renders with custom className", () => { render(Footer); const footer = screen.getByText("Footer"); expect(footer).toHaveClass("custom-footer"); }); it("has proper default styling", () => { render(Footer); const footer = screen.getByText("Footer"); expect(footer).toHaveClass("flex", "items-center", "p-6", "pt-0"); }); it("handles different justify options", () => { const { rerender } = render(Start); let footer = screen.getByText("Start"); expect(footer).toHaveClass("justify-start"); rerender(Center); footer = screen.getByText("Center"); expect(footer).toHaveClass("justify-center"); rerender(End); footer = screen.getByText("End"); expect(footer).toHaveClass("justify-end"); rerender(Between); footer = screen.getByText("Between"); expect(footer).toHaveClass("justify-between"); }); it("forwards ref correctly", () => { const ref = React.createRef(); render(Footer); expect(ref.current).toBeInstanceOf(HTMLDivElement); }); });