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");
});
});
});