import React from "react";
import { render, screen } from "@testing-library/react";
import { Stack } from "./stack";
describe("Stack", () => {
// ============================================================================
// Rendering Tests
// ============================================================================
it("renders with default props", () => {
render(Content);
expect(screen.getByText("Content")).toBeInTheDocument();
});
it("renders children correctly", () => {
render(
Child 1
Child 2
);
expect(screen.getByText("Child 1")).toBeInTheDocument();
expect(screen.getByText("Child 2")).toBeInTheDocument();
});
it("renders as div by default", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack.tagName).toBe("DIV");
});
it("always has base stack class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack");
});
// ============================================================================
// Polymorphic Rendering Tests
// ============================================================================
it("renders as different elements via as prop", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack.tagName).toBe("SECTION");
});
it("renders as article", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack.tagName).toBe("ARTICLE");
});
it("renders as nav", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack.tagName).toBe("NAV");
});
it("renders as ul", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack.tagName).toBe("UL");
});
it("renders as ol", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack.tagName).toBe("OL");
});
// ============================================================================
// Direction Class Tests
// ============================================================================
it("applies vertical direction class by default", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-vertical");
});
it("applies vertical direction class explicitly", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-vertical");
});
it("applies horizontal direction class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-horizontal");
});
// ============================================================================
// Gap Class Tests
// ============================================================================
it("applies gap-0 class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-gap-0");
});
it("applies gap-xs class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-gap-xs");
});
it("applies gap-sm class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-gap-sm");
});
it("applies gap-md class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-gap-md");
});
it("applies gap-lg class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-gap-lg");
});
it("applies gap-xl class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-gap-xl");
});
// ============================================================================
// Align Class Tests (Cross-Axis)
// ============================================================================
it("applies align-start class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-align-start");
});
it("applies align-center class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-align-center");
});
it("applies align-end class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-align-end");
});
it("applies align-stretch class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-align-stretch");
});
// ============================================================================
// Justify Class Tests (Main-Axis)
// ============================================================================
it("applies justify-start class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-justify-start");
});
it("applies justify-center class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-justify-center");
});
it("applies justify-end class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-justify-end");
});
it("applies justify-between class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-justify-between");
});
// ============================================================================
// Wrap Class Tests
// ============================================================================
it("applies wrap class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-wrap");
});
it("applies nowrap class", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-nowrap");
});
// ============================================================================
// Multiple Props Tests
// ============================================================================
it("applies multiple utility classes", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack");
expect(stack).toHaveClass("stack-horizontal");
expect(stack).toHaveClass("stack-gap-lg");
expect(stack).toHaveClass("stack-align-center");
expect(stack).toHaveClass("stack-justify-between");
expect(stack).toHaveClass("stack-wrap");
});
it("combines vertical direction with other props", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-vertical");
expect(stack).toHaveClass("stack-gap-md");
expect(stack).toHaveClass("stack-align-start");
expect(stack).toHaveClass("stack-justify-center");
});
// ============================================================================
// Custom Class Tests
// ============================================================================
it("merges custom className with utility classes", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack");
expect(stack).toHaveClass("stack-vertical");
expect(stack).toHaveClass("stack-gap-md");
expect(stack).toHaveClass("custom-class");
});
it("merges custom classes prop with utility classes", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack");
expect(stack).toHaveClass("stack-gap-md");
expect(stack).toHaveClass("legacy-class");
});
it("merges both className and classes with utility classes", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack");
expect(stack).toHaveClass("stack-gap-md");
expect(stack).toHaveClass("custom-class");
expect(stack).toHaveClass("legacy-class");
});
// ============================================================================
// Inline Styles Tests
// ============================================================================
it("applies custom styles", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveStyle({ backgroundColor: "rgb(255, 0, 0)" });
expect(stack).toHaveStyle({ color: "rgb(255, 255, 255)" });
});
it("accepts CSS custom properties in styles", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveAttribute("style");
});
// ============================================================================
// Ref Forwarding Tests
// ============================================================================
it("forwards ref correctly", () => {
const ref = React.createRef();
render(
Content
);
expect(ref.current).toBeInstanceOf(HTMLDivElement);
});
it("forwards ref with polymorphic as prop", () => {
const ref = React.createRef();
render(
Content
);
expect(ref.current).toBeInstanceOf(HTMLElement);
expect(ref.current?.tagName).toBe("SECTION");
});
// ============================================================================
// Accessibility Tests
// ============================================================================
it("forwards ARIA attributes", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveAttribute("aria-label", "Test Stack");
expect(stack).toHaveAttribute("role", "region");
});
it("forwards data attributes", () => {
render(
Content
);
const stack = screen.getByTestId("stack");
expect(stack).toHaveAttribute("data-custom", "value");
});
// ============================================================================
// Edge Cases
// ============================================================================
it("handles empty children", () => {
render();
const stack = screen.getByTestId("stack");
expect(stack).toBeInTheDocument();
expect(stack).toBeEmptyDOMElement();
});
it("handles no optional props gracefully", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toBeInTheDocument();
expect(stack).toHaveClass("stack");
expect(stack).toHaveClass("stack-vertical");
expect(stack.tagName).toBe("DIV");
});
it("handles only direction prop", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack");
expect(stack).toHaveClass("stack-horizontal");
// Should not have gap, align, justify, or wrap classes when not provided
expect(stack.className.split(" ").length).toBe(2); // only "stack" and "stack-horizontal"
});
// ============================================================================
// Layout Behavior Tests
// ============================================================================
it("creates vertical flex container by default", () => {
render(Content);
const stack = screen.getByTestId("stack");
// Base stack class ensures display: flex is applied
expect(stack).toHaveClass("stack");
});
it("creates horizontal flex container when direction is horizontal", () => {
render(Content);
const stack = screen.getByTestId("stack");
expect(stack).toHaveClass("stack-horizontal");
});
});