From 6db82c0d157a597d6dda5fb8f1e75e97c7fbc605 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Sat, 15 Aug 2026 02:31:08 -0700 Subject: [PATCH] test(ui): assert what collaborators are called with, not merely that they were A bare toHaveBeenCalled() passes no matter what the caller passed, so the CSV export could serialize the wrong rows, write the wrong content type, and name the file wrong while its test stayed green. Strengthens the load-bearing cases in three files onto the arguments that carry the behaviour: the rows handed to the CSV serializer, the blob content type, the anchor that gets attached and cleaned up, and the specific message each validation failure shows the user. Two of the discount and margin tests previously asserted the same bare call for different validation failures, so neither could tell the two apart. Each rewrite was proven by mutating the source it covers and confirming the test goes red where the bare assertion stayed green. --- .../_components/use_discount_config.test.ts | 10 +++++--- .../_components/use_margin_config.test.ts | 6 ++--- .../EntityUsageExport/utils.test.ts | 24 +++++++++++++------ 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_discount_config.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_discount_config.test.ts index d0ebb8ee7c7..0ab5f0b08c2 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_discount_config.test.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_discount_config.test.ts @@ -84,7 +84,9 @@ describe("useDiscountConfig", () => { }); expect(success!).toBe(false); - expect(NotificationsManager.fromBackend).toHaveBeenCalled(); + expect(NotificationsManager.fromBackend).toHaveBeenCalledWith( + "Please select a provider and enter discount percentage", + ); }); it("should return false and notify when no discount is provided", async () => { @@ -96,7 +98,9 @@ describe("useDiscountConfig", () => { }); expect(success!).toBe(false); - expect(NotificationsManager.fromBackend).toHaveBeenCalled(); + expect(NotificationsManager.fromBackend).toHaveBeenCalledWith( + "Please select a provider and enter discount percentage", + ); }); it("should return false and notify when the discount exceeds 100", async () => { @@ -152,7 +156,7 @@ describe("useDiscountConfig", () => { }); expect(success!).toBe(true); - expect(NotificationsManager.success).toHaveBeenCalled(); + expect(NotificationsManager.success).toHaveBeenCalledWith("Discount configuration updated successfully"); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_margin_config.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_margin_config.test.ts index 88a865e4fa2..10db6a0e7fb 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_margin_config.test.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/use_margin_config.test.ts @@ -89,7 +89,7 @@ describe("useMarginConfig", () => { }); expect(success!).toBe(false); - expect(NotificationsManager.fromBackend).toHaveBeenCalled(); + expect(NotificationsManager.fromBackend).toHaveBeenCalledWith("Please select a provider"); }); it("should return false and notify when percentage is out of range", async () => { @@ -160,7 +160,7 @@ describe("useMarginConfig", () => { }); expect(success!).toBe(true); - expect(NotificationsManager.success).toHaveBeenCalled(); + expect(NotificationsManager.success).toHaveBeenCalledWith("Margin configuration updated successfully"); }); it("should save a fixed amount margin and return true for a valid new provider", async () => { @@ -189,7 +189,7 @@ describe("useMarginConfig", () => { }); expect(success!).toBe(true); - expect(NotificationsManager.success).toHaveBeenCalled(); + expect(NotificationsManager.success).toHaveBeenCalledWith("Margin configuration updated successfully"); }); it("should accept the global provider without provider_map lookup", async () => { diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts index 97f14e2d3d0..d80294aa2e6 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts @@ -1964,11 +1964,18 @@ describe("EntityUsageExport utils", () => { handleExportCSV(mockSpendData, "daily", "Team", "team", mockTeamAliasMap); - expect(Papa.unparse).toHaveBeenCalled(); - expect(createObjectURLSpy).toHaveBeenCalled(); + const unparsedRows = vi.mocked(Papa.unparse).mock.calls[0][0] as Record[]; + expect(unparsedRows).toHaveLength(3); + const day1Team1 = unparsedRows.find((r) => r["Date"] === "2025-01-01" && r["Team ID"] === "team-1"); + expect(day1Team1?.["Cache Read Input Tokens"]).toBe(50); + + const exportedBlob = createObjectURLSpy.mock.calls[0][0] as Blob; + expect(exportedBlob.type).toBe("text/csv;charset=utf-8;"); + expect(createElementSpy).toHaveBeenCalledWith("a"); - expect(appendChildSpy).toHaveBeenCalled(); - expect(removeChildSpy).toHaveBeenCalled(); + const attached = appendChildSpy.mock.calls[0][0] as HTMLAnchorElement; + expect(attached.download).toMatch(/^team_usage_daily_.*\.csv$/); + expect(removeChildSpy).toHaveBeenCalledWith(attached); }); it("should generate correct filename", () => { @@ -2028,10 +2035,13 @@ describe("EntityUsageExport utils", () => { handleExportJSON(mockSpendData, "daily", "Team", "team", mockDateRange, [], mockTeamAliasMap); - expect(createObjectURLSpy).toHaveBeenCalled(); + const exportedBlob = createObjectURLSpy.mock.calls[0][0] as Blob; + expect(exportedBlob.type).toBe("application/json"); + expect(createElementSpy).toHaveBeenCalledWith("a"); - expect(appendChildSpy).toHaveBeenCalled(); - expect(removeChildSpy).toHaveBeenCalled(); + const attached = appendChildSpy.mock.calls[0][0] as HTMLAnchorElement; + expect(attached.download).toMatch(/^team_usage_daily_.*\.json$/); + expect(removeChildSpy).toHaveBeenCalledWith(attached); }); it("should generate correct filename", () => {