From 3500823aa3cd3a0dde6e1d6a90530042e5c9705b Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 24 Apr 2026 14:38:22 +0000 Subject: [PATCH] chore(ui): repair failing vitest tests after shadcn migration (batch A) Co-authored-by: yuneng-jiang --- .../AIHub/AgentHubTableColumns.test.tsx | 13 +- .../agent_management/AgentSelector.test.tsx | 120 +++---- .../src/components/agents/agent_card.tsx | 1 + .../common_components/DurationSelect.test.tsx | 2 +- .../Filters/FiltersButton.test.tsx | 14 +- .../KeyLifecycleSettings.test.tsx | 317 +++++++++--------- .../common_components/LabeledField.test.tsx | 21 +- .../OrganizationDropdown.test.tsx | 8 +- .../TableHeaderSortDropdown.test.tsx | 100 ++---- 9 files changed, 286 insertions(+), 310 deletions(-) diff --git a/ui/litellm-dashboard/src/components/AIHub/AgentHubTableColumns.test.tsx b/ui/litellm-dashboard/src/components/AIHub/AgentHubTableColumns.test.tsx index 083e67c297a..df1add83d30 100644 --- a/ui/litellm-dashboard/src/components/AIHub/AgentHubTableColumns.test.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/AgentHubTableColumns.test.tsx @@ -102,14 +102,11 @@ describe("AgentHubTableColumns", () => { it("should display I/O modes", () => { render(); - // "In:" and "Out:" are in children; getByText with exact:false - // matches against the element's full textContent across child nodes - expect(screen.getByText((_, el) => - el?.tagName === "P" && el.textContent === "In: text" - )).toBeInTheDocument(); - expect(screen.getByText((_, el) => - el?.tagName === "P" && el.textContent === "Out: text, image" - )).toBeInTheDocument(); + // The label and value are sibling text nodes within the same container div. + const inLabel = screen.getByText("In:"); + expect(inLabel.parentElement?.textContent).toContain("text"); + const outLabel = screen.getByText("Out:"); + expect(outLabel.parentElement?.textContent).toContain("text, image"); }); it("should display 'Yes' badge for public agents", () => { diff --git a/ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx b/ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx index 26f903cd310..7d3f5d2edac 100644 --- a/ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx +++ b/ui/litellm-dashboard/src/components/agent_management/AgentSelector.test.tsx @@ -2,41 +2,11 @@ import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { describe, expect, it, vi, beforeEach } from "vitest"; -// Mock networking module const mockGetAgentsList = vi.fn(); vi.mock("../networking", () => ({ getAgentsList: (...args: any[]) => mockGetAgentsList(...args), })); -// Mock antd Select -vi.mock("antd", () => { - const SelectComponent = ({ children, onChange, value, mode, placeholder, loading, disabled, ...props }: any) => ( -
- - {loading && Loading} -
- ); - - SelectComponent.Option = ({ children, value, ...props }: any) => ( - - ); - - return { Select: SelectComponent }; -}); - import AgentSelector from "./AgentSelector"; describe("AgentSelector", () => { @@ -50,95 +20,125 @@ describe("AgentSelector", () => { mockGetAgentsList.mockResolvedValue({ agents: [ { agent_id: "agent-1", agent_name: "Agent One" }, - { agent_id: "agent-2", agent_name: "Agent Two", agent_access_groups: ["group-a", "group-b"] }, + { + agent_id: "agent-2", + agent_name: "Agent Two", + agent_access_groups: ["group-a", "group-b"], + }, ], }); }); - it("renders the selector", () => { + it("should render the selector trigger", () => { render(); - expect(screen.getByTestId("agent-select")).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /select agents/i })).toBeInTheDocument(); }); - it("fetches agents on mount with access token", async () => { + it("should fetch agents on mount with access token", async () => { render(); await waitFor(() => { expect(mockGetAgentsList).toHaveBeenCalledWith("test-token"); }); }); - it("does not fetch when accessToken is empty", () => { + it("should not fetch when accessToken is empty", () => { render(); expect(mockGetAgentsList).not.toHaveBeenCalled(); }); - it("shows loading state while fetching", async () => { - // Keep the promise pending - let resolve: any; - mockGetAgentsList.mockReturnValue(new Promise((r) => { resolve = r; })); - + it("should render agent options after fetch when popover is opened", async () => { + const user = userEvent.setup(); render(); - expect(screen.getByTestId("agent-select")).toHaveAttribute("data-loading", "true"); - - // Resolve to clean up - resolve({ agents: [] }); await waitFor(() => { - expect(screen.getByTestId("agent-select")).toHaveAttribute("data-loading", "false"); + expect(mockGetAgentsList).toHaveBeenCalled(); }); - }); - it("renders agent options after fetch", async () => { - render(); + await user.click(screen.getByRole("button", { name: /select agents/i })); + await waitFor(() => { expect(screen.getByText("Agent One")).toBeInTheDocument(); expect(screen.getByText("Agent Two")).toBeInTheDocument(); }); }); - it("renders access group options with group prefix", async () => { + it("should render access group options with group prefix when popover is opened", async () => { + const user = userEvent.setup(); render(); + await waitFor(() => { + expect(mockGetAgentsList).toHaveBeenCalled(); + }); + + await user.click(screen.getByRole("button", { name: /select agents/i })); + await waitFor(() => { expect(screen.getByText("group-a")).toBeInTheDocument(); expect(screen.getByText("group-b")).toBeInTheDocument(); }); }); - it("respects disabled prop", () => { + it("should respect disabled prop", () => { render(); - expect(screen.getByTestId("agent-select")).toHaveAttribute("data-disabled", "true"); + expect(screen.getByRole("button", { name: /select agents/i })).toBeDisabled(); }); - it("handles API error gracefully", async () => { + it("should handle API error gracefully", async () => { const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {}); mockGetAgentsList.mockRejectedValue(new Error("API error")); render(); await waitFor(() => { - expect(consoleSpy).toHaveBeenCalledWith("Error fetching agents:", expect.any(Error)); + expect(consoleSpy).toHaveBeenCalledWith( + "Error fetching agents:", + expect.any(Error), + ); }); consoleSpy.mockRestore(); }); - it("passes value as flattened selectedValues", async () => { + it("should render selected agents and access groups as badges", async () => { render( + />, ); + await waitFor(() => { - const select = screen.getByTestId("select-input"); - // The value should contain agent-1 and group:group-a - expect(select).toBeInTheDocument(); + expect(mockGetAgentsList).toHaveBeenCalled(); + }); + + // Labels are resolved from the options list once the fetch completes + await waitFor(() => { + expect(screen.getByText("Agent One")).toBeInTheDocument(); + expect(screen.getByText("group-a")).toBeInTheDocument(); }); }); - it("handles null response from API", async () => { + it("should handle null response from API without error", async () => { mockGetAgentsList.mockResolvedValue(null); render(); await waitFor(() => { - expect(screen.getByTestId("agent-select")).toHaveAttribute("data-loading", "false"); + expect(mockGetAgentsList).toHaveBeenCalled(); + }); + // Trigger still renders with placeholder + expect(screen.getByRole("button", { name: /select agents/i })).toBeInTheDocument(); + }); + + it("should call onChange when an option is selected", async () => { + const user = userEvent.setup(); + const onChange = vi.fn(); + render(); + await waitFor(() => { + expect(mockGetAgentsList).toHaveBeenCalled(); + }); + + await user.click(screen.getByRole("button", { name: /select agents/i })); + await user.click(await screen.findByText("Agent One")); + + expect(onChange).toHaveBeenCalledWith({ + agents: ["agent-1"], + accessGroups: [], }); }); }); diff --git a/ui/litellm-dashboard/src/components/agents/agent_card.tsx b/ui/litellm-dashboard/src/components/agents/agent_card.tsx index b93b7d34738..5d36c24302c 100644 --- a/ui/litellm-dashboard/src/components/agents/agent_card.tsx +++ b/ui/litellm-dashboard/src/components/agents/agent_card.tsx @@ -85,6 +85,7 @@ const AgentCard: React.FC = ({