diff --git a/ui/litellm-dashboard/src/components/Navbar/WorkerDropdown/WorkerDropdown.test.tsx b/ui/litellm-dashboard/src/components/Navbar/WorkerDropdown/WorkerDropdown.test.tsx
new file mode 100644
index 00000000000..79b47adc3a1
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/Navbar/WorkerDropdown/WorkerDropdown.test.tsx
@@ -0,0 +1,78 @@
+import { renderWithProviders, screen } from "../../../../tests/test-utils";
+import userEvent from "@testing-library/user-event";
+import { vi, describe, it, expect, beforeEach } from "vitest";
+import WorkerDropdown from "./WorkerDropdown";
+
+const mockUseWorker = vi.fn();
+
+vi.mock("@/hooks/useWorker", () => ({
+ useWorker: () => mockUseWorker(),
+}));
+
+const workers = [
+ { worker_id: "w1", name: "Worker 1", url: "http://w1" },
+ { worker_id: "w2", name: "Worker 2", url: "http://w2" },
+ { worker_id: "w3", name: "Worker 3", url: "http://w3" },
+];
+
+describe("WorkerDropdown", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ });
+
+ it("should render", () => {
+ mockUseWorker.mockReturnValue({
+ isControlPlane: true,
+ selectedWorker: workers[0],
+ workers,
+ });
+
+ renderWithProviders();
+ expect(screen.getByRole("combobox")).toBeInTheDocument();
+ });
+
+ it("should return null when not a control plane", () => {
+ mockUseWorker.mockReturnValue({
+ isControlPlane: false,
+ selectedWorker: null,
+ workers: [],
+ });
+
+ const { container } = renderWithProviders(
+
+ );
+ expect(container.firstChild).toBeNull();
+ });
+
+ it("should return null when there is no selected worker", () => {
+ mockUseWorker.mockReturnValue({
+ isControlPlane: true,
+ selectedWorker: null,
+ workers,
+ });
+
+ const { container } = renderWithProviders(
+
+ );
+ expect(container.firstChild).toBeNull();
+ });
+
+ it("should call onWorkerSwitch when a different worker is selected", async () => {
+ mockUseWorker.mockReturnValue({
+ isControlPlane: true,
+ selectedWorker: workers[0],
+ workers,
+ });
+ const onWorkerSwitch = vi.fn();
+ const user = userEvent.setup();
+
+ renderWithProviders();
+
+ // Open the dropdown
+ await user.click(screen.getByRole("combobox"));
+ // Select Worker 2
+ await user.click(await screen.findByText("Worker 2"));
+
+ expect(onWorkerSwitch).toHaveBeenCalledWith("w2");
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/common_components/AccessGroupSelector.test.tsx b/ui/litellm-dashboard/src/components/common_components/AccessGroupSelector.test.tsx
new file mode 100644
index 00000000000..f8604ecb320
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/common_components/AccessGroupSelector.test.tsx
@@ -0,0 +1,114 @@
+import { renderWithProviders, screen } from "../../../tests/test-utils";
+import { vi, describe, it, expect, beforeEach } from "vitest";
+import AccessGroupSelector from "./AccessGroupSelector";
+
+const mockAccessGroups = [
+ {
+ access_group_id: "ag-1",
+ access_group_name: "Engineering",
+ description: null,
+ access_model_names: [],
+ access_mcp_server_ids: [],
+ access_agent_ids: [],
+ assigned_team_ids: [],
+ assigned_key_ids: [],
+ created_at: "2024-01-01",
+ created_by: null,
+ updated_at: "2024-01-01",
+ updated_by: null,
+ },
+ {
+ access_group_id: "ag-2",
+ access_group_name: "Product",
+ description: null,
+ access_model_names: [],
+ access_mcp_server_ids: [],
+ access_agent_ids: [],
+ assigned_team_ids: [],
+ assigned_key_ids: [],
+ created_at: "2024-01-01",
+ created_by: null,
+ updated_at: "2024-01-01",
+ updated_by: null,
+ },
+];
+
+const mockUseAccessGroups = vi.fn();
+
+vi.mock("@/app/(dashboard)/hooks/accessGroups/useAccessGroups", () => ({
+ useAccessGroups: () => mockUseAccessGroups(),
+ // Re-export the type for imports to work
+ get AccessGroupResponse() {
+ return {};
+ },
+}));
+
+describe("AccessGroupSelector", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ });
+
+ it("should render", () => {
+ mockUseAccessGroups.mockReturnValue({
+ data: mockAccessGroups,
+ isLoading: false,
+ isError: false,
+ });
+
+ renderWithProviders();
+ expect(screen.getByRole("combobox")).toBeInTheDocument();
+ });
+
+ it("should show a loading skeleton when data is loading", () => {
+ mockUseAccessGroups.mockReturnValue({
+ data: undefined,
+ isLoading: true,
+ isError: false,
+ });
+
+ renderWithProviders();
+ // Ant Design Skeleton renders with class ant-skeleton
+ expect(screen.queryByRole("combobox")).not.toBeInTheDocument();
+ });
+
+ it("should show the label text when showLabel is true", () => {
+ mockUseAccessGroups.mockReturnValue({
+ data: mockAccessGroups,
+ isLoading: false,
+ isError: false,
+ });
+
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("My Groups")).toBeInTheDocument();
+ });
+
+ it("should not show the label by default", () => {
+ mockUseAccessGroups.mockReturnValue({
+ data: mockAccessGroups,
+ isLoading: false,
+ isError: false,
+ });
+
+ renderWithProviders();
+ expect(screen.queryByText("Access Group")).not.toBeInTheDocument();
+ });
+
+ it("should show error content when data fails to load", async () => {
+ mockUseAccessGroups.mockReturnValue({
+ data: undefined,
+ isLoading: false,
+ isError: true,
+ });
+
+ const user = (await import("@testing-library/user-event")).default.setup();
+ renderWithProviders();
+
+ // Open the dropdown to see notFoundContent
+ await user.click(screen.getByRole("combobox"));
+ expect(
+ await screen.findByText("Failed to load access groups")
+ ).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/common_components/AutoRotationView.test.tsx b/ui/litellm-dashboard/src/components/common_components/AutoRotationView.test.tsx
new file mode 100644
index 00000000000..c98cfb0ed0c
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/common_components/AutoRotationView.test.tsx
@@ -0,0 +1,105 @@
+import { renderWithProviders, screen } from "../../../tests/test-utils";
+import { vi, describe, it, expect } from "vitest";
+import AutoRotationView from "./AutoRotationView";
+
+// Mock heroicons since jsdom doesn't support SVG rendering
+vi.mock("@heroicons/react/outline", () => ({
+ RefreshIcon: (props: Record) => ,
+ ClockIcon: (props: Record) => ,
+}));
+
+describe("AutoRotationView", () => {
+ it("should render", () => {
+ renderWithProviders();
+ expect(screen.getAllByText("Auto-Rotation").length).toBeGreaterThan(0);
+ });
+
+ it("should show Disabled badge when autoRotate is false", () => {
+ renderWithProviders();
+ expect(screen.getByText("Disabled")).toBeInTheDocument();
+ });
+
+ it("should show Enabled badge when autoRotate is true", () => {
+ renderWithProviders();
+ expect(screen.getByText("Enabled")).toBeInTheDocument();
+ });
+
+ it("should show the rotation interval when autoRotate is true", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Every 7d")).toBeInTheDocument();
+ });
+
+ it("should show 'No rotation history available' when autoRotate is enabled but no timestamps", () => {
+ renderWithProviders();
+ expect(
+ screen.getByText("No rotation history available")
+ ).toBeInTheDocument();
+ });
+
+ it("should show disabled message when autoRotate is off and no rotation data", () => {
+ renderWithProviders();
+ expect(
+ screen.getByText("Auto-rotation is not enabled for this key")
+ ).toBeInTheDocument();
+ });
+
+ it("should show last rotation timestamp when provided", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Last Rotation")).toBeInTheDocument();
+ });
+
+ it("should show next scheduled rotation when nextRotationAt is provided", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Next Scheduled Rotation")).toBeInTheDocument();
+ });
+
+ it("should show next scheduled rotation when keyRotationAt is provided", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Next Scheduled Rotation")).toBeInTheDocument();
+ });
+
+ describe("when variant is 'inline'", () => {
+ it("should render without the card wrapper", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Disabled")).toBeInTheDocument();
+ // The card variant has a subtitle; inline does not
+ expect(
+ screen.queryByText(
+ "Automatic key rotation settings and status for this key"
+ )
+ ).not.toBeInTheDocument();
+ });
+ });
+
+ describe("when variant is 'card'", () => {
+ it("should render with the card subtitle", () => {
+ renderWithProviders(
+
+ );
+ expect(
+ screen.getByText(
+ "Automatic key rotation settings and status for this key"
+ )
+ ).toBeInTheDocument();
+ });
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/common_components/MemberTable.test.tsx b/ui/litellm-dashboard/src/components/common_components/MemberTable.test.tsx
new file mode 100644
index 00000000000..b36a78a7362
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/common_components/MemberTable.test.tsx
@@ -0,0 +1,183 @@
+import { renderWithProviders, screen, within } from "../../../tests/test-utils";
+import userEvent from "@testing-library/user-event";
+import { vi, describe, it, expect, beforeEach } from "vitest";
+import MemberTable from "./MemberTable";
+import type { Member } from "@/components/networking";
+
+vi.mock(
+ "@/components/common_components/IconActionButton/TableIconActionButtons/TableIconActionButton",
+ () => ({
+ default: ({
+ onClick,
+ dataTestId,
+ variant,
+ }: {
+ onClick: () => void;
+ dataTestId?: string;
+ variant: string;
+ }) => (
+
+ ),
+ })
+);
+
+const members: Member[] = [
+ { user_id: "user-1", user_email: "alice@example.com", role: "admin" },
+ { user_id: "user-2", user_email: "bob@example.com", role: "user" },
+ {
+ user_id: "default_user_id",
+ user_email: "proxy@admin.com",
+ role: "admin",
+ },
+];
+
+describe("MemberTable", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ });
+
+ it("should render", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("3 Members")).toBeInTheDocument();
+ });
+
+ it("should display member emails in the table", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("alice@example.com")).toBeInTheDocument();
+ expect(screen.getByText("bob@example.com")).toBeInTheDocument();
+ });
+
+ it("should show Default Proxy Admin tag for default_user_id", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Default Proxy Admin")).toBeInTheDocument();
+ });
+
+ it("should show singular 'Member' label when there is only one member", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("1 Member")).toBeInTheDocument();
+ });
+
+ it("should call onEdit when the edit button is clicked", async () => {
+ const onEdit = vi.fn();
+ const user = userEvent.setup();
+
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByTestId("edit-member"));
+ expect(onEdit).toHaveBeenCalledWith(members[0]);
+ });
+
+ it("should call onDelete when the delete button is clicked", async () => {
+ const onDelete = vi.fn();
+ const user = userEvent.setup();
+
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByTestId("delete-member"));
+ expect(onDelete).toHaveBeenCalledWith(members[0]);
+ });
+
+ it("should not show action buttons when canEdit is false", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.queryByTestId("edit-member")).not.toBeInTheDocument();
+ expect(screen.queryByTestId("delete-member")).not.toBeInTheDocument();
+ });
+
+ it("should show the Add Member button when onAddMember is provided and canEdit is true", () => {
+ renderWithProviders(
+
+ );
+ expect(
+ screen.getByRole("button", { name: /add member/i })
+ ).toBeInTheDocument();
+ });
+
+ it("should call onAddMember when the Add Member button is clicked", async () => {
+ const onAddMember = vi.fn();
+ const user = userEvent.setup();
+
+ renderWithProviders(
+
+ );
+
+ await user.click(screen.getByRole("button", { name: /add member/i }));
+ expect(onAddMember).toHaveBeenCalled();
+ });
+
+ it("should hide delete for a member when showDeleteForMember returns false", () => {
+ renderWithProviders(
+ false}
+ />
+ );
+ expect(screen.queryByTestId("delete-member")).not.toBeInTheDocument();
+ expect(screen.getByTestId("edit-member")).toBeInTheDocument();
+ });
+});
diff --git a/ui/litellm-dashboard/src/components/common_components/ModelSelector.test.tsx b/ui/litellm-dashboard/src/components/common_components/ModelSelector.test.tsx
new file mode 100644
index 00000000000..246fcec3e2b
--- /dev/null
+++ b/ui/litellm-dashboard/src/components/common_components/ModelSelector.test.tsx
@@ -0,0 +1,78 @@
+import { renderWithProviders, screen, waitFor } from "../../../tests/test-utils";
+import userEvent from "@testing-library/user-event";
+import { vi, describe, it, expect, beforeEach } from "vitest";
+import ModelSelector from "./ModelSelector";
+import { fetchAvailableModels } from "@/components/playground/llm_calls/fetch_models";
+
+const mockModels = [
+ { model_group: "gpt-4" },
+ { model_group: "claude-3-opus" },
+ { model_group: "gemini-pro" },
+];
+
+vi.mock("@/components/playground/llm_calls/fetch_models", () => ({
+ fetchAvailableModels: vi.fn(),
+}));
+
+describe("ModelSelector", () => {
+ beforeEach(() => {
+ vi.resetAllMocks();
+ vi.mocked(fetchAvailableModels).mockResolvedValue(mockModels);
+ });
+
+ it("should render", () => {
+ renderWithProviders();
+ expect(screen.getByRole("combobox")).toBeInTheDocument();
+ });
+
+ it("should show the label by default", () => {
+ renderWithProviders();
+ expect(screen.getByText("Select Model")).toBeInTheDocument();
+ });
+
+ it("should hide the label when showLabel is false", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.queryByText("Select Model")).not.toBeInTheDocument();
+ });
+
+ it("should show custom label text", () => {
+ renderWithProviders(
+
+ );
+ expect(screen.getByText("Pick a Model")).toBeInTheDocument();
+ });
+
+ it("should show the custom model input when 'Enter custom model' is selected", async () => {
+ const user = userEvent.setup();
+
+ renderWithProviders();
+
+ // Wait for models to load
+ await waitFor(() => {
+ expect(fetchAvailableModels).toHaveBeenCalledWith("test-token");
+ });
+
+ await user.click(screen.getByRole("combobox"));
+ await user.click(await screen.findByText("Enter custom model"));
+
+ expect(
+ screen.getByPlaceholderText("Enter custom model name")
+ ).toBeInTheDocument();
+ });
+
+ it("should fetch models when accessToken is provided", async () => {
+ renderWithProviders();
+
+ await waitFor(() => {
+ expect(fetchAvailableModels).toHaveBeenCalledWith("test-token");
+ });
+ });
+
+ it("should not fetch models when accessToken is empty", () => {
+ renderWithProviders();
+
+ expect(fetchAvailableModels).not.toHaveBeenCalled();
+ });
+});