import React from "react"; import { render, screen } from "@testing-library/react"; import { Loading } from "../Loading"; describe("Loading", () => { // Basic rendering tests describe("Rendering", () => { it("renders loading indicator", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).toBeInTheDocument(); }); it("renders with custom className", () => { render(); const loadingElement = screen.getByRole("status"); const spinner = loadingElement.querySelector("svg"); expect(spinner).toHaveClass("custom-loading"); }); it("renders with text", () => { render(); expect(screen.getByText("Loading data...")).toBeInTheDocument(); }); it("renders without text by default", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).not.toHaveTextContent(); }); it("renders different sizes", () => { const { rerender } = render(); let spinner = screen.getByRole("status").firstChild; expect(spinner).toHaveClass("w-3", "h-3"); rerender(); spinner = screen.getByRole("status").firstChild; expect(spinner).toHaveClass("w-4", "h-4"); rerender(); spinner = screen.getByRole("status").firstChild; expect(spinner).toHaveClass("w-8", "h-8"); rerender(); spinner = screen.getByRole("status").firstChild; expect(spinner).toHaveClass("w-12", "h-12"); rerender(); spinner = screen.getByRole("status").firstChild; expect(spinner).toHaveClass("w-16", "h-16"); }); }); // Variant tests describe("Variants", () => { it("renders spinner variant by default", () => { render(); const spinner = screen.getByRole("status").firstChild; expect(spinner).toHaveClass("animate-spin"); }); it("renders dots variant", () => { render(); const dotsContainer = screen.getByRole("status").firstChild; expect(dotsContainer).toHaveClass("flex", "space-x-1"); // Should have 3 dots const dots = dotsContainer?.children; expect(dots).toHaveLength(3); }); it("renders pulse variant", () => { render(); const pulseElement = screen.getByRole("status").firstChild; expect(pulseElement).toHaveClass("animate-pulse"); }); it("renders bars variant", () => { render(); const barsContainer = screen.getByRole("status").firstChild; // Should have 4 bars const bars = barsContainer?.children; expect(bars).toHaveLength(4); }); it("renders ring variant", () => { render(); const ring = screen.getByRole("status").firstChild; expect(ring).toHaveClass("relative"); }); }); // Color tests describe("Colors", () => { it("renders with primary color by default", () => { render(); const container = screen.getByRole("status"); expect(container).toHaveClass("text-primary"); }); it("renders with secondary color", () => { render(); const container = screen.getByRole("status"); expect(container).toHaveClass("text-secondary"); }); it("renders with muted color", () => { render(); const container = screen.getByRole("status"); expect(container).toHaveClass("text-muted-foreground"); }); }); // Layout tests describe("Layout", () => { it("centers loading indicator when center prop is true", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).toHaveClass("justify-center"); }); it("does not center by default", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).not.toHaveClass("justify-center"); }); it("renders as overlay when overlay prop is true", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).toHaveClass("fixed", "inset-0", "z-50"); }); it("renders normally when overlay is false", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).not.toHaveClass("fixed", "inset-0", "z-50"); }); }); // Accessibility tests describe("Accessibility", () => { it("has proper role and ARIA attributes", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).toHaveAttribute("role", "status"); expect(loadingElement).toHaveAttribute("aria-live", "polite"); expect(loadingElement).toHaveAttribute("aria-label", "Loading"); }); it("uses custom text for aria-label when provided", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).toHaveAttribute("aria-label", "Loading user data"); }); it("announces text to screen readers", () => { render(); const textElement = screen.getByText("Processing request..."); expect(textElement).toBeInTheDocument(); expect(textElement).toHaveClass("ml-2", "text-sm", "font-medium"); }); }); // Animation tests describe("Animations", () => { it("has proper animation classes for spinner", () => { render(); const spinner = screen.getByRole("status").querySelector("svg"); expect(spinner).toHaveClass("animate-spin"); }); it("has proper animation classes for dots", () => { render(); const dotsContainer = screen.getByRole("status").firstChild; const dots = dotsContainer?.children; // Each dot should have animation style expect(dots?.[0]).toHaveStyle( "animation: loading-dots 1.4s ease-in-out 0s infinite both" ); expect(dots?.[1]).toHaveStyle( "animation: loading-dots 1.4s ease-in-out 0.2s infinite both" ); expect(dots?.[2]).toHaveStyle( "animation: loading-dots 1.4s ease-in-out 0.4s infinite both" ); }); it("has proper animation classes for pulse", () => { render(); const pulseElement = screen.getByRole("status").firstChild; expect(pulseElement).toHaveClass("animate-pulse"); }); it("has proper animation classes for bars", () => { render(); const barsContainer = screen.getByRole("status").firstChild; const bars = barsContainer?.children; // Each bar should have scaling animation expect(bars?.[0]).toHaveStyle( "animation: loading-bars 1s ease-in-out 0s infinite" ); expect(bars?.[1]).toHaveStyle( "animation: loading-bars 1s ease-in-out 0.1s infinite" ); expect(bars?.[2]).toHaveStyle( "animation: loading-bars 1s ease-in-out 0.2s infinite" ); }); it("has proper animation classes for ring", () => { render(); const ring = screen.getByRole("status").firstChild; const animatedElement = ring?.querySelector(".animate-spin"); expect(animatedElement).toBeInTheDocument(); }); }); // Edge cases describe("Edge cases", () => { it("forwards ref correctly", () => { const ref = React.createRef(); render(); expect(ref.current).toBeInstanceOf(HTMLDivElement); }); it("handles empty text gracefully", () => { render(); const loadingElement = screen.getByRole("status"); expect(loadingElement).toHaveAttribute("aria-label", "Loading"); }); it("combines multiple props correctly", () => { render( ); const container = screen.getByRole("status"); expect(container).toHaveClass("text-secondary"); const dotsContainer = container.firstChild; const dots = dotsContainer?.children; expect(dots).toHaveLength(3); expect(dots?.[0]).toHaveClass("w-3", "h-3", "bg-current"); }); it("handles multiple class names", () => { render(); const spinner = screen.getByRole("status").querySelector("svg"); expect(spinner).toHaveClass("class1", "class2"); }); }); });