diff --git a/ui/litellm-dashboard/src/components/bulk_create_users_button.test.tsx b/ui/litellm-dashboard/src/components/bulk_create_users_button.test.tsx
index 7397eaa6b24..dd3439c0bba 100644
--- a/ui/litellm-dashboard/src/components/bulk_create_users_button.test.tsx
+++ b/ui/litellm-dashboard/src/components/bulk_create_users_button.test.tsx
@@ -1,4 +1,4 @@
-import { render } from "@testing-library/react";
+import { fireEvent, render } from "@testing-library/react";
import { describe, it, expect, vi } from "vitest";
import BulkCreateUsersButton from "./bulk_create_users_button";
@@ -25,4 +25,50 @@ describe("BulkCreateUsersButton", () => {
const { getByText } = render();
expect(getByText("+ Bulk Invite Users")).toBeInTheDocument();
});
+
+ it("downloads the CSV template when clicked", async () => {
+ const originalCreateObjectURL = window.URL.createObjectURL;
+ const originalRevokeObjectURL = window.URL.revokeObjectURL;
+ const createObjectURLSpy = vi.fn(() => "blob:test");
+ const revokeObjectURLSpy = vi.fn();
+ const appendChildSpy = vi.spyOn(document.body, "appendChild");
+ const removeChildSpy = vi.spyOn(document.body, "removeChild");
+ const clickSpy = vi.fn();
+ const originalCreateElement = document.createElement.bind(document);
+ let createdAnchor: HTMLAnchorElement | null = null;
+
+ window.URL.createObjectURL = createObjectURLSpy;
+ window.URL.revokeObjectURL = revokeObjectURLSpy;
+
+ const createElementSpy = vi.spyOn(document, "createElement").mockImplementation((tagName: string) => {
+ if (tagName === "a") {
+ const anchor = originalCreateElement("a");
+ anchor.click = clickSpy;
+ createdAnchor = anchor;
+ return anchor;
+ }
+
+ return originalCreateElement(tagName);
+ });
+
+ const { getByText, findByText } = render(
+
+ );
+
+ fireEvent.click(getByText("+ Bulk Invite Users"));
+ fireEvent.click(await findByText("Download CSV Template"));
+
+ expect(createObjectURLSpy).toHaveBeenCalledOnce();
+ expect(clickSpy).toHaveBeenCalledOnce();
+ expect(createdAnchor).not.toBeNull();
+ expect(appendChildSpy).toHaveBeenCalledWith(createdAnchor);
+ expect(removeChildSpy).toHaveBeenCalledWith(createdAnchor);
+ expect(revokeObjectURLSpy).toHaveBeenCalledWith("blob:test");
+
+ appendChildSpy.mockRestore();
+ removeChildSpy.mockRestore();
+ createElementSpy.mockRestore();
+ window.URL.createObjectURL = originalCreateObjectURL;
+ window.URL.revokeObjectURL = originalRevokeObjectURL;
+ });
});
diff --git a/ui/litellm-dashboard/src/components/bulk_create_users_button.tsx b/ui/litellm-dashboard/src/components/bulk_create_users_button.tsx
index 4d0eb254d0d..28016266269 100644
--- a/ui/litellm-dashboard/src/components/bulk_create_users_button.tsx
+++ b/ui/litellm-dashboard/src/components/bulk_create_users_button.tsx
@@ -629,7 +629,13 @@ const BulkCreateUsersButton: React.FC = ({
- }>
+ }
+ onClick={downloadTemplate}
+ >
Download CSV Template