diff --git a/apps/loopover-ui/src/routes/app.index.test.tsx b/apps/loopover-ui/src/routes/app.index.test.tsx
new file mode 100644
index 0000000000..3048a714fa
--- /dev/null
+++ b/apps/loopover-ui/src/routes/app.index.test.tsx
@@ -0,0 +1,41 @@
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it } from "vitest";
+
+import { TooltipProvider } from "@/components/ui/tooltip";
+import { SparkStat } from "./app.index";
+
+// #6984: SparkStat's loading branch hand-rolled its own animate-pulse divs instead of the shared
+// Skeleton primitive every other loading placeholder in this app already uses.
+describe("SparkStat loading state (#6984)", () => {
+ it("renders Skeleton placeholders (not the raw hand-rolled divs) while loading", () => {
+ const { container } = render(
+ ,
+ );
+
+ expect(screen.getByRole("status", { name: "Loading Open PRs" })).toBeTruthy();
+ // Skeleton renders animate-pulse blocks; the label/value/sparkline placeholders are 3 in total.
+ expect(container.querySelectorAll(".animate-pulse").length).toBe(3);
+ // The real label/value text never renders while loading.
+ expect(screen.queryByText("Open PRs")).toBeNull();
+ expect(screen.queryByText("4")).toBeNull();
+ });
+
+ it("renders the real label and value once data is available (not loading)", () => {
+ render(
+
+
+ ,
+ );
+
+ expect(screen.getByText("Open PRs")).toBeTruthy();
+ expect(screen.getByText("4")).toBeTruthy();
+ expect(screen.queryByRole("status", { name: "Loading Open PRs" })).toBeNull();
+ });
+});
diff --git a/apps/loopover-ui/src/routes/app.index.tsx b/apps/loopover-ui/src/routes/app.index.tsx
index 89acdac9f0..5791de28fc 100644
--- a/apps/loopover-ui/src/routes/app.index.tsx
+++ b/apps/loopover-ui/src/routes/app.index.tsx
@@ -16,6 +16,7 @@ import {
X,
} from "lucide-react";
+import { Skeleton } from "@/components/ui/skeleton";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import { StatusPill } from "@/components/site/control-primitives";
@@ -494,7 +495,7 @@ function OnboardingChecklist() {
);
}
-function SparkStat({
+export function SparkStat({
label,
value,
hint,
@@ -518,10 +519,10 @@ function SparkStat({
aria-label={`Loading ${label}`}
className="rounded-token border-hairline bg-card p-4"
>
-
+
);