diff --git a/src/components/__tests__/Button.test.tsx b/src/components/__tests__/Button.test.tsx
new file mode 100644
index 0000000..b86f1e1
--- /dev/null
+++ b/src/components/__tests__/Button.test.tsx
@@ -0,0 +1,46 @@
+import { render, screen } from "@testing-library/react";
+import { Button } from "../Button";
+
+describe("Button", () => {
+ it("renders the primary variant by default", () => {
+ render();
+
+ expect(screen.getByRole("button", { name: /save route/i }).className).toMatch(
+ /bg-black/
+ );
+ });
+
+ it("applies each supported variant", () => {
+ render(
+ <>
+
+
+ >
+ );
+
+ expect(screen.getByRole("button", { name: /cancel/i }).className).toMatch(
+ /border-neutral-300/
+ );
+ expect(screen.getByRole("button", { name: /delete/i }).className).toMatch(
+ /bg-rose-600/
+ );
+ });
+
+ it("supports disabled state and forwards arbitrary props", () => {
+ render(
+
+ );
+
+ const button = screen.getByTestId("route-button");
+ expect(button).toBeDisabled();
+ expect(button).toHaveAttribute("aria-label", "Submit route");
+ expect(button).toHaveAttribute("type", "submit");
+ expect(button.className).toMatch(/tracking-wide/);
+ });
+});
diff --git a/src/components/__tests__/Card.test.tsx b/src/components/__tests__/Card.test.tsx
index 1cc596f..3d99a45 100644
--- a/src/components/__tests__/Card.test.tsx
+++ b/src/components/__tests__/Card.test.tsx
@@ -16,4 +16,17 @@ describe("Card", () => {
);
expect(screen.getByText(/foot/)).toBeInTheDocument();
});
+
+ it("omits optional regions and forwards div props", () => {
+ render(
+
+ body
+
+ );
+
+ const card = screen.getByTestId("card-shell");
+ expect(card.className).toMatch(/shadow-sm/);
+ expect(card.querySelector("header")).not.toBeInTheDocument();
+ expect(card.querySelector("footer")).not.toBeInTheDocument();
+ });
});
diff --git a/src/components/__tests__/EmptyState.test.tsx b/src/components/__tests__/EmptyState.test.tsx
new file mode 100644
index 0000000..a09ae12
--- /dev/null
+++ b/src/components/__tests__/EmptyState.test.tsx
@@ -0,0 +1,26 @@
+import { render, screen } from "@testing-library/react";
+import { EmptyState } from "../EmptyState";
+
+describe("EmptyState", () => {
+ it("renders the title, description, and action when provided", () => {
+ render(
+ Create route}
+ description="There are no active routes yet."
+ title="No routes"
+ />
+ );
+
+ expect(screen.getByText("No routes")).toBeInTheDocument();
+ expect(screen.getByText("There are no active routes yet.")).toBeInTheDocument();
+ expect(screen.getByRole("button", { name: /create route/i })).toBeInTheDocument();
+ });
+
+ it("omits optional slots when they are not provided", () => {
+ render();
+
+ expect(screen.getByText("No alerts")).toBeInTheDocument();
+ expect(screen.queryByText("There are no active routes yet.")).not.toBeInTheDocument();
+ expect(screen.queryByRole("button")).not.toBeInTheDocument();
+ });
+});
diff --git a/src/components/__tests__/PageHeading.test.tsx b/src/components/__tests__/PageHeading.test.tsx
new file mode 100644
index 0000000..20a930d
--- /dev/null
+++ b/src/components/__tests__/PageHeading.test.tsx
@@ -0,0 +1,31 @@
+import { render, screen } from "@testing-library/react";
+import { PageHeading } from "../PageHeading";
+
+describe("PageHeading", () => {
+ it("renders heading, description, and action content", () => {
+ render(
+ New quote}
+ description="Monitor bridge quotes in one place."
+ title="Route dashboard"
+ />
+ );
+
+ expect(
+ screen.getByRole("heading", { level: 1, name: /route dashboard/i })
+ ).toBeInTheDocument();
+ expect(screen.getByText("Monitor bridge quotes in one place.")).toBeInTheDocument();
+ expect(screen.getByRole("link", { name: /new quote/i })).toHaveAttribute(
+ "href",
+ "/quote"
+ );
+ });
+
+ it("renders only the heading when optional props are omitted", () => {
+ render();
+
+ expect(screen.getByRole("heading", { level: 1, name: /stats/i })).toBeInTheDocument();
+ expect(screen.queryByText("Monitor bridge quotes in one place.")).not.toBeInTheDocument();
+ expect(screen.queryByRole("link")).not.toBeInTheDocument();
+ });
+});