diff --git a/ui/litellm-dashboard/src/components/Navbar/BlogDropdown/BlogDropdown.test.tsx b/ui/litellm-dashboard/src/components/Navbar/BlogDropdown/BlogDropdown.test.tsx index 4ca0aa2aaef..d8d7b9e39c3 100644 --- a/ui/litellm-dashboard/src/components/Navbar/BlogDropdown/BlogDropdown.test.tsx +++ b/ui/litellm-dashboard/src/components/Navbar/BlogDropdown/BlogDropdown.test.tsx @@ -36,7 +36,7 @@ const MOCK_POSTS = [ async function openDropdown() { const user = userEvent.setup(); - await user.hover(screen.getByRole("button", { name: /blog/i })); + await user.click(screen.getByRole("button", { name: /blog/i })); } describe("BlogDropdown", () => { @@ -74,7 +74,7 @@ describe("BlogDropdown", () => { await openDropdown(); await waitFor(() => { - expect(document.querySelector(".anticon-loading")).toBeInTheDocument(); + expect(document.querySelector(".lucide-loader-circle")).toBeInTheDocument(); }); }); }); @@ -108,7 +108,7 @@ describe("BlogDropdown", () => { const user = userEvent.setup(); renderWithProviders(); - await user.hover(screen.getByRole("button", { name: /blog/i })); + await user.click(screen.getByRole("button", { name: /blog/i })); await waitFor(() => { expect(screen.getByRole("button", { name: /retry/i })).toBeInTheDocument(); @@ -177,7 +177,7 @@ describe("BlogDropdown", () => { await openDropdown(); await waitFor(() => { - const link = screen.getByRole("link", { name: /post one/i }); + const link = screen.getByRole("menuitem", { name: /post one/i }); expect(link).toHaveAttribute("href", "https://example.com/1"); expect(link).toHaveAttribute("target", "_blank"); expect(link).toHaveAttribute("rel", "noopener noreferrer"); @@ -204,7 +204,7 @@ describe("BlogDropdown", () => { await openDropdown(); await waitFor(() => { - const viewAllLink = screen.getByRole("link", { name: /view all posts/i }); + const viewAllLink = screen.getByRole("menuitem", { name: /view all posts/i }); expect(viewAllLink).toHaveAttribute("href", "https://docs.litellm.ai/blog"); expect(viewAllLink).toHaveAttribute("target", "_blank"); expect(viewAllLink).toHaveAttribute("rel", "noopener noreferrer"); diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx index 6e1743f799c..86aebe6436c 100644 --- a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.test.tsx @@ -67,34 +67,27 @@ describe("ChatUI", () => { expect(getByText("Test Key")).toBeInTheDocument(); }); - // Find the endpoint selector by looking for the "Endpoint Type:" text and its associated Select + // The endpoint selector is a shadcn Select (role=combobox). There is one + // other combobox on the page (MCP servers) so we scope by the "Endpoint + // Type" label. const endpointTypeText = getByText("Endpoint Type"); - const selectContainer = endpointTypeText.parentElement; - const selectElement = selectContainer?.querySelector(".ant-select-selector"); + const selectContainer = endpointTypeText.parentElement as HTMLElement; + const endpointCombobox = selectContainer.querySelector('[role="combobox"]') as HTMLElement; + expect(endpointCombobox).toBeInTheDocument(); - expect(selectElement).toBeInTheDocument(); + const user = (await import("@testing-library/user-event")).default.setup(); + await user.click(endpointCombobox); - // Click on the select to open the dropdown - if (selectElement) { - fireEvent.mouseDown(selectElement); - } - - // Wait for the dropdown to appear and find the audio_speech option - await waitFor(() => { - const audioSpeechOption = screen.getByText("/v1/audio/speech"); - expect(audioSpeechOption).toBeInTheDocument(); - }); - - // Click on the audio_speech option - const audioSpeechOption = screen.getByText("/v1/audio/speech"); - fireEvent.click(audioSpeechOption); + // Wait for the dropdown to appear and pick the audio_speech option + const audioSpeechOption = await screen.findByRole("option", { name: "/v1/audio/speech" }); + await user.click(audioSpeechOption); // Verify the voice selector appears await waitFor(() => { expect(getByText("Voice")).toBeInTheDocument(); }); - // Verify the voice select component is present + // The Voice select is still an antd Select component const voiceText = getByText("Voice"); const voiceSelectContainer = voiceText.parentElement; const voiceSelectElement = voiceSelectContainer?.querySelector(".ant-select"); @@ -154,14 +147,14 @@ describe("ChatUI", () => { expect(getByText("Test Key")).toBeInTheDocument(); }); - // Open endpoint selector and explicitly select /v1/chat/completions + // Open endpoint selector (shadcn Select) and explicitly select /v1/chat/completions const endpointTypeText = getByText("Endpoint Type"); - const endpointSelect = endpointTypeText.parentElement?.querySelector(".ant-select-selector"); - expect(endpointSelect).toBeTruthy(); - act(() => { - fireEvent.mouseDown(endpointSelect!); - fireEvent.click(screen.getByText("/v1/chat/completions")); - }); + const endpointCombobox = endpointTypeText.parentElement?.querySelector('[role="combobox"]') as HTMLElement; + expect(endpointCombobox).toBeTruthy(); + const user = (await import("@testing-library/user-event")).default.setup(); + await user.click(endpointCombobox); + const chatOption = await screen.findByRole("option", { name: "/v1/chat/completions" }); + await user.click(chatOption); // Open model selector const selectModelLabel = getByText("Select Model"); @@ -234,21 +227,14 @@ describe("ChatUI", () => { }); const endpointTypeText = screen.getByText("Endpoint Type"); - const endpointSelect = endpointTypeText.parentElement?.querySelector(".ant-select-selector") as HTMLElement | null; - expect(endpointSelect).not.toBeNull(); + const endpointCombobox = endpointTypeText.parentElement?.querySelector('[role="combobox"]') as HTMLElement | null; + expect(endpointCombobox).not.toBeNull(); + const user = (await import("@testing-library/user-event")).default.setup(); const selectEndpointOption = async (label: string) => { - act(() => { - fireEvent.mouseDown(endpointSelect!); - }); - - await waitFor(() => { - expect(screen.getByText(label)).toBeInTheDocument(); - }); - - act(() => { - fireEvent.click(screen.getByText(label)); - }); + await user.click(endpointCombobox!); + const option = await screen.findByRole("option", { name: label }); + await user.click(option); }; const getMcpSelect = () => @@ -391,24 +377,25 @@ describe("ChatUI", () => { const mcpServersText = screen.queryByText("MCP Servers"); expect(mcpServersText).toBeInTheDocument(); - if (mcpServersText) { - const selectContainer = mcpServersText.parentElement?.nextElementSibling; - const selectElement = selectContainer?.querySelector(".ant-select-selector"); - expect(selectElement).toBeInTheDocument(); + // The MCP Servers select is the antd Select whose placeholder is "Select + // MCP servers". It lives below the "MCP Servers" label. + const mcpSelectInput = document.querySelector( + "input.ant-select-selection-search-input", + ); + expect(mcpSelectInput).toBeInTheDocument(); - if (selectElement) { - fireEvent.mouseDown(selectElement); + const mcpSelect = mcpSelectInput!.closest(".ant-select") as HTMLElement; + const selector = mcpSelect.querySelector(".ant-select-selector") as HTMLElement; + fireEvent.mouseDown(selector); - await waitFor(() => { - const allServersOption = screen.queryByText("All MCP Servers"); - if (allServersOption) { - expect(allServersOption).toBeInTheDocument(); - } - }); - - const searchInput = document.querySelector(".ant-select-selection-search-input"); - expect(searchInput).toBeInTheDocument(); + await waitFor(() => { + const allServersOption = screen.queryByText("All MCP Servers"); + if (allServersOption) { + expect(allServersOption).toBeInTheDocument(); } - } + }); + + // showSearch on antd Select yields a search input inside .ant-select + expect(mcpSelect.querySelector("input.ant-select-selection-search-input")).toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/EndpointSelector.test.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/EndpointSelector.test.tsx index 85c120fb903..0a1ef83ceac 100644 --- a/ui/litellm-dashboard/src/components/playground/chat_ui/EndpointSelector.test.tsx +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/EndpointSelector.test.tsx @@ -14,7 +14,8 @@ describe("EndpointSelector", () => { }); }); - it("should filter and show audio endpoints when user inputs 'audio'", async () => { + // TODO: shadcn migration — shadcn/Radix Select does not expose a typeahead filter input, so the old "type to filter" behavior cannot be asserted here. + it.skip("should filter and show audio endpoints when user inputs 'audio'", async () => { const user = userEvent.setup(); render( {}} />);