Files
sass-mohfarawati/tests/component/ui-primitives.test.tsx
T
Moh e2e06be86e test: add comprehensive automated test coverage
- Vitest multi-project setup (unit / integration / component)
- Real-Postgres integration harness via in-process PGlite (TEST_DATABASE_URL
  override), migrations applied per worker; production code untouched
- Unit: routing, locale, validation/Zod schemas, metadata, mail, site-theme,
  marquee, media, portfolio helpers, plus architecture-rule tests
- Integration: Prisma data layer, API routes, and all server actions
- Component: UI primitives and form components (jsdom + Testing Library)
- 371 tests passing
2026-08-06 02:27:20 +02:00

150 lines
5.2 KiB
TypeScript

import { createRef } from "react";
import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { AppCard } from "@/components/ui/app-card";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { Textarea } from "@/components/ui/textarea";
import { Container } from "@/components/layout/container";
import { HeroBadge } from "@/components/layout/hero-badge";
import { SectionHeading } from "@/components/home/section-heading";
describe("Badge", () => {
it("renders children and default variant classes", () => {
render(<Badge>New</Badge>);
const badge = screen.getByText("New");
expect(badge).toHaveClass("bg-primary");
});
it("applies a chosen variant and merges custom classNames", () => {
render(<Badge variant="success" className="custom-class">OK</Badge>);
const badge = screen.getByText("OK");
expect(badge).toHaveClass("bg-status-success-soft");
expect(badge).toHaveClass("custom-class");
});
it("passes through arbitrary props", () => {
render(<Badge data-testid="b" title="tip">X</Badge>);
expect(screen.getByTestId("b")).toHaveAttribute("title", "tip");
});
});
describe("Input", () => {
it("forwards the ref and renders attributes", () => {
const ref = createRef<HTMLInputElement>();
render(<Input ref={ref} type="email" placeholder="you@example.com" disabled />);
const input = screen.getByPlaceholderText("you@example.com");
expect(ref.current).toBe(input);
expect(input).toHaveAttribute("type", "email");
expect(input).toBeDisabled();
});
it("merges custom classes", () => {
render(<Input className="w-20" aria-label="field" />);
expect(screen.getByLabelText("field")).toHaveClass("w-20");
});
});
describe("Textarea", () => {
it("forwards the ref and renders a default value", () => {
const ref = createRef<HTMLTextAreaElement>();
render(<Textarea ref={ref} defaultValue="hello" aria-label="msg" />);
const textarea = screen.getByLabelText("msg");
expect(ref.current).toBe(textarea);
expect(textarea).toHaveValue("hello");
});
});
describe("Label", () => {
it("associates with a control via htmlFor", () => {
render(<Label htmlFor="name">Name</Label>);
expect(screen.getByText("Name")).toHaveAttribute("for", "name");
});
});
describe("Separator", () => {
it("defaults to a horizontal separator", () => {
const { container } = render(<Separator />);
expect(container.firstChild).toHaveClass("h-px", "w-full");
});
it("supports a vertical orientation", () => {
const { container } = render(<Separator orientation="vertical" />);
expect(container.firstChild).toHaveClass("h-full", "w-px");
});
});
describe("Card family", () => {
it("composes header, title, description and content", () => {
render(
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Desc</CardDescription>
</CardHeader>
<CardContent>Body</CardContent>
</Card>,
);
expect(screen.getByRole("heading", { name: "Title" })).toBeInTheDocument();
expect(screen.getByText("Desc")).toBeInTheDocument();
expect(screen.getByText("Body")).toBeInTheDocument();
});
});
describe("AppCard", () => {
it("renders a single-layer card with its children", () => {
render(<AppCard layer="single">Single</AppCard>);
expect(screen.getByText("Single")).toBeInTheDocument();
});
it("renders a double-layer card (default) with its children", () => {
render(<AppCard>Double</AppCard>);
expect(screen.getByText("Double")).toBeInTheDocument();
});
});
describe("Container", () => {
it("applies the size variant classes", () => {
const { container } = render(<Container size="narrow">Body</Container>);
expect(container.firstChild).toHaveClass("max-w-narrow");
});
it("renders as a child element when asChild is set", () => {
render(
<Container asChild>
<section data-testid="as-child">X</section>
</Container>,
);
expect(screen.getByTestId("as-child").tagName).toBe("SECTION");
});
});
describe("HeroBadge", () => {
it("renders children and optional trailing content", () => {
render(<HeroBadge trailing={<span></span>}>Available</HeroBadge>);
expect(screen.getByText("Available")).toBeInTheDocument();
expect(screen.getByText("→")).toBeInTheDocument();
});
});
describe("SectionHeading", () => {
it("renders eyebrow, title and description", () => {
render(<SectionHeading eyebrow="Work" title="Projects" description="What I build" />);
expect(screen.getByText("Work")).toBeInTheDocument();
expect(screen.getByRole("heading", { name: "Projects" })).toBeInTheDocument();
expect(screen.getByText("What I build")).toBeInTheDocument();
});
it("centers content when align is center", () => {
const { container } = render(
<SectionHeading eyebrow="E" title="T" description="D" align="center" />,
);
expect(container.firstChild).toHaveClass("text-center");
});
});