diff --git a/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx b/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx index 522af5a85ad..e253b06e1b3 100644 --- a/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx +++ b/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx @@ -7,11 +7,12 @@ vi.mock("@/lib/toast", () => ({ })); // ---- Hoisted shared mocks (safe to use inside vi.mock factories) ---- -const { keyUpdateCallMock, keyDeleteCallMock, mockUseAuthorized } = vi.hoisted(() => { +const { keyUpdateCallMock, keyDeleteCallMock, mockUseAuthorized, invalidateQueriesMock } = vi.hoisted(() => { return { keyUpdateCallMock: vi.fn().mockResolvedValue({}), keyDeleteCallMock: vi.fn().mockResolvedValue({}), mockUseAuthorized: vi.fn(), + invalidateQueriesMock: vi.fn(), }; }); @@ -165,12 +166,11 @@ vi.mock("@/app/(dashboard)/hooks/keys/useSetKeyBlockedState", () => ({ }), })); -// useQueryClient also needs a provider; the delete-path invalidation is covered in key_info_view.test.tsx vi.mock("@tanstack/react-query", async (importOriginal) => { const actual = await importOriginal(); return { ...actual, - useQueryClient: () => ({ invalidateQueries: vi.fn() }), + useQueryClient: () => ({ invalidateQueries: invalidateQueriesMock }), }; }); @@ -196,6 +196,7 @@ vi.mock("./key_edit_view", async () => { // ---- SUT import AFTER mocks ---- import KeyInfoView from "./key_info_view"; +import { keyKeys } from "@/app/(dashboard)/hooks/keys/useKeys"; // ---- Test data helpers ---- const baseKeyData = { @@ -528,6 +529,28 @@ describe("KeyInfoView handleKeyUpdate empty strings", () => { }); }); +describe("KeyInfoView handleKeyUpdate keys-list invalidation", () => { + it("invalidates the keys list query after a successful update so the table reflects the change", async () => { + renderView(true); + + fireEvent.click(screen.getByText("Settings")); + fireEvent.click(screen.getByText("Edit Settings")); + (globalThis as any).__TEST_FORM_VALUES = { + token: "tok_123", + max_budget: 60, + budget_duration: "24h", + }; + + fireEvent.click(screen.getByText("Mock Submit")); + + await waitFor(() => expect(keyUpdateCallMock).toHaveBeenCalled()); + + await waitFor(() => { + expect(invalidateQueriesMock).toHaveBeenCalledWith({ queryKey: keyKeys.lists() }); + }); + }); +}); + describe("KeyInfoView handleKeyUpdate soft_budget", () => { const premiumAdminAuth = { accessToken: "access_abc", diff --git a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx index 7eb09926caf..d39f7ee218a 100644 --- a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx @@ -389,7 +389,7 @@ export default function KeyInfoView({ } toast.success("Key updated successfully"); setIsEditing(false); - // Refresh key data here if needed + await queryClient.invalidateQueries({ queryKey: keyKeys.lists() }); } catch (error) { toast.fromError(parseErrorMessage(error)); console.error("Error updating key:", error);