diff --git a/src/app/agents/[agent]/page.test.tsx b/src/app/agents/[agent]/page.test.tsx index 538acfb..0077fcf 100644 --- a/src/app/agents/[agent]/page.test.tsx +++ b/src/app/agents/[agent]/page.test.tsx @@ -77,4 +77,70 @@ describe("AgentDetailPage", () => { const currentItem = screen.getByText(specialId, { selector: '[aria-current="page"]' }); expect(currentItem).toBeInTheDocument(); }); + + it("formats a large lifetime total with thousands separators", async () => { + mockApiGet.mockReset(); + mockApiGet.mockImplementation((url: string) => { + if (url.endsWith("/total")) return Promise.resolve({ total: 1234567 }) as never; + if (url.endsWith("/usage")) return Promise.resolve({ items: [] }) as never; + return Promise.reject(new Error("Not found")) as never; + }); + + renderPage("agent-big"); + + const strong = await screen.findByText("1,234,567"); + expect(strong.tagName).toBe("STRONG"); + expect(strong.parentElement).toHaveTextContent("1,234,567 requests"); + }); + + it("formats per-service totals with thousands separators", async () => { + mockApiGet.mockReset(); + mockApiGet.mockImplementation((url: string) => { + if (url.endsWith("/total")) return Promise.resolve({ total: 0 }) as never; + if (url.endsWith("/usage")) + return Promise.resolve({ + items: [ + { serviceId: "svc-a", total: 999 }, + { serviceId: "svc-b", total: 1500000 }, + ], + }) as never; + return Promise.reject(new Error("Not found")) as never; + }); + + renderPage("agent-svc"); + + await screen.findByText(/Lifetime total/i); + + expect(screen.getByText("999 requests")).toBeInTheDocument(); + expect(screen.getByText("1,500,000 requests")).toBeInTheDocument(); + }); + + it("renders zero total without grouping", async () => { + mockApiGet.mockReset(); + mockApiGet.mockImplementation((url: string) => { + if (url.endsWith("/total")) return Promise.resolve({ total: 0 }) as never; + if (url.endsWith("/usage")) return Promise.resolve({ items: [] }) as never; + return Promise.reject(new Error("Not found")) as never; + }); + + renderPage("agent-zero"); + + const strong = await screen.findByText("0"); + expect(strong.tagName).toBe("STRONG"); + }); + + it("does not render lifetime total when the optional total fetch fails", async () => { + mockApiGet.mockReset(); + mockApiGet.mockImplementation((url: string) => { + if (url.endsWith("/total")) return Promise.reject(new Error("boom")) as never; + if (url.endsWith("/usage")) return Promise.resolve({ items: [] }) as never; + return Promise.reject(new Error("Not found")) as never; + }); + + renderPage("agent-no-total"); + + await screen.findByText(/No services consumed yet/i); + + expect(screen.queryByText(/Lifetime total/i)).not.toBeInTheDocument(); + }); }); diff --git a/src/app/agents/[agent]/page.tsx b/src/app/agents/[agent]/page.tsx index 8489b19..a53b67e 100644 --- a/src/app/agents/[agent]/page.tsx +++ b/src/app/agents/[agent]/page.tsx @@ -3,6 +3,7 @@ import { useEffect, useState, use } from "react"; import { Breadcrumb } from "@/components/Breadcrumb"; import { apiGet } from "@/lib/apiClient"; +import { formatRequests } from "@/lib/format"; type Usage = { agent: string; items: { serviceId: string; total: number }[] }; @@ -44,7 +45,7 @@ export default function AgentDetailPage({ )} {total !== null && (
- Lifetime total: {total} requests + Lifetime total: {formatRequests(total)} requests
)} {items && items.length === 0 && ( @@ -55,7 +56,7 @@ export default function AgentDetailPage({ {items.map((s) => (