diff --git a/frontend/src/components/Dashboard/StatsCard.test.tsx b/frontend/src/components/Dashboard/StatsCard.test.tsx
new file mode 100644
index 0000000..1183d15
--- /dev/null
+++ b/frontend/src/components/Dashboard/StatsCard.test.tsx
@@ -0,0 +1,95 @@
+import { describe, it, expect } from "vitest";
+import { render, screen } from "@testing-library/react";
+import "@testing-library/jest-dom";
+import StatsCard from "./StatsCard";
+
+describe("StatsCard", () => {
+ // -------------------------------------------------------------------------
+ // Normal rendering
+ // -------------------------------------------------------------------------
+ describe("normal value rendering", () => {
+ it("renders the title", () => {
+ render();
+ expect(screen.getByText("Total Settlements")).toBeInTheDocument();
+ });
+
+ it("renders the value when provided", () => {
+ render();
+ expect(screen.getByText("42")).toBeInTheDocument();
+ });
+
+ it("does not render a skeleton when value is a non-empty string", () => {
+ render();
+ expect(screen.queryByRole("status")).not.toBeInTheDocument();
+ });
+
+ it("renders value '0' without a skeleton (falsy-but-valid value)", () => {
+ render();
+ expect(screen.getByText("0")).toBeInTheDocument();
+ expect(screen.queryByRole("status")).not.toBeInTheDocument();
+ });
+ });
+
+ // -------------------------------------------------------------------------
+ // Loading skeleton for null / undefined
+ // -------------------------------------------------------------------------
+ describe("loading skeleton state", () => {
+ it("renders a loading skeleton when value is null", () => {
+ render();
+ expect(screen.getByRole("status")).toBeInTheDocument();
+ });
+
+ it("renders a loading skeleton when value is undefined", () => {
+ render();
+ expect(screen.getByRole("status")).toBeInTheDocument();
+ });
+
+ it("does not render the value paragraph when value is null", () => {
+ render();
+ // The value paragraph should be absent; only the skeleton status element.
+ const valueEl = screen.queryByText(/^\d/);
+ expect(valueEl).not.toBeInTheDocument();
+ });
+
+ it("skeleton has an accessible label that includes the card title", () => {
+ render();
+ // The Skeleton component renders with aria-label on the status div.
+ expect(screen.getByRole("status", { name: /Active Disputes/i })).toBeInTheDocument();
+ });
+
+ it("still renders the card title while the value is loading", () => {
+ render();
+ expect(screen.getByText("Pending Approvals")).toBeInTheDocument();
+ });
+ });
+
+ // -------------------------------------------------------------------------
+ // Variant classes
+ // -------------------------------------------------------------------------
+ describe("variant prop", () => {
+ it("applies the default variant class by default", () => {
+ const { container } = render();
+ expect(container.firstChild).toHaveClass("stats-card--default");
+ });
+
+ it("applies the success variant class", () => {
+ const { container } = render();
+ expect(container.firstChild).toHaveClass("stats-card--success");
+ });
+
+ it("applies the warning variant class", () => {
+ const { container } = render();
+ expect(container.firstChild).toHaveClass("stats-card--warning");
+ });
+
+ it("applies the danger variant class", () => {
+ const { container } = render();
+ expect(container.firstChild).toHaveClass("stats-card--danger");
+ });
+
+ it("applies the correct variant class even when value is null (loading state)", () => {
+ const { container } = render();
+ expect(container.firstChild).toHaveClass("stats-card--danger");
+ });
+ });
+});
diff --git a/frontend/src/components/Dashboard/StatsCard.tsx b/frontend/src/components/Dashboard/StatsCard.tsx
index 3e00243..8704984 100644
--- a/frontend/src/components/Dashboard/StatsCard.tsx
+++ b/frontend/src/components/Dashboard/StatsCard.tsx
@@ -1,8 +1,9 @@
+import { Skeleton } from "../Skeleton";
import "./StatsCard.css";
interface StatsCardProps {
title: string;
- value: string;
+ value: string | null | undefined;
variant?: "default" | "success" | "warning" | "danger";
}
@@ -10,7 +11,16 @@ export default function StatsCard({ title, value, variant = "default" }: StatsCa
return (
{title}
-
{value}
+ {value == null ? (
+
+ ) : (
+
{value}
+ )}
);
}