diff --git a/ui/litellm-dashboard/src/app/(dashboard)/agentControlPlaneView.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/agentControlPlaneView.test.tsx index 26de1eed7b8..3e3b3d2b8bf 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/agentControlPlaneView.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/agentControlPlaneView.test.tsx @@ -33,7 +33,7 @@ describe("AgentControlPlaneView iframe", () => { expect(src).toBe("http://localhost:3300/"); expect(src).not.toContain("/sessions"); // title comes from the plugin's display_name, not a hardcoded label - expect(iframe!.getAttribute("title")).toBe("Chat UI"); + expect(iframe!).toHaveAttribute("title", "Chat UI"); }); it("does not double the slash when the plugin url has a trailing slash", () => { @@ -43,7 +43,7 @@ describe("AgentControlPlaneView iframe", () => { url: "http://localhost:3300/", }; const { container } = render(); - expect(container.querySelector("iframe")!.getAttribute("src")).toBe("http://localhost:3300/"); + expect(container.querySelector("iframe")!).toHaveAttribute("src", "http://localhost:3300/"); pluginModeValue.activePlugin = { name: "litellm-platform-plugin", display_name: "Chat UI", diff --git a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/AgentsTable.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/AgentsTable.test.tsx index f86ef16e836..06099a9fc22 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/AgentsTable.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/AgentsTable.test.tsx @@ -101,8 +101,8 @@ describe("AgentsTable", () => { ); const bodyRows = screen.getAllByRole("row").slice(1); - expect(bodyRows[0].textContent).toContain("Beta Agent"); - expect(bodyRows[1].textContent).toContain("Alpha Agent"); + expect(bodyRows[0]).toHaveTextContent(/Beta Agent/); + expect(bodyRows[1]).toHaveTextContent(/Alpha Agent/); }); it("sorts agents with no created_at last, never ahead of dated ones", () => { @@ -118,9 +118,9 @@ describe("AgentsTable", () => { ); const bodyRows = screen.getAllByRole("row").slice(1); - expect(bodyRows[0].textContent).toContain("Beta Agent"); - expect(bodyRows[1].textContent).toContain("Alpha Agent"); - expect(bodyRows[2].textContent).toContain("Undated Agent"); + expect(bodyRows[0]).toHaveTextContent(/Beta Agent/); + expect(bodyRows[1]).toHaveTextContent(/Alpha Agent/); + expect(bodyRows[2]).toHaveTextContent(/Undated Agent/); }); it("shows a rich empty state when there are no agents", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/agent_card_discovery.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/agent_card_discovery.test.tsx index 7858bdb1cd4..e3c5e1dd94f 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/agent_card_discovery.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/agent_card_discovery.test.tsx @@ -196,12 +196,10 @@ describe("AgentCardDiscovery", () => { ); expect( - ( - screen.getByRole("button", { - name: /discover/i, - }) as HTMLButtonElement - ).disabled, - ).toBe(true); + screen.getByRole("button", { + name: /discover/i, + }), + ).toBeDisabled(); expect(mockDiscover).not.toHaveBeenCalled(); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/api-reference/_components/APIReferenceView.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/api-reference/_components/APIReferenceView.test.tsx index ad1cf28dc54..b2e0a42eecb 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/api-reference/_components/APIReferenceView.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/api-reference/_components/APIReferenceView.test.tsx @@ -16,7 +16,7 @@ describe("APIReferenceView", () => { const { getAllByTestId } = render(); const codeBlocks = getAllByTestId(codeBlockTestId); - expect(codeBlocks[0].textContent).toContain(apiDocUrl); + expect(codeBlocks[0]).toHaveTextContent(new RegExp(apiDocUrl)); }); it("falls back to the proxy base url when the docs url is missing", () => { @@ -24,7 +24,7 @@ describe("APIReferenceView", () => { const { getAllByTestId } = render(); const codeBlocks = getAllByTestId(codeBlockTestId); - expect(codeBlocks[0].textContent).toContain(proxyUrl); + expect(codeBlocks[0]).toHaveTextContent(new RegExp(proxyUrl)); }); it("prefers the docs url when both urls are provided", () => { @@ -49,12 +49,12 @@ describe("APIReferenceView", () => { it("renders the page title, blurb and docs link", () => { render(); - expect(screen.getByText("OpenAI Compatible Proxy: API Reference")).toBeTruthy(); - expect(screen.getByText(/LiteLLM is OpenAI Compatible/)).toBeTruthy(); + expect(screen.getByText("OpenAI Compatible Proxy: API Reference")).toBeInTheDocument(); + expect(screen.getByText(/LiteLLM is OpenAI Compatible/)).toBeInTheDocument(); const docsLink = screen.getByRole("link", { name: /API Reference Docs/ }); - expect(docsLink.getAttribute("href")).toBe("https://docs.litellm.ai/docs/proxy/user_keys"); - expect(docsLink.getAttribute("target")).toBe("_blank"); + expect(docsLink).toHaveAttribute("href", "https://docs.litellm.ai/docs/proxy/user_keys"); + expect(docsLink).toHaveAttribute("target", "_blank"); }); it("exposes the three SDK tabs with the first selected by default", () => { @@ -83,10 +83,10 @@ describe("APIReferenceView", () => { await user.click(screen.getByRole("tab", { name: tabName })); - expect(screen.getByRole("tab", { name: tabName }).getAttribute("aria-selected")).toBe("true"); + expect(screen.getByRole("tab", { name: tabName })).toHaveAttribute("aria-selected", "true"); const selectedPanel = screen.getByRole("tabpanel"); - expect(selectedPanel.textContent).toContain(marker); - expect(selectedPanel.textContent).toContain(proxyUrl); + expect(selectedPanel).toHaveTextContent(new RegExp(marker)); + expect(selectedPanel).toHaveTextContent(new RegExp(proxyUrl)); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/BudgetTable.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/BudgetTable.test.tsx index f78ba34770d..c425e766f2d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/BudgetTable.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/budgets/_components/BudgetTable.test.tsx @@ -105,7 +105,7 @@ describe("BudgetTable", () => { const list = makeList({ rows: [makeBudget({ budget_id: budgetId })] }); renderWithProviders(); const idCell = screen.getByText(budgetId); - expect(idCell.className).not.toContain("truncate"); + expect(idCell).not.toHaveClass("truncate"); expect(idCell.className).not.toMatch(/max-w-\[\d+(ch|rem|px)\]/); }); @@ -113,7 +113,7 @@ describe("BudgetTable", () => { const budgetId = "ecc1869c-6231-4380-a56d-1a0be457477d"; const list = makeList({ rows: [makeBudget({ budget_id: budgetId })] }); renderWithProviders(); - expect(screen.getByText(budgetId).className).toContain("whitespace-nowrap"); + expect(screen.getByText(budgetId)).toHaveClass("whitespace-nowrap"); }); it("should copy the budget id from the cell's copy button", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.activity.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.activity.test.tsx index 96502cac953..70d7dade97a 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.activity.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/CostOptimizationView.activity.test.tsx @@ -52,7 +52,7 @@ describe("CostOptimizationView daily activity", () => { useAuthorizedMock.mockReturnValue({ accessToken: "test-token", userId: "u1", userRole: "proxy_admin" }); const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); - const { getByRole, getByTestId } = render( + const { getByRole, getByTestId, findByTestId } = render( , @@ -61,7 +61,7 @@ describe("CostOptimizationView daily activity", () => { await waitFor(() => expect(mockUserDailyActivityCall).toHaveBeenCalledTimes(1)); fireEvent.click(getByRole("tab", { name: "Prompt Caching" })); - await waitFor(() => expect(getByTestId("caching-settings")).toBeInTheDocument()); + await findByTestId("caching-settings"); expect(mockUserDailyActivityCall).toHaveBeenCalledTimes(1); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.test.tsx index 25be956f18b..20d57754857 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-optimization/_components/UsageTab.test.tsx @@ -218,7 +218,7 @@ describe("UsageTab", () => { // Per day switches to a bar chart of the unaccumulated daily savings, with no // synthetic anchor prepended. - expect(queryByTestId("area-chart")).toBeNull(); + expect(queryByTestId("area-chart")).not.toBeInTheDocument(); const series = readSeries(getByTestId("bar-chart")); expect(series).toHaveLength(2); expect(series[0]).toMatchObject({ Compression: 0.04, "Prompt caching": 0.006 }); @@ -264,7 +264,7 @@ describe("UsageTab", () => { await userEvent.click(getByRole("tab", { name: "Per day" })); const bars = getByTestId("bar-chart"); - expect(bars.getAttribute("data-stack")).toBe("false"); + expect(bars).toHaveAttribute("data-stack", "false"); expect(readSeries(bars)[0]).toMatchObject({ "Auto-router": -0.05 }); }); @@ -290,7 +290,7 @@ describe("UsageTab", () => { expect(before.action.contains(getByRole("tablist"))).toBe(true); // the subtitle lives outside that slot, so its length cannot reposition the controls expect(before.action.contains(before.description)).toBe(false); - expect(before.description.textContent).toContain("Running total saved"); + expect(before.description).toHaveTextContent(/Running total saved/); await userEvent.click(getByRole("tab", { name: "Per day" })); @@ -298,8 +298,8 @@ describe("UsageTab", () => { expect(after.action).toBe(before.action); expect(after.cardHeader).toBe(before.cardHeader); expect(after.action.contains(after.description)).toBe(false); - expect(after.description.textContent).toContain("Saved per day"); - expect(container.textContent).toContain("Savings"); + expect(after.description).toHaveTextContent(/Saved per day/); + expect(container).toHaveTextContent(/Savings/); }); it("subtracts a losing auto-router route from the total and keeps it out of the donut", () => { @@ -319,7 +319,7 @@ describe("UsageTab", () => { const slices = JSON.parse(getByTestId("donut-chart").getAttribute("data-slices") ?? "[]"); expect(slices.map((d: { driver: string }) => d.driver)).toEqual(["Compression", "Prompt caching"]); - expect(getByTestId("donut-chart").getAttribute("data-label")).toBe("$0.1200"); + expect(getByTestId("donut-chart")).toHaveAttribute("data-label", "$0.1200"); }); it("carries auto-router savings into the summary card, donut slice, and cumulative series", () => { @@ -370,7 +370,7 @@ describe("UsageTab", () => { expect(series[0]).toMatchObject({ tool_name: "search", spend: 4.0 }); // The 64px bar cap is this card's opt-in; the shared BarChart must not cap // by default (other consumers keep their pre-existing geometry). - expect(bars[0].getAttribute("data-max-bar-size")).toBe("64"); + expect(bars[0]).toHaveAttribute("data-max-bar-size", "64"); }); it("renders the tool legend once outside the charts, with both charts sharing the tool colors", async () => { @@ -387,8 +387,8 @@ describe("UsageTab", () => { const bars = await findAllByTestId("bar-chart"); const [totalByTool, dailyByTool] = bars.slice(-2); - expect(dailyByTool.getAttribute("data-show-legend")).toBe("false"); - expect(totalByTool.getAttribute("data-colors")).toBe(dailyByTool.getAttribute("data-colors")); + expect(dailyByTool).toHaveAttribute("data-show-legend", "false"); + expect(totalByTool).toHaveAttribute("data-colors", dailyByTool.getAttribute("data-colors")); const toolLegends = getAllByTestId("chart-legend").filter((legend) => legend.textContent === "search,read_file"); expect(toolLegends).toHaveLength(1); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_margin_form.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_margin_form.test.tsx index 1ededd9e4b1..63a0b3c355f 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_margin_form.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_margin_form.test.tsx @@ -67,7 +67,7 @@ describe("AddMarginForm", () => { it("should enable the submit button when provider and percentage value are both provided", () => { renderWithProviders(); - expect(screen.getByRole("button", { name: /add provider margin/i })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: /add provider margin/i })).toBeEnabled(); }); it("should disable the submit button in fixed mode when no fixed amount is provided", () => { @@ -81,7 +81,7 @@ describe("AddMarginForm", () => { renderWithProviders( , ); - expect(screen.getByRole("button", { name: /add provider margin/i })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: /add provider margin/i })).toBeEnabled(); }); it("should call onAddProvider when the enabled submit button is clicked", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_provider_form.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_provider_form.test.tsx index 08fb63c32b9..084233b3670 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_provider_form.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/add_provider_form.test.tsx @@ -48,7 +48,7 @@ describe("AddProviderForm", () => { it("should enable the submit button when both a provider and a discount value are provided", () => { renderWithProviders(); - expect(screen.getByRole("button", { name: /add provider discount/i })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: /add provider discount/i })).toBeEnabled(); }); it("should call onAddProvider when the enabled submit button is clicked", async () => { @@ -71,7 +71,7 @@ describe("AddProviderForm", () => { renderWithProviders(); const logo = await screen.findByRole("img", { name: `${Providers.OpenAI} logo` }); - expect(logo.getAttribute("src")).toBe(providerLogoMap[Providers.OpenAI]); + expect(logo).toHaveAttribute("src", providerLogoMap[Providers.OpenAI]); }); it("falls back to a letter avatar for a selected provider that has no bundled logo", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/cost_tracking_settings.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/cost_tracking_settings.test.tsx index 03cef2a66b8..9cdc8509fbf 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/cost_tracking_settings.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/cost_tracking_settings.test.tsx @@ -73,7 +73,7 @@ describe("CostTrackingSettings", () => { const { container } = renderWithProviders( , ); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should render the page title", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/how_it_works.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/how_it_works.test.tsx index a574f4b628e..6739beb81d9 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/how_it_works.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/how_it_works.test.tsx @@ -32,7 +32,7 @@ describe("HowItWorks", () => { it("should render the code block with a curl example", () => { renderWithProviders(); expect(screen.getByTestId("code-block")).toBeInTheDocument(); - expect(screen.getByTestId("code-block").textContent).toContain("curl"); + expect(screen.getByTestId("code-block")).toHaveTextContent(/curl/); }); it("should show the response header names for discount verification", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_dropdown.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_dropdown.test.tsx index 1c6800de7d2..52d5a3f9007 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_dropdown.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/pricing_calculator/multi_export_dropdown.test.tsx @@ -63,7 +63,7 @@ describe("MultiExportDropdown", () => { it("should not render anything when no entries have results", () => { const { container } = renderWithProviders(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should render the Export button when at least one entry has a result", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/provider_margin_table.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/provider_margin_table.test.tsx index dd478571568..3663783347d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/provider_margin_table.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/cost-tracking/_components/provider_margin_table.test.tsx @@ -68,7 +68,7 @@ describe("ProviderMarginTable", () => { />, ); const logo = screen.getByRole("img", { name: `${Providers.OpenAI} logo` }); - expect(logo.getAttribute("src")).toBe(providerLogoMap[Providers.OpenAI]); + expect(logo).toHaveAttribute("src", providerLogoMap[Providers.OpenAI]); }); it("should fall back to a letter avatar for a provider with no bundled logo", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsMonitorView.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsMonitorView.test.tsx index b946749bf65..9f27daab6b3 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsMonitorView.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails-monitor/_components/GuardrailsMonitorView.test.tsx @@ -32,7 +32,7 @@ describe("GuardrailsMonitorView", () => { render(, { wrapper }); - expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeDefined(); + expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeInTheDocument(); await waitFor(() => { expect(mockGetGuardrailsUsageOverview).toHaveBeenCalled(); }); @@ -40,6 +40,6 @@ describe("GuardrailsMonitorView", () => { it("should render without crashing when accessToken is null", async () => { render(, { wrapper }); - expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeDefined(); + expect(await screen.findByRole("heading", { name: /Guardrails Monitor/i })).toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.test.tsx index a386fca598e..e8463025e31 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.test.tsx @@ -53,6 +53,6 @@ describe("AddGuardrailForm provider options", () => { fireEvent.mouseDown(screen.getByLabelText("Guardrail Provider")); const logo = await screen.findByAltText("Presidio PII logo"); - expect(logo.getAttribute("src")).toContain("microsoft_azure.svg"); + expect(logo).toHaveAttribute("src", expect.stringContaining("microsoft_azure.svg")); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentFilterManager.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentFilterManager.test.tsx index c3fd2e3eb59..83ed695f34a 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentFilterManager.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/content_filter/ContentFilterManager.test.tsx @@ -124,7 +124,7 @@ describe("ContentFilterManager", () => { expect(screen.queryByTestId("content-filter-config")).not.toBeInTheDocument(); expect(screen.queryByTestId("content-filter-display")).not.toBeInTheDocument(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should render read-only display when isEditing is false", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_garden_card.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_garden_card.test.tsx index 2d1f35e456c..d81eaa5a4fc 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_garden_card.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_garden_card.test.tsx @@ -56,7 +56,7 @@ describe("GuardrailCard", () => { it("should render the logo through the shared Logo component with the card src", () => { render(); const img = screen.getByAltText("Test Guardrail logo"); - expect(img.getAttribute("src")).toContain("/logos/test.svg"); + expect(img).toHaveAttribute("src", expect.stringContaining("/logos/test.svg")); }); it("should pass a bundled static-import src through unchanged", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_info.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_info.test.tsx index aae1998644a..eca1cf4df8a 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_info.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_info.test.tsx @@ -109,7 +109,7 @@ describe("Guardrail Info", () => { ); const logo = await findByAltText("Presidio PII logo"); - expect(logo.getAttribute("src")).toContain("microsoft_azure.svg"); + expect(logo).toHaveAttribute("src", expect.stringContaining("microsoft_azure.svg")); }); it("should not render the edit button for config guardrails", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_table.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_table.test.tsx index 7612b702391..ee619dc7468 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_table.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/guardrail_table.test.tsx @@ -33,7 +33,7 @@ describe("GuardrailTable", () => { it("renders the provider logo from the bundled guardrail logo map", () => { render(); const logo = screen.getByAltText("Presidio PII logo"); - expect(logo.getAttribute("src")).toContain("microsoft_azure.svg"); + expect(logo).toHaveAttribute("src", expect.stringContaining("microsoft_azure.svg")); }); it("falls back to a letter avatar for an unknown provider slug", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx index 340077e9569..7f1f4cc4bd5 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx @@ -82,15 +82,15 @@ describe("(dashboard) Layout", () => { , ); - await waitFor(() => expect(screen.getByTestId("loading-screen")).toBeTruthy()); - expect(screen.queryByTestId("page-content")).toBeNull(); - expect(screen.queryByTestId("dashboard-header")).toBeNull(); + expect(await screen.findByTestId("loading-screen")).toBeInTheDocument(); + expect(screen.queryByTestId("page-content")).not.toBeInTheDocument(); + expect(screen.queryByTestId("dashboard-header")).not.toBeInTheDocument(); pendingUiConfig.resolve(); - await waitFor(() => expect(screen.getByTestId("page-content")).toBeTruthy()); - expect(screen.getByTestId("dashboard-header")).toBeTruthy(); - expect(screen.queryByTestId("loading-screen")).toBeNull(); + expect(await screen.findByTestId("page-content")).toBeInTheDocument(); + expect(screen.getByTestId("dashboard-header")).toBeInTheDocument(); + expect(screen.queryByTestId("loading-screen")).not.toBeInTheDocument(); }); it("redirects an invitation link to the onboarding route instead of rendering the dashboard shell", async () => { @@ -109,8 +109,8 @@ describe("(dashboard) Layout", () => { await waitFor(() => expect(replaceMock).toHaveBeenCalledWith(expect.stringContaining("/onboarding?invitation_id=abc123")), ); - expect(screen.queryByTestId("page-content")).toBeNull(); - expect(screen.queryByTestId("dashboard-header")).toBeNull(); - expect(screen.queryByTestId("sidebar")).toBeNull(); + expect(screen.queryByTestId("page-content")).not.toBeInTheDocument(); + expect(screen.queryByTestId("dashboard-header")).not.toBeInTheDocument(); + expect(screen.queryByTestId("sidebar")).not.toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx index c9007e29c3e..f08aacb5522 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/CreateMCPServer.integration.test.tsx @@ -676,7 +676,7 @@ describe("CreateMCPServer", () => { it("clears the DCR ref and the upstream warning when the modal closes so nothing leaks to the next session", async () => { const { rerender } = render(); await selectAntOption("Transport Type", "Streamable HTTP"); - await waitFor(() => expect(screen.getByPlaceholderText("https://your-mcp-server.com")).toBeInTheDocument()); + expect(await screen.findByPlaceholderText("https://your-mcp-server.com")).toBeInTheDocument(); const user = userEvent.setup({ delay: null }); await user.type(getServerNameInput(), "Leak_Server"); await user.type(screen.getByPlaceholderText("https://your-mcp-server.com"), "https://example.com/mcp"); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPLogoSelector.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPLogoSelector.test.tsx index f126a030b9f..0f75f32dda5 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPLogoSelector.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPLogoSelector.test.tsx @@ -69,6 +69,6 @@ describe("MCPLogoSelector", () => { it("should preview a custom external URL untouched", () => { render(); - expect(screen.getByAltText("Selected logo").getAttribute("src")).toBe("https://cdn.example.com/logo.png"); + expect(screen.getByAltText("Selected logo")).toHaveAttribute("src", "https://cdn.example.com/logo.png"); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPPermissionManagement.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPPermissionManagement.test.tsx index a53681f6cd8..ee6aee86a4d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPPermissionManagement.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPPermissionManagement.test.tsx @@ -48,7 +48,7 @@ describe("MCPPermissionManagement", () => { // The first switch in the component is for allow_all_keys const switches = screen.getAllByRole("switch"); const toggle = switches[0]; - expect(toggle).toHaveAttribute("aria-checked", "false"); + expect(toggle).not.toBeChecked(); }); const renderWithInitialValues = (initialValues: Record, props = {}) => { @@ -122,9 +122,9 @@ describe("MCPPermissionManagement", () => { // The first switch in the component is for allow_all_keys const switches = screen.getAllByRole("switch"); const toggle = switches[0]; - expect(toggle).toHaveAttribute("aria-checked", "true"); + expect(toggle).toBeChecked(); await user.click(toggle); - expect(toggle).toHaveAttribute("aria-checked", "false"); + expect(toggle).not.toBeChecked(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPServerCard.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPServerCard.test.tsx index d6343afe219..8c7fe46a1a2 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPServerCard.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/MCPServerCard.test.tsx @@ -52,13 +52,13 @@ describe("MCPServerCard logo", () => { it("passes an external logo_url through untouched", () => { renderCard({ mcp_info: { server_name: "demo_server", logo_url: "https://cdn.example.com/logo.png" } }); - expect(screen.getByAltText("demo_server logo").getAttribute("src")).toBe("https://cdn.example.com/logo.png"); + expect(screen.getByAltText("demo_server logo")).toHaveAttribute("src", "https://cdn.example.com/logo.png"); }); it("prefixes a stored asset path with the server root path under a non-root mount", () => { setServerRootPath("/litellm"); renderCard({ mcp_info: { server_name: "demo_server", logo_url: "/ui/assets/logos/github.svg" } }); - expect(screen.getByAltText("demo_server logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg"); + expect(screen.getByAltText("demo_server logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg"); }); it("renders a letter avatar when no logo_url is set", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connection_status.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connection_status.test.tsx index 15e5d886d37..7511b8684a4 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connection_status.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_connection_status.test.tsx @@ -21,7 +21,7 @@ describe("MCPConnectionStatus", () => { it("should render nothing when canFetchTools is false and no URL is set", () => { const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should show 'Complete required fields' message when URL is set but canFetchTools is false", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx index b660c4bdb76..6972c33ea1b 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx @@ -1214,8 +1214,9 @@ describe("MCPServerEdit (tool list fetch)", () => { ); await waitFor(() => { - expect(screen.getByTestId("mcp-tool-config").getAttribute("data-external-error")).toContain( - "Authorize with the upstream (browser-only", + expect(screen.getByTestId("mcp-tool-config")).toHaveAttribute( + "data-external-error", + expect.stringContaining("Authorize with the upstream (browser-only"), ); }); expect(networking.listMCPTools).not.toHaveBeenCalled(); @@ -1242,8 +1243,9 @@ describe("MCPServerEdit (tool list fetch)", () => { const { rerender } = render(); await waitFor(() => { - expect(screen.getByTestId("mcp-tool-config").getAttribute("data-external-error")).toContain( - "Authenticate with this server in the Tools tab", + expect(screen.getByTestId("mcp-tool-config")).toHaveAttribute( + "data-external-error", + expect.stringContaining("Authenticate with this server in the Tools tab"), ); }); expect(networking.listMCPTools).not.toHaveBeenCalled(); @@ -1277,8 +1279,9 @@ describe("MCPServerEdit (tool list fetch)", () => { ); await waitFor(() => { - expect(screen.getByTestId("mcp-tool-config").getAttribute("data-external-error")).toContain( - "Authenticate with this server in the Tools tab", + expect(screen.getByTestId("mcp-tool-config")).toHaveAttribute( + "data-external-error", + expect.stringContaining("Authenticate with this server in the Tools tab"), ); }); expect(networking.listMCPTools).not.toHaveBeenCalled(); @@ -1657,9 +1660,7 @@ describe("MCPServerEdit (OAuth token persistence on save)", () => { // Check "remove saved app" on server A. fireEvent.click(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ })); - expect( - (screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ }) as HTMLInputElement).checked, - ).toBe(true); + expect(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ })).toBeChecked(); // Switch the panel to server B without unmounting. rerender( @@ -1674,9 +1675,7 @@ describe("MCPServerEdit (OAuth token persistence on save)", () => { ); // The checkbox must have reset, so saving server B does not send the explicit-null delete write. - expect( - (screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ }) as HTMLInputElement).checked, - ).toBe(false); + expect(screen.getByRole("checkbox", { name: /Remove the saved OAuth app on save/ })).not.toBeChecked(); await act(async () => { fireEvent.click(screen.getAllByRole("button", { name: "Save Changes" })[0]); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/page.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/page.test.tsx index 222a2e04117..521f89a39f2 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/page.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/page.test.tsx @@ -76,14 +76,14 @@ describe("ModelsAndEndpointsPage", () => { const { getByRole, getByTestId, queryByTestId } = renderPage(); await user.click(getByRole("tab", { name: "Health Status" })); expect(getByTestId("panel-health")).toBeInTheDocument(); - expect(queryByTestId("panel-all-models")).toBeNull(); + expect(queryByTestId("panel-all-models")).not.toBeInTheDocument(); }); it("renders the model detail overlay from the ?model drill-in and hides the tabs", () => { detailState.modelId = "abc-123"; const { getByTestId, queryByRole } = renderPage(); expect(getByTestId("model-info")).toHaveTextContent("model:abc-123"); - expect(queryByRole("tab", { name: "All Models" })).toBeNull(); + expect(queryByRole("tab", { name: "All Models" })).not.toBeInTheDocument(); }); it("renders the team detail overlay from the ?team drill-in", () => { @@ -95,8 +95,8 @@ describe("ModelsAndEndpointsPage", () => { it("hides admin-only tabs for a non-admin user", () => { mockUseAuthorized.mockReturnValue(NON_ADMIN); const { queryByRole } = renderPage(); - expect(queryByRole("tab", { name: "LLM Credentials" })).toBeNull(); - expect(queryByRole("tab", { name: "Health Status" })).toBeNull(); + expect(queryByRole("tab", { name: "LLM Credentials" })).not.toBeInTheDocument(); + expect(queryByRole("tab", { name: "Health Status" })).not.toBeInTheDocument(); }); // Auto-routers are excluded from the All Models table, so this tab is their home: the only @@ -125,7 +125,7 @@ describe("ModelsAndEndpointsPage", () => { mockUseAuthorized.mockReturnValue(NON_ADMIN); const { queryByRole } = renderPage(); - expect(queryByRole("tab", { name: /Auto-Routers/ })).toBeNull(); + expect(queryByRole("tab", { name: /Auto-Routers/ })).not.toBeInTheDocument(); }); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AdditionalModelSettings.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AdditionalModelSettings.test.tsx index 1c2cb426f23..4c0f2831c6e 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AdditionalModelSettings.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AdditionalModelSettings.test.tsx @@ -39,13 +39,13 @@ describe("AdditionalModelSettings", () => { await waitFor(() => { const sliders = screen.getAllByRole("slider"); expect(sliders.length).toBeGreaterThan(0); - expect(sliders[0]).not.toBeDisabled(); + expect(sliders[0]).toBeEnabled(); }); const temperatureSlider = screen.getAllByRole("slider")[0]; const maxTokensSlider = screen.getAllByRole("slider")[1]; - expect(temperatureSlider).not.toBeDisabled(); - expect(maxTokensSlider).not.toBeDisabled(); + expect(temperatureSlider).toBeEnabled(); + expect(maxTokensSlider).toBeEnabled(); }); it("should not show Stream responses when onStreamingChange is not provided", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.test.tsx index e30f87115cf..f2c2c3d2c8c 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/AgentBuilderView.test.tsx @@ -132,7 +132,7 @@ describe("AgentBuilderView", () => { expect(screen.getByRole("button", { name: "research-agent litellm_agent" })).toBeInTheDocument(); expect(screen.getByText("Agent Builder")).toBeInTheDocument(); - await waitFor(() => expect(screen.getByDisplayValue("support-agent")).toBeInTheDocument()); + expect(await screen.findByDisplayValue("support-agent")).toBeInTheDocument(); expect(screen.getByDisplayValue("Be helpful.")).toBeInTheDocument(); expect(screen.getByDisplayValue("0.3")).toBeInTheDocument(); }); @@ -144,7 +144,7 @@ describe("AgentBuilderView", () => { await user.click(screen.getByRole("button", { name: "research-agent litellm_agent" })); - await waitFor(() => expect(screen.getByDisplayValue("research-agent")).toBeInTheDocument()); + expect(await screen.findByDisplayValue("research-agent")).toBeInTheDocument(); }); it("offers a blank draft and a save control for a new agent", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatComposer.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatComposer.test.tsx index f3efb0a9b0f..da2e4debb3c 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatComposer.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatComposer.test.tsx @@ -109,6 +109,6 @@ describe("ChatComposer", () => { fireEvent.click(addonOf(container)); - expect(document.activeElement).toBe(screen.getByTestId("chat-composer-input")); + expect(screen.getByTestId("chat-composer-input")).toHaveFocus(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatUI.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatUI.test.tsx index de079cdebc9..24c56b276af 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatUI.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/ChatUI.test.tsx @@ -148,10 +148,10 @@ describe("ChatUI", () => { await waitFor(() => { expect(screen.getAllByText("ChatModel").length).toBeGreaterThan(0); expect(screen.getAllByText("NoModeModel").length).toBeGreaterThan(0); - expect(screen.queryByText("SpeechModel")).toBeNull(); - expect(screen.queryByText("ImageModel")).toBeNull(); - expect(screen.queryByText("ResponsesModel")).toBeNull(); - expect(screen.queryByText("RealtimeModel")).toBeNull(); + expect(screen.queryByText("SpeechModel")).not.toBeInTheDocument(); + expect(screen.queryByText("ImageModel")).not.toBeInTheDocument(); + expect(screen.queryByText("ResponsesModel")).not.toBeInTheDocument(); + expect(screen.queryByText("RealtimeModel")).not.toBeInTheDocument(); }); }); @@ -182,7 +182,7 @@ describe("ChatUI", () => { await waitFor(() => { expect(screen.getAllByText("RealtimeModel").length).toBeGreaterThan(0); expect(screen.getAllByText("NoModeModel").length).toBeGreaterThan(0); - expect(screen.queryByText("ChatModel")).toBeNull(); + expect(screen.queryByText("ChatModel")).not.toBeInTheDocument(); }); }); @@ -234,7 +234,7 @@ describe("ChatUI", () => { await selectComboboxOption("Select an endpoint", "/v1/chat/completions"); await waitFor(() => { - expect(mcpInput()).not.toBeDisabled(); + expect(mcpInput()).toBeEnabled(); }); }); @@ -432,7 +432,7 @@ describe("ChatUI", () => { }); await waitFor(() => { - expect(screen.queryByText("Fill")).toBeNull(); + expect(screen.queryByText("Fill")).not.toBeInTheDocument(); }); const customProxyInput = screen.getByPlaceholderText( @@ -461,7 +461,7 @@ describe("ChatUI", () => { const mcpInput = screen.getByLabelText("Select MCP servers"); expect(mcpInput).toBeInTheDocument(); - expect(mcpInput).not.toBeDisabled(); + expect(mcpInput).toBeEnabled(); await user.click(mcpInput); @@ -521,7 +521,7 @@ describe("ChatUI", () => { await waitFor(() => { expect(screen.getAllByText("ChatModel").length).toBeGreaterThan(0); }); - expect(screen.queryByText("SpeechModel")).toBeNull(); + expect(screen.queryByText("SpeechModel")).not.toBeInTheDocument(); }); it("should attach an audio file dropped on the transcription upload area", async () => { @@ -611,7 +611,7 @@ describe("ChatUI", () => { await user.clear(keyField); await waitFor(() => { - expect(screen.getByPlaceholderText("Select a Model")).not.toBeDisabled(); + expect(screen.getByPlaceholderText("Select a Model")).toBeEnabled(); }); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/CodeInterpreterOutput.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/CodeInterpreterOutput.test.tsx index a42bd42ed81..c9cfc3ac833 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/CodeInterpreterOutput.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/CodeInterpreterOutput.test.tsx @@ -235,7 +235,7 @@ describe("CodeInterpreterOutput", () => { it("should return null when no code and no annotations", () => { const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should handle multiple image formats", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/RealtimePlayground.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/RealtimePlayground.test.tsx index a72a02a59e9..f374582fb41 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/RealtimePlayground.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/chat_ui/RealtimePlayground.test.tsx @@ -1,4 +1,4 @@ -import { act, render, screen, waitFor } from "@testing-library/react"; +import { act, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import RealtimePlayground from "./RealtimePlayground"; @@ -261,7 +261,7 @@ describe("RealtimePlayground", () => { await user.click(screen.getByRole("button", { name: /Disconnect/i })); expect(socket.close).toHaveBeenCalled(); - await waitFor(() => expect(screen.getByRole("button", { name: /Connect/i })).toBeInTheDocument()); + expect(await screen.findByRole("button", { name: /Connect/i })).toBeInTheDocument(); expect(screen.queryByPlaceholderText("Type a message or use the mic...")).not.toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/CompareUI.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/CompareUI.test.tsx index a68513b5204..cb8a5c16d3b 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/CompareUI.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/CompareUI.test.tsx @@ -138,14 +138,14 @@ describe("CompareUI", () => { } await waitFor(() => { - expect(queryByTestId("has-attachment")).toBeInTheDocument(); + expect(getByTestId("has-attachment")).toBeInTheDocument(); }); const textarea = getByTestId("message-textarea"); await user.type(textarea, "Describe this image"); const sendButton = getByTestId("send-button"); - expect(sendButton).not.toBeDisabled(); + expect(sendButton).toBeEnabled(); await user.click(sendButton); await waitFor(() => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/components/MessageInput.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/components/MessageInput.test.tsx index 049b70b982c..f1db0e863fa 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/components/MessageInput.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/playground/components/compareUI/components/MessageInput.test.tsx @@ -41,7 +41,7 @@ describe("MessageInput", () => { render(); const send = screen.getByRole("button"); - expect(send).not.toBeDisabled(); + expect(send).toBeEnabled(); await user.click(send); expect(onSend).toHaveBeenCalledTimes(1); @@ -63,7 +63,7 @@ describe("MessageInput", () => { expect(screen.getByTestId("upload-component")).toBeInTheDocument(); const send = screen.getByRole("button"); - expect(send).not.toBeDisabled(); + expect(send).toBeEnabled(); await user.click(send); expect(onSend).toHaveBeenCalledTimes(1); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/AttachmentTable.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/AttachmentTable.test.tsx index b544c44d190..e746effd634 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/AttachmentTable.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/AttachmentTable.test.tsx @@ -135,9 +135,9 @@ describe("AttachmentTable", () => { const attachment = makeAttachment({ attachment_id: "att-abcdef1234567" }); renderWithProviders(); const idElement = screen.getByText("att-abcdef1234567"); - expect(idElement.className).toContain("font-mono"); - expect(idElement.className).toContain("truncate"); - expect(idElement.className).not.toContain("bg-blue-50"); + expect(idElement).toHaveClass("font-mono"); + expect(idElement).toHaveClass("truncate"); + expect(idElement).not.toHaveClass("bg-blue-50"); }); it("should render model chips when the attachment has models", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/ai_suggestion_modal.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/ai_suggestion_modal.test.tsx index 4db75fb1ced..c504d0759ae 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/ai_suggestion_modal.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/ai_suggestion_modal.test.tsx @@ -96,7 +96,7 @@ describe("AiSuggestionModal", () => { expect(screen.getByRole("button", { name: "Suggest Policies" })).toBeDisabled(); await pickModel(user); - expect(screen.getByRole("button", { name: "Suggest Policies" })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: "Suggest Policies" })).toBeEnabled(); }); it("sends the examples, description and model to the suggest API", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/index.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/index.test.tsx index 3b6534ab0f0..f508f6866d6 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/index.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/index.test.tsx @@ -156,8 +156,8 @@ describe("PoliciesPanel attachment delete", () => { await waitFor(() => { expect(networkingMocks.deletePolicyAttachmentCall).toHaveBeenCalledTimes(1); - expect(networkingMocks.deletePolicyAttachmentCall).toHaveBeenCalledWith("test-token", EXPECTED_ATTACHMENT_ID); }); + expect(networkingMocks.deletePolicyAttachmentCall).toHaveBeenCalledWith("test-token", EXPECTED_ATTACHMENT_ID); }); it("should show mutation pending state while attachment delete is in flight", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/template_parameter_modal.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/template_parameter_modal.test.tsx index 5dcab5cec80..c3b55cd18ff 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/template_parameter_modal.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/template_parameter_modal.test.tsx @@ -95,7 +95,7 @@ describe("TemplateParameterModal", () => { await user.type(screen.getByPlaceholderText("e.g. Contoso"), "Contoso"); - expect(screen.getByRole("button", { name: "Continue" })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: "Continue" })).toBeEnabled(); }); it("hands the entered parameters back to the caller", async () => { @@ -181,7 +181,7 @@ describe("TemplateParameterModal", () => { expect(await screen.findByText("Northwind")).toBeInTheDocument(); expect(screen.getByText("Fabrikam")).toBeInTheDocument(); await waitFor(() => { - expect(screen.getByRole("button", { name: "Continue" })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: "Continue" })).toBeEnabled(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/CreateSearchTools.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/CreateSearchTools.test.tsx index 7f1d7edc97f..f860b1a8bd4 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/CreateSearchTools.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/CreateSearchTools.test.tsx @@ -12,17 +12,20 @@ describe("SearchProviderLabel", () => { it("renders the exa_ai logo file for the exa_ai slug", () => { render(); const img = screen.getByRole("img", { name: "Exa AI logo" }); - expect(img.getAttribute("src")).toContain("exa_ai.png"); + expect(img).toHaveAttribute("src", expect.stringContaining("exa_ai.png")); }); it("renders the google_pse logo file for the google_pse slug", () => { render(); - expect(screen.getByRole("img", { name: "Google PSE logo" }).getAttribute("src")).toContain("google_pse.png"); + expect(screen.getByRole("img", { name: "Google PSE logo" })).toHaveAttribute( + "src", + expect.stringContaining("google_pse.png"), + ); }); it("falls back to a letter avatar for a provider with no bundled logo", () => { render(); - expect(screen.queryByRole("img")).toBeNull(); + expect(screen.queryByRole("img")).not.toBeInTheDocument(); expect(screen.getByText("B")).toBeInTheDocument(); expect(screen.getByText("Brave Search")).toBeInTheDocument(); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/SearchToolTester.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/SearchToolTester.test.tsx index fd944120624..3d4144a74e6 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/SearchToolTester.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/search-tools/_components/SearchToolTester.test.tsx @@ -82,7 +82,7 @@ describe("SearchToolTester", () => { const input = screen.getByPlaceholderText("Enter your search query..."); await user.type(input, "test query"); const searchButton = screen.getByRole("button", { name: /search/i }); - expect(searchButton).not.toBeDisabled(); + expect(searchButton).toBeEnabled(); }); it("should call searchToolQueryCall when search button is clicked", async () => { @@ -416,11 +416,9 @@ describe("SearchToolTester", () => { await user.type(input, "test query"); const searchButton = screen.getByRole("button", { name: /search/i }); await user.click(searchButton); - await waitFor(() => { - const link = screen.getByRole("link", { name: "Test Result 1" }); - expect(link).toHaveAttribute("href", "https://example.com/result1"); - expect(link).toHaveAttribute("target", "_blank"); - expect(link).toHaveAttribute("rel", "noopener noreferrer"); - }); + const link = await screen.findByRole("link", { name: "Test Result 1" }); + expect(link).toHaveAttribute("href", "https://example.com/result1"); + expect(link).toHaveAttribute("rel", "noopener noreferrer"); + expect(link).toHaveAttribute("target", "_blank"); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/skills/_components/add_plugin_form.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/skills/_components/add_plugin_form.test.tsx index 74d1fb5facf..713cee7682c 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/skills/_components/add_plugin_form.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/skills/_components/add_plugin_form.test.tsx @@ -90,7 +90,7 @@ describe("AddPluginForm", () => { await waitFor(() => { expect(screen.getByText(/Git repo/)).toBeInTheDocument(); }); - expect(screen.getByPlaceholderText(SUBPATH_PLACEHOLDER)).not.toBeDisabled(); + expect(screen.getByPlaceholderText(SUBPATH_PLACEHOLDER)).toBeEnabled(); }); it("combines a repo URL with a subfolder into a git-subdir preview", async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/transform-request/TransformRequestPanel.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/transform-request/TransformRequestPanel.test.tsx index a0add153116..d8d46c361a2 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/transform-request/TransformRequestPanel.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/transform-request/TransformRequestPanel.test.tsx @@ -76,10 +76,10 @@ describe("TransformRequestPanel", () => { }); const output = await screen.findByText(/api\.anthropic\.com\/v1\/messages/); - expect(output.textContent).toContain("curl -X POST"); - expect(output.textContent).toContain("-H 'x-api-key: redacted'"); - expect(output.textContent).toContain('"model": "claude-opus-4-8"'); - expect(output.textContent).toContain('"max_tokens": 42'); + expect(output).toHaveTextContent(/curl \-X POST/); + expect(output).toHaveTextContent(/\-H 'x\-api\-key: redacted'/); + expect(output).toHaveTextContent(/"model": "claude\-opus\-4\-8"/); + expect(output).toHaveTextContent(/"max_tokens": 42/); expect(notify.success).toHaveBeenCalledWith("Request transformed successfully"); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EndpointUsage/components/EndpointUsageLineChart.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EndpointUsage/components/EndpointUsageLineChart.test.tsx index 33914e627dc..81ca90d8cb9 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EndpointUsage/components/EndpointUsageLineChart.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EndpointUsage/components/EndpointUsageLineChart.test.tsx @@ -68,8 +68,8 @@ describe("EndpointUsageLineChart", () => { const legend = container.querySelector(".recharts-legend-wrapper"); expect(legend).not.toBeNull(); - expect(legend!.textContent).toContain("/chat/completions"); - expect(legend!.textContent).toContain("/embeddings"); + expect(legend!).toHaveTextContent(/\/chat\/completions/); + expect(legend!).toHaveTextContent(/\/embeddings/); }); it("orders formatted dates oldest to newest on the x axis", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx index 1f3dd5642ee..b11fbbee258 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/EntityUsage/EntityUsage.test.tsx @@ -838,7 +838,7 @@ describe("EntityUsage", () => { const sectors = container.querySelectorAll(".recharts-pie-sector path"); expect(sectors).toHaveLength(1); - expect(sectors[0].getAttribute("fill")).toBe("var(--color-cyan-500, #06b6d4)"); + expect(sectors[0]).toHaveAttribute("fill", "var(--color-cyan-500, #06b6d4)"); const centerLabels = Array.from(container.querySelectorAll("text.fill-foreground")).map((text) => text.textContent); expect(centerLabels).toContain("$100.50"); @@ -883,7 +883,7 @@ describe("EntityUsage", () => { render(); const logo = await screen.findByAltText("openai logo"); - expect(logo.getAttribute("src")).toContain("openai_small"); + expect(logo).toHaveAttribute("src", expect.stringContaining("openai_small")); }); describe("capability gating", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/user_edit_view.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/user_edit_view.test.tsx index 4d5ddaa1df6..b3d77a567f7 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/user_edit_view.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/user_edit_view.test.tsx @@ -241,7 +241,7 @@ describe("UserEditView", () => { await waitFor(() => { const modelsSelect = screen.getByRole("combobox", { name: /select models/i }); - expect(modelsSelect).not.toBeDisabled(); + expect(modelsSelect).toBeEnabled(); }); }); @@ -300,7 +300,7 @@ describe("UserEditView", () => { await waitFor(() => { const budgetInput = screen.getByRole("spinbutton", { name: /max budget/i }); - expect(budgetInput).not.toBeDisabled(); + expect(budgetInput).toBeEnabled(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users.test.tsx index 1a3d517df3e..57a50f6cfc2 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users.test.tsx @@ -273,7 +273,7 @@ describe("ViewUserDashboard", () => { await user.click(screen.getByTestId("datatable-select-row-user-2")); expect(screen.getByTestId("bulk-edit-users")).toHaveTextContent("Bulk Edit (1 selected)"); - expect(screen.getByTestId("bulk-edit-users")).not.toBeDisabled(); + expect(screen.getByTestId("bulk-edit-users")).toBeEnabled(); await user.click(screen.getByTestId("datatable-select-all")); expect(screen.getByTestId("bulk-edit-users")).toHaveTextContent("Bulk Edit (2 selected)"); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/UsersTable.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/UsersTable.test.tsx index 6262fd60f70..860b1c35cfd 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/UsersTable.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/users/_components/view_users/UsersTable.test.tsx @@ -119,7 +119,7 @@ describe("UsersTable", () => { "Created At", "Updated At", ].forEach((header) => { - expect(headerRow.textContent).toContain(header); + expect(headerRow).toHaveTextContent(header); }); }); @@ -251,7 +251,7 @@ describe("UsersTable", () => { await user.click(screen.getByTestId("datatable-select-row-user-1")); - expect(screen.getByTestId("datatable-select-all")).toHaveAttribute("aria-checked", "mixed"); + expect(screen.getByTestId("datatable-select-all")).toBePartiallyChecked(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/CreateVectorStore.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/CreateVectorStore.test.tsx index 6c7a647e2d3..048b2d05f1d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/CreateVectorStore.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/CreateVectorStore.test.tsx @@ -226,9 +226,9 @@ describe("CreateVectorStore", () => { // Check if S3-specific fields are displayed await waitFor(() => { - expect(screen.queryByText("Vector Bucket Name")).toBeInTheDocument(); - expect(screen.queryByText("AWS Region")).toBeInTheDocument(); - expect(screen.queryByText("Embedding Model")).toBeInTheDocument(); + expect(screen.getByText("Vector Bucket Name")).toBeInTheDocument(); + expect(screen.getByText("AWS Region")).toBeInTheDocument(); + expect(screen.getByText("Embedding Model")).toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/IndexesTable.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/IndexesTable.test.tsx index f31c51f3fba..e318efb103b 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/IndexesTable.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/IndexesTable.test.tsx @@ -87,7 +87,7 @@ describe("IndexesTable", () => { it("should link created_by to the user detail deep link", () => { render(); const link = screen.getByRole("link", { name: "admin@example.com" }); - expect(link.getAttribute("href")).toMatch(/\/users\?user=admin%40example\.com$/); + expect(link).toHaveAttribute("href", expect.stringMatching(/\/users\?user=admin%40example\.com$/)); }); it("should keep the dash fallback and render no link for a null created_by", () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/VectorStoreForm.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/VectorStoreForm.test.tsx index 3eb013d47ad..94511ea114d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/VectorStoreForm.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/vector-stores/_components/VectorStoreForm.test.tsx @@ -29,6 +29,6 @@ describe("VectorStoreForm", () => { renderForm(); const logo = screen.getByRole("img", { name: `${VectorStoreProviders.Bedrock} logo` }); - expect(logo.getAttribute("src")).toBe(providerLogoMap[Providers.Bedrock]); + expect(logo).toHaveAttribute("src", providerLogoMap[Providers.Bedrock]); }); }); diff --git a/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx b/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx index 718c692a7a6..1918d19dae6 100644 --- a/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx +++ b/ui/litellm-dashboard/src/app/chat/page.integration.test.tsx @@ -69,7 +69,7 @@ const ON_TOTAL_LATENCY_INDEX = 24; async function sendOneMessage(): Promise { render(); - await waitFor(() => expect(screen.getByRole("button", { name: /gpt-5\.4-mini/ })).toBeInTheDocument()); + expect(await screen.findByRole("button", { name: /gpt-5\.4-mini/ })).toBeInTheDocument(); fireEvent.change(screen.getByPlaceholderText("How can I help you today?"), { target: { value: "How much did this cost?" }, }); @@ -98,7 +98,7 @@ describe("/ui/chat request metrics", () => { await sendOneMessage(); - await waitFor(() => expect(screen.getByLabelText("Total: 20")).toBeInTheDocument()); + expect(await screen.findByLabelText("Total: 20")).toBeInTheDocument(); expect(screen.getByLabelText("TTFT: 0.25s")).toBeInTheDocument(); expect(screen.getByLabelText("Total Latency: 1.20s")).toBeInTheDocument(); expect(screen.getByLabelText("In: 12")).toBeInTheDocument(); @@ -126,7 +126,7 @@ describe("/ui/chat request metrics", () => { await sendOneMessage(); - await waitFor(() => expect(screen.getByText("No usage here.")).toBeInTheDocument()); + expect(await screen.findByText("No usage here.")).toBeInTheDocument(); expect(document.querySelector(".response-metrics")).toBeNull(); }); }); diff --git a/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.test.tsx b/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.test.tsx index 0a859ca95f8..3a66efd9fe1 100644 --- a/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.test.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.test.tsx @@ -84,7 +84,7 @@ describe("UsefulLinksManagement", () => { render(); - await waitFor(() => expect(screen.getByText("First Link")).toBeInTheDocument()); + expect(await screen.findByText("First Link")).toBeInTheDocument(); await user.click(screen.getByRole("button", { name: /rearrange order/i })); @@ -123,7 +123,7 @@ describe("UsefulLinksManagement", () => { render(); - await waitFor(() => expect(screen.getByText("Test Link")).toBeInTheDocument()); + expect(await screen.findByText("Test Link")).toBeInTheDocument(); // Click edit button const editButton = screen.getByTestId("edit-link-0-Test Link"); @@ -147,7 +147,7 @@ describe("UsefulLinksManagement", () => { render(); - await waitFor(() => expect(screen.getByText("Test Link")).toBeInTheDocument()); + expect(await screen.findByText("Test Link")).toBeInTheDocument(); // Click edit button const editButton = screen.getByTestId("edit-link-0-Test Link"); @@ -183,7 +183,7 @@ describe("UsefulLinksManagement", () => { render(); - await waitFor(() => expect(screen.getByText("Test Link")).toBeInTheDocument()); + expect(await screen.findByText("Test Link")).toBeInTheDocument(); // Click edit button const editButton = screen.getByTestId("edit-link-0-Test Link"); @@ -216,7 +216,7 @@ describe("UsefulLinksManagement", () => { render(); - await waitFor(() => expect(screen.getByText("First Link")).toBeInTheDocument()); + expect(await screen.findByText("First Link")).toBeInTheDocument(); // Enter rearrange mode await user.click(screen.getByRole("button", { name: /rearrange order/i })); @@ -235,7 +235,7 @@ describe("UsefulLinksManagement", () => { const user = userEvent.setup(); render(); - await waitFor(() => expect(screen.getByText("Link Management")).toBeInTheDocument()); + expect(await screen.findByText("Link Management")).toBeInTheDocument(); // Initially expanded expect(screen.getByText("Manage Existing Links")).toBeInTheDocument(); diff --git a/ui/litellm-dashboard/src/components/AIHub/forms/MakeAgentPublicForm.test.tsx b/ui/litellm-dashboard/src/components/AIHub/forms/MakeAgentPublicForm.test.tsx index a55beaf517f..882e059e327 100644 --- a/ui/litellm-dashboard/src/components/AIHub/forms/MakeAgentPublicForm.test.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/forms/MakeAgentPublicForm.test.tsx @@ -74,7 +74,7 @@ describe("MakeAgentPublicForm", () => { // Check that the Next button is enabled (agents are preselected) const nextButton = screen.getByRole("button", { name: "Next" }); - expect(nextButton).not.toBeDisabled(); + expect(nextButton).toBeEnabled(); }); it("should handle agent selection and navigation", async () => { @@ -91,7 +91,7 @@ describe("MakeAgentPublicForm", () => { // Verify Next button is enabled const nextButton = screen.getByRole("button", { name: "Next" }); - expect(nextButton).not.toBeDisabled(); + expect(nextButton).toBeEnabled(); // Click Next await act(async () => { diff --git a/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.test.tsx b/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.test.tsx index ff385b3ed7c..5b96e9ad194 100644 --- a/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.test.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.test.tsx @@ -97,7 +97,7 @@ describe("MakeMCPPublicForm", () => { // Check that the Next button is enabled (servers are preselected) const nextButton = screen.getByRole("button", { name: "Next" }); - expect(nextButton).not.toBeDisabled(); + expect(nextButton).toBeEnabled(); }); it("should handle server selection and navigation", async () => { @@ -114,7 +114,7 @@ describe("MakeMCPPublicForm", () => { // Verify Next button is enabled const nextButton = screen.getByRole("button", { name: "Next" }); - expect(nextButton).not.toBeDisabled(); + expect(nextButton).toBeEnabled(); // Click Next await act(async () => { diff --git a/ui/litellm-dashboard/src/components/AIHub/forms/MakeModelPublicForm.test.tsx b/ui/litellm-dashboard/src/components/AIHub/forms/MakeModelPublicForm.test.tsx index ac0df137f6a..013d92ea463 100644 --- a/ui/litellm-dashboard/src/components/AIHub/forms/MakeModelPublicForm.test.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/forms/MakeModelPublicForm.test.tsx @@ -121,7 +121,7 @@ describe("MakeModelPublicForm", () => { // Check that the Next button is enabled (models are preselected) const nextButton = screen.getByRole("button", { name: "Next" }); - expect(nextButton).not.toBeDisabled(); + expect(nextButton).toBeEnabled(); }); it("should handle model selection and navigation", async () => { @@ -138,7 +138,7 @@ describe("MakeModelPublicForm", () => { // Verify Next button is enabled const nextButton = screen.getByRole("button", { name: "Next" }); - expect(nextButton).not.toBeDisabled(); + expect(nextButton).toBeEnabled(); // Click Next await act(async () => { diff --git a/ui/litellm-dashboard/src/components/BetaBadge.test.tsx b/ui/litellm-dashboard/src/components/BetaBadge.test.tsx index 7eaf414087d..888842feada 100644 --- a/ui/litellm-dashboard/src/components/BetaBadge.test.tsx +++ b/ui/litellm-dashboard/src/components/BetaBadge.test.tsx @@ -47,7 +47,7 @@ describe("BetaBadge", () => { const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should render badge with dot instead of text when dot prop is true", () => { diff --git a/ui/litellm-dashboard/src/components/DashboardHeader.test.tsx b/ui/litellm-dashboard/src/components/DashboardHeader.test.tsx index 6f08dc8ebd4..6c656382deb 100644 --- a/ui/litellm-dashboard/src/components/DashboardHeader.test.tsx +++ b/ui/litellm-dashboard/src/components/DashboardHeader.test.tsx @@ -1,5 +1,5 @@ import { afterEach, describe, expect, it, vi } from "vitest"; -import { act, fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { act, fireEvent, render, screen } from "@testing-library/react"; import { DashboardHeader } from "./DashboardHeader"; const { mockUsePluginMode, mockUseUISettings, state } = vi.hoisted(() => { @@ -44,7 +44,7 @@ describe("DashboardHeader breadcrumb", () => { act(() => { fireEvent.click(selector); }); - await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument()); + expect(await screen.findByText("Chat")).toBeInTheDocument(); }); it("keeps the AI Gateway selector at the root even when there is nothing to switch to (discovery)", () => { 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 bad740fa361..0581a381a9a 100644 --- a/ui/litellm-dashboard/src/components/Navbar/BlogDropdown/BlogDropdown.test.tsx +++ b/ui/litellm-dashboard/src/components/Navbar/BlogDropdown/BlogDropdown.test.tsx @@ -197,12 +197,10 @@ describe("BlogDropdown", () => { await openDropdown(); - await waitFor(() => { - const link = screen.getByRole("link", { name: /post one/i }); - expect(link).toHaveAttribute("href", "https://example.com/1"); - expect(link).toHaveAttribute("target", "_blank"); - expect(link).toHaveAttribute("rel", "noopener noreferrer"); - }); + const link = await screen.findByRole("link", { name: /post one/i }); + expect(link).toHaveAttribute("href", "https://example.com/1"); + expect(link).toHaveAttribute("rel", "noopener noreferrer"); + expect(link).toHaveAttribute("target", "_blank"); }); it("should render formatted post dates", async () => { @@ -226,12 +224,10 @@ describe("BlogDropdown", () => { await openDropdown(); - await waitFor(() => { - const viewAllLink = screen.getByRole("link", { 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"); - }); + const viewAllLink = await screen.findByRole("link", { name: /view all posts/i }); + expect(viewAllLink).toHaveAttribute("href", "https://docs.litellm.ai/blog"); + expect(viewAllLink).toHaveAttribute("rel", "noopener noreferrer"); + expect(viewAllLink).toHaveAttribute("target", "_blank"); }); }); diff --git a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx index d9a28b2ab8c..449ef2eddc6 100644 --- a/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx +++ b/ui/litellm-dashboard/src/components/Navbar/ViewSwitcher.test.tsx @@ -1,5 +1,5 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { act, fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { act, fireEvent, render, screen } from "@testing-library/react"; import ViewSwitcher from "./ViewSwitcher"; const { mockUsePluginMode, mockUseUISettings, mockUsePathname, state } = vi.hoisted(() => { @@ -58,7 +58,7 @@ describe("ViewSwitcher", () => { act(() => { fireEvent.click(button); }); - await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument()); + expect(await screen.findByText("Chat")).toBeInTheDocument(); expect(screen.getByText(/Admins can enable in Settings/i)).toBeInTheDocument(); act(() => { @@ -81,7 +81,7 @@ describe("ViewSwitcher", () => { act(() => { fireEvent.click(screen.getByRole("button")); }); - await waitFor(() => expect(screen.getByText("AI Gateway")).toBeInTheDocument()); + expect(await screen.findByText("AI Gateway")).toBeInTheDocument(); expect(screen.getByText("Observability")).toBeInTheDocument(); }); @@ -93,7 +93,7 @@ describe("ViewSwitcher", () => { act(() => { fireEvent.click(screen.getByRole("button")); }); - await waitFor(() => expect(screen.getByText("Chat UI")).toBeInTheDocument()); + expect(await screen.findByText("Chat UI")).toBeInTheDocument(); act(() => { fireEvent.click(screen.getByText("Chat UI")); }); @@ -108,7 +108,7 @@ describe("ViewSwitcher", () => { act(() => { fireEvent.click(screen.getByRole("button")); }); - await waitFor(() => expect(screen.getByText("Chat")).toBeInTheDocument()); + expect(await screen.findByText("Chat")).toBeInTheDocument(); expect(screen.queryByText(/Admins can enable in Settings/i)).not.toBeInTheDocument(); act(() => { @@ -127,7 +127,7 @@ describe("ViewSwitcher", () => { act(() => { fireEvent.click(screen.getByRole("button")); }); - await waitFor(() => expect(screen.getByText("AI Gateway")).toBeInTheDocument()); + expect(await screen.findByText("AI Gateway")).toBeInTheDocument(); act(() => { fireEvent.click(screen.getByText("AI Gateway")); }); @@ -143,7 +143,7 @@ describe("ViewSwitcher", () => { act(() => { fireEvent.click(screen.getByRole("button")); }); - await waitFor(() => expect(screen.getByText("Observability")).toBeInTheDocument()); + expect(await screen.findByText("Observability")).toBeInTheDocument(); expect(screen.getByText("Chat")).toBeInTheDocument(); expect(screen.getByText(/Admins can enable in Settings/i)).toBeInTheDocument(); diff --git a/ui/litellm-dashboard/src/components/SSOModals.test.tsx b/ui/litellm-dashboard/src/components/SSOModals.test.tsx index 0fcfe60ffe8..783fd58392a 100644 --- a/ui/litellm-dashboard/src/components/SSOModals.test.tsx +++ b/ui/litellm-dashboard/src/components/SSOModals.test.tsx @@ -67,10 +67,8 @@ describe("SSOModals", () => { const ssoProviderSelect = screen.getByLabelText("SSO Provider"); fireEvent.mouseDown(ssoProviderSelect); // Wait for dropdown and select Google - await waitFor(() => { - const googleOption = screen.getByText("Google SSO"); - fireEvent.click(googleOption); - }); + const googleOption = await screen.findByText("Google SSO"); + fireEvent.click(googleOption); // Fill in the email field const emailInput = screen.getByLabelText("Proxy Admin Email"); @@ -119,10 +117,8 @@ describe("SSOModals", () => { const ssoProviderSelect = screen.getByLabelText("SSO Provider"); fireEvent.mouseDown(ssoProviderSelect); // Wait for dropdown and select Google - await waitFor(() => { - const googleOption = screen.getByText("Google SSO"); - fireEvent.click(googleOption); - }); + const googleOption = await screen.findByText("Google SSO"); + fireEvent.click(googleOption); // Fill in the email field const emailInput = screen.getByLabelText("Proxy Admin Email"); @@ -216,10 +212,8 @@ describe("SSOModals", () => { const ssoProviderSelect = screen.getByLabelText("SSO Provider"); fireEvent.mouseDown(ssoProviderSelect); // Wait for dropdown and select Google - await waitFor(() => { - const googleOption = screen.getByText("Google SSO"); - fireEvent.click(googleOption); - }); + const googleOption = await screen.findByText("Google SSO"); + fireEvent.click(googleOption); // Fill in the email field const emailInput = screen.getByLabelText("Proxy Admin Email"); diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterSettings.test.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterSettings.test.tsx index 39542945c45..af2cc0beb7e 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterSettings.test.tsx @@ -143,7 +143,7 @@ describe("MCPSemanticFilterSettings", () => { await user.click(screen.getByRole("switch")); - expect(screen.getByRole("button", { name: /save settings/i })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: /save settings/i })).toBeEnabled(); }); it("should show an error alert when the mutation fails", async () => { diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterTestPanel.test.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterTestPanel.test.tsx index c35caffc4be..2362f5ead60 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterTestPanel.test.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/MCPSemanticFilterSettings/MCPSemanticFilterTestPanel.test.tsx @@ -69,7 +69,7 @@ describe("MCPSemanticFilterTestPanel", () => { it("should enable the Test Filter button when testQuery is set and filter is enabled", () => { render(); - expect(screen.getByRole("button", { name: /test filter/i })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: /test filter/i })).toBeEnabled(); }); it("should call onTest when the Test Filter button is clicked", async () => { diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/BaseSSOSettingsForm.test.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/BaseSSOSettingsForm.test.tsx index 2f9c49dfa56..8043e41a2de 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/BaseSSOSettingsForm.test.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/BaseSSOSettingsForm.test.tsx @@ -39,10 +39,8 @@ describe("BaseSSOSettingsForm", () => { fireEvent.mouseDown(providerSelect); }); - await waitFor(() => { - const googleOption = screen.getByText(/google sso/i); - fireEvent.click(googleOption); - }); + const googleOption = await screen.findByText(/google sso/i); + fireEvent.click(googleOption); await waitFor(() => { expect(screen.getByText("Google Client ID")).toBeInTheDocument(); @@ -65,10 +63,8 @@ describe("BaseSSOSettingsForm", () => { fireEvent.mouseDown(providerSelect); }); - await waitFor(() => { - const oktaOption = screen.getByText(/okta/i); - fireEvent.click(oktaOption); - }); + const oktaOption = await screen.findByText(/okta/i); + fireEvent.click(oktaOption); await waitFor(() => { expect(screen.getByText("Use Role Mappings")).toBeInTheDocument(); @@ -132,10 +128,8 @@ describe("BaseSSOSettingsForm", () => { fireEvent.mouseDown(providerSelect); }); - await waitFor(() => { - const genericOption = screen.getByText(/generic sso/i); - fireEvent.click(genericOption); - }); + const genericOption = await screen.findByText(/generic sso/i); + fireEvent.click(genericOption); await waitFor(() => { expect(screen.getByText("Use Role Mappings")).toBeInTheDocument(); @@ -167,10 +161,8 @@ describe("BaseSSOSettingsForm", () => { fireEvent.mouseDown(providerSelect); }); - await waitFor(() => { - const oktaOption = screen.getByText(/okta/i); - fireEvent.click(oktaOption); - }); + const oktaOption = await screen.findByText(/okta/i); + fireEvent.click(oktaOption); await waitFor(() => { expect(screen.getByText("Use Team Mappings")).toBeInTheDocument(); @@ -192,10 +184,8 @@ describe("BaseSSOSettingsForm", () => { fireEvent.mouseDown(providerSelect); }); - await waitFor(() => { - const genericOption = screen.getByText(/generic sso/i); - fireEvent.click(genericOption); - }); + const genericOption = await screen.findByText(/generic sso/i); + fireEvent.click(genericOption); await waitFor(() => { expect(screen.getByText("Use Team Mappings")).toBeInTheDocument(); @@ -217,10 +207,8 @@ describe("BaseSSOSettingsForm", () => { fireEvent.mouseDown(providerSelect); }); - await waitFor(() => { - const oktaOption = screen.getByText(/okta/i); - fireEvent.click(oktaOption); - }); + const oktaOption = await screen.findByText(/okta/i); + fireEvent.click(oktaOption); await waitFor(() => { expect(screen.getByText("Use Team Mappings")).toBeInTheDocument(); @@ -251,10 +239,8 @@ describe("BaseSSOSettingsForm", () => { fireEvent.mouseDown(providerSelect); }); - await waitFor(() => { - const googleOption = screen.getByText(/google sso/i); - fireEvent.click(googleOption); - }); + const googleOption = await screen.findByText(/google sso/i); + fireEvent.click(googleOption); await waitFor(() => { expect(screen.getByText("Google Client ID")).toBeInTheDocument(); diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.test.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.test.tsx index f4b7b9aadd4..8a1b9bc99ed 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.test.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/RoleMappings.test.tsx @@ -26,7 +26,7 @@ describe("RoleMappings", () => { it("should return null when roleMappings is undefined", () => { const { container } = renderWithProviders(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should display Group Claim and Default Role with correct values and display names", () => { diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.test.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.test.tsx index 1253532f269..1cdb57335ce 100644 --- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.test.tsx +++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/AddFallbacks.test.tsx @@ -189,7 +189,7 @@ describe("AddFallbacks", () => { }); const saveButton = screen.getByRole("button", { name: /save all configurations/i }); - expect(saveButton).not.toBeDisabled(); + expect(saveButton).toBeEnabled(); await user.click(saveButton); await waitFor(() => { diff --git a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.test.tsx b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.test.tsx index a397b061801..cdcb1eefadb 100644 --- a/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.test.tsx +++ b/ui/litellm-dashboard/src/components/Settings/RouterSettings/Fallbacks/Fallbacks.test.tsx @@ -125,7 +125,7 @@ describe("Fallbacks", () => { it("should not render when accessToken is null", () => { const { container } = renderWithQueryClient(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should fetch router settings on mount", async () => { diff --git a/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx b/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx index 8fd03d7340f..9b4e0527190 100644 --- a/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/TeamSSOSettings.test.tsx @@ -368,7 +368,7 @@ describe("TeamSSOSettings", () => { await userEvent.click(screen.getByRole("button", { name: /Edit Settings/i })); const permissionComboboxes = screen.getAllByRole("combobox"); const permissionCombobox = permissionComboboxes[permissionComboboxes.length - 1]; - expect(permissionCombobox).toBeDefined(); + expect(permissionCombobox).toBeInTheDocument(); await userEvent.click(permissionCombobox!); const deletePermissionOptions = await screen.findAllByText("/key/delete"); await userEvent.click(deletePermissionOptions[deletePermissionOptions.length - 1]); diff --git a/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx b/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx index 71c6aa66cf3..9375673ba10 100644 --- a/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx +++ b/ui/litellm-dashboard/src/components/TeamsPage/TeamsTable.test.tsx @@ -151,7 +151,7 @@ describe("sort contract – only backend-sortable columns are sortable", () => { it("does not make Spend / Budget sortable (the backend rejects sort_by=spend)", () => { renderTable(); - expect(screen.getByText("Spend / Budget").closest("button")).toBeNull(); + expect(screen.queryByText("Spend / Budget").closest("button")).toBeNull(); // Team and Created are the only sortable headers. expect(screen.getByText("Team").closest("button")).not.toBeNull(); expect(screen.getByText("Created").closest("button")).not.toBeNull(); diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopKeyView.test.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopKeyView.test.tsx index be13ea1a7d3..dda1b805582 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopKeyView.test.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/TopKeyView.test.tsx @@ -152,7 +152,7 @@ describe("TopKeyView", () => { const bars = container.querySelectorAll("path.recharts-rectangle"); expect(bars).toHaveLength(1); - expect(bars[0].getAttribute("fill")).toBe("var(--color-cyan-500, #06b6d4)"); + expect(bars[0]).toHaveAttribute("fill", "var(--color-cyan-500, #06b6d4)"); expect(screen.getAllByText("A Very Lon...").length).toBeGreaterThan(0); fireEvent.click(bars[0]); diff --git a/ui/litellm-dashboard/src/components/UsagePage/components/KeyModelUsageView.test.tsx b/ui/litellm-dashboard/src/components/UsagePage/components/KeyModelUsageView.test.tsx index 024226c3c03..d513d7c3a80 100644 --- a/ui/litellm-dashboard/src/components/UsagePage/components/KeyModelUsageView.test.tsx +++ b/ui/litellm-dashboard/src/components/UsagePage/components/KeyModelUsageView.test.tsx @@ -31,7 +31,7 @@ describe("KeyModelUsageView", () => { it("should return null when topModels is empty", () => { const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should display Model Usage title", () => { diff --git a/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx b/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx index 0910925a940..9ef849dbeb2 100644 --- a/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx +++ b/ui/litellm-dashboard/src/components/VirtualKeysPage/VirtualKeysTable.test.tsx @@ -339,13 +339,9 @@ it("emphasizes the active field in the Spend / Budget header so the sorted colum await user.click(await screen.findByText("Budget descending")); await waitFor(() => { - expect(screen.getByText("Budget", { selector: "[data-sort-field='max_budget']" }).className).toContain( - "font-semibold", - ); + expect(screen.getByText("Budget", { selector: "[data-sort-field='max_budget']" })).toHaveClass("font-semibold"); }); - expect(screen.getByText("Spend", { selector: "[data-sort-field='spend']" }).className).toContain( - "text-muted-foreground", - ); + expect(screen.getByText("Spend", { selector: "[data-sort-field='spend']" })).toHaveClass("text-muted-foreground"); }); it("sorts by spend ascending when 'Spend ascending' is chosen from the Spend / Budget menu", async () => { @@ -537,7 +533,7 @@ describe("refresh button", () => { const refresh = screen.getByTestId("datatable-refresh"); expect(refresh).toBeInTheDocument(); - expect(refresh).not.toBeDisabled(); + expect(refresh).toBeEnabled(); }); it("disables the refresh control while a fetch is in flight but keeps data visible", () => { diff --git a/ui/litellm-dashboard/src/components/add_model/ClassifierPromptEditor.integration.test.tsx b/ui/litellm-dashboard/src/components/add_model/ClassifierPromptEditor.integration.test.tsx index f80753bc9a8..c35457630a5 100644 --- a/ui/litellm-dashboard/src/components/add_model/ClassifierPromptEditor.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/ClassifierPromptEditor.integration.test.tsx @@ -1,4 +1,4 @@ -import { renderWithProviders, screen, waitFor } from "../../../tests/test-utils"; +import { renderWithProviders, screen } from "../../../tests/test-utils"; import userEvent from "@testing-library/user-event"; import { vi } from "vitest"; import ClassifierPromptEditor from "./ClassifierPromptEditor"; @@ -45,7 +45,7 @@ const openEditor = async ({ />, ); await userEvent.click(screen.getByRole("button", { name: /prompt/i })); - await waitFor(() => expect(screen.getByLabelText("Classifier system prompt")).toBeInTheDocument()); + expect(await screen.findByLabelText("Classifier system prompt")).toBeInTheDocument(); return onChange; }; diff --git a/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.test.tsx b/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.test.tsx index f94f3306291..27ede9159a8 100644 --- a/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/add_auto_router_tab.test.tsx @@ -455,7 +455,7 @@ describe("AddAutoRouterTab", () => { const anthropicOption = optionByLabel("Anthropic Family")!; expect(isOptionDisabled(anthropicOption)).toBe(true); - expect(anthropicOption.textContent).toContain("Checking model availability"); + expect(anthropicOption).toHaveTextContent(/Checking model availability/); // The dropdown is already open from above; polling re-reads its options in place rather than // reopening (openTemplateDropdown toggles, so a second call here would close it instead). @@ -474,7 +474,7 @@ describe("AddAutoRouterTab", () => { openTemplateDropdown(); const anthropicOption = optionByLabel("Anthropic Family")!; expect(isOptionDisabled(anthropicOption)).toBe(true); - expect(anthropicOption.textContent).toContain("Cannot verify these models are available"); + expect(anthropicOption).toHaveTextContent(/Cannot verify these models are available/); }); it("keeps group-name presets selectable when only the deployment fetch fails", async () => { @@ -496,7 +496,7 @@ describe("AddAutoRouterTab", () => { openTemplateDropdown(); await waitFor(() => { - expect(optionByLabel("Anthropic Family")!.textContent).toContain(`Missing: ${ANTHROPIC_ONLY_MODEL}`); + expect(optionByLabel("Anthropic Family")!).toHaveTextContent(new RegExp(`Missing: ${ANTHROPIC_ONLY_MODEL}`)); }); expect(isOptionDisabled(optionByLabel("Anthropic Family")!)).toBe(true); }); @@ -695,7 +695,7 @@ describe("AddAutoRouterTab", () => { await waitFor(() => { expect(isOptionDisabled(optionByLabel("Anthropic Family")!)).toBe(false); }); - expect(optionByLabel("Anthropic Family")!.textContent).toContain("Matches your deployments"); + expect(optionByLabel("Anthropic Family")!).toHaveTextContent(/Matches your deployments/); }); it("keeps detailed configuration open and prefills the admin's group names on apply", async () => { @@ -755,7 +755,7 @@ describe("AddAutoRouterTab", () => { openTemplateDropdown(); await waitFor(() => { - expect(optionByLabel("OpenAI Family")!.textContent).toContain("Missing:"); + expect(optionByLabel("OpenAI Family")!).toHaveTextContent(/Missing:/); }); expect(isOptionDisabled(optionByLabel("OpenAI Family")!)).toBe(true); }); @@ -784,7 +784,7 @@ describe("AddAutoRouterTab", () => { await waitFor(() => { expect(isOptionDisabled(optionByLabel("Anthropic Family")!)).toBe(false); }); - expect(optionByLabel("Anthropic Family")!.textContent).toContain("Matches your deployments"); + expect(optionByLabel("Anthropic Family")!).toHaveTextContent(/Matches your deployments/); }); it("prefills the expanded group names and submits them", async () => { diff --git a/ui/litellm-dashboard/src/components/add_model/auto_router_connection_test.test.tsx b/ui/litellm-dashboard/src/components/add_model/auto_router_connection_test.test.tsx index b07270b5ced..41fb773dc96 100644 --- a/ui/litellm-dashboard/src/components/add_model/auto_router_connection_test.test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/auto_router_connection_test.test.tsx @@ -44,7 +44,7 @@ describe("AutoRouterConnectionTest", () => { renderWithProviders(); await waitFor(() => expect(screen.getAllByTestId("test-status-success")).toHaveLength(3)); - expect(screen.queryByTestId("test-status-error")).toBeNull(); + expect(screen.queryByTestId("test-status-error")).not.toBeInTheDocument(); expect(screen.getByText("MEDIUM, COMPLEX")).toBeInTheDocument(); }); @@ -60,7 +60,7 @@ describe("AutoRouterConnectionTest", () => { renderWithProviders(); - await waitFor(() => expect(screen.getByTestId("test-error-message")).toBeInTheDocument()); + expect(await screen.findByTestId("test-error-message")).toBeInTheDocument(); expect(screen.getByTestId("test-error-message")).toHaveTextContent("invalid api key"); expect(screen.getByTestId("test-error-message")).not.toHaveTextContent("litellm.AuthenticationError"); expect(screen.getAllByTestId("test-status-success")).toHaveLength(2); diff --git a/ui/litellm-dashboard/src/components/add_model/litellm_model_name.test.tsx b/ui/litellm-dashboard/src/components/add_model/litellm_model_name.test.tsx index f1fd3fecb37..37eecec1f3f 100644 --- a/ui/litellm-dashboard/src/components/add_model/litellm_model_name.test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/litellm_model_name.test.tsx @@ -25,6 +25,6 @@ describe("LitellmModelNameField", () => { , ); expect(getByPlaceholderText("my-deployment")).toBeInTheDocument(); - expect(queryByPlaceholderText("gpt-3.5-turbo")).toBeNull(); + expect(queryByPlaceholderText("gpt-3.5-turbo")).not.toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx index c2b730bf46a..bf62b4873b7 100644 --- a/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/provider_specific_fields.test.tsx @@ -150,17 +150,15 @@ describe("ProviderSpecificFields", () => { , ); - await waitFor(() => { - const apiKeyLabel = screen.getByLabelText("OpenAI API Key"); - expect(apiKeyLabel).toBeInTheDocument(); + const apiKeyLabel = await screen.findByLabelText("OpenAI API Key"); + expect(apiKeyLabel).toBeInTheDocument(); - const apiBaseInput = screen.getByPlaceholderText("https://api.openai.com/v1"); - expect(apiBaseInput).toBeInTheDocument(); - expect(apiBaseInput).toHaveAttribute("type", "text"); + const apiBaseInput = screen.getByPlaceholderText("https://api.openai.com/v1"); + expect(apiBaseInput).toBeInTheDocument(); + expect(apiBaseInput).toHaveAttribute("type", "text"); - const orgInput = screen.getByPlaceholderText("[OPTIONAL] my-unique-org"); - expect(orgInput).toBeInTheDocument(); - }); + const orgInput = screen.getByPlaceholderText("[OPTIONAL] my-unique-org"); + expect(orgInput).toBeInTheDocument(); }); it("should render the provider specific fields for vLLM", async () => { @@ -173,14 +171,12 @@ describe("ProviderSpecificFields", () => { , ); - await waitFor(() => { - const apiKeyLabel = screen.getByLabelText("vLLM API Key"); - expect(apiKeyLabel).toBeInTheDocument(); + const apiKeyLabel = await screen.findByLabelText("vLLM API Key"); + expect(apiKeyLabel).toBeInTheDocument(); - const apiBaseInput = screen.getByPlaceholderText("https://..."); - expect(apiBaseInput).toBeInTheDocument(); - expect(apiBaseInput).toHaveAttribute("type", "text"); - }); + const apiBaseInput = screen.getByPlaceholderText("https://..."); + expect(apiBaseInput).toBeInTheDocument(); + expect(apiBaseInput).toHaveAttribute("type", "text"); }); it("should render the provider specific fields for Azure", async () => { @@ -193,27 +189,25 @@ describe("ProviderSpecificFields", () => { , ); - await waitFor(() => { - const apiKeyInput = screen.getByLabelText("Azure API Key"); - expect(apiKeyInput).toBeInTheDocument(); - expect(apiKeyInput).toHaveAttribute("type", "password"); - expect(apiKeyInput).toHaveAttribute("placeholder", "Enter your Azure API Key"); + const apiKeyInput = await screen.findByLabelText("Azure API Key"); + expect(apiKeyInput).toBeInTheDocument(); + expect(apiKeyInput).toHaveAttribute("type", "password"); + expect(apiKeyInput).toHaveAttribute("placeholder", "Enter your Azure API Key"); - const azureAdTokenInput = screen.getByLabelText("Azure AD Token"); - expect(azureAdTokenInput).toBeInTheDocument(); - expect(azureAdTokenInput).toHaveAttribute("type", "password"); - expect(azureAdTokenInput).toHaveAttribute("placeholder", "Enter your Azure AD Token"); + const azureAdTokenInput = screen.getByLabelText("Azure AD Token"); + expect(azureAdTokenInput).toBeInTheDocument(); + expect(azureAdTokenInput).toHaveAttribute("type", "password"); + expect(azureAdTokenInput).toHaveAttribute("placeholder", "Enter your Azure AD Token"); - const apiBaseInput = screen.getByPlaceholderText("https://..."); - expect(apiBaseInput).toBeInTheDocument(); - expect(apiBaseInput).toHaveAttribute("type", "text"); + const apiBaseInput = screen.getByPlaceholderText("https://..."); + expect(apiBaseInput).toBeInTheDocument(); + expect(apiBaseInput).toHaveAttribute("type", "text"); - const apiVersionInput = screen.getByPlaceholderText("2023-07-01-preview"); - expect(apiVersionInput).toBeInTheDocument(); + const apiVersionInput = screen.getByPlaceholderText("2023-07-01-preview"); + expect(apiVersionInput).toBeInTheDocument(); - const baseModelInput = screen.getByPlaceholderText("azure/gpt-3.5-turbo"); - expect(baseModelInput).toBeInTheDocument(); - }); + const baseModelInput = screen.getByPlaceholderText("azure/gpt-3.5-turbo"); + expect(baseModelInput).toBeInTheDocument(); }); it("sets Azure API version from the API base query parameter", async () => { diff --git a/ui/litellm-dashboard/src/components/chat/ConnectFlowBanner.test.tsx b/ui/litellm-dashboard/src/components/chat/ConnectFlowBanner.test.tsx index 4833b4ad8a4..b3cd6e229af 100644 --- a/ui/litellm-dashboard/src/components/chat/ConnectFlowBanner.test.tsx +++ b/ui/litellm-dashboard/src/components/chat/ConnectFlowBanner.test.tsx @@ -16,8 +16,8 @@ describe("ConnectFlowBanner", () => { const { container } = render(); const form = container.querySelector("form")!; - expect(form.getAttribute("method")).toBe("POST"); - expect(form.getAttribute("action")).toBe("https://gateway.example.com/authorize/complete"); + expect(form).toHaveAttribute("method", "POST"); + expect(form).toHaveAttribute("action", "https://gateway.example.com/authorize/complete"); const hidden = form.querySelector('input[name="flow"]') as HTMLInputElement; expect(hidden.value).toBe("flow-handle-123"); diff --git a/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.test.tsx b/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.test.tsx index 5fc3e75195b..e8795c36bc6 100644 --- a/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.test.tsx +++ b/ui/litellm-dashboard/src/components/chat/MCPAppsPanel.test.tsx @@ -58,8 +58,8 @@ describe("MCPAppsPanel logos", () => { renderPanel(); expect(await screen.findByText("external_logo")).toBeInTheDocument(); - expect(screen.getByAltText("external_logo logo").getAttribute("src")).toBe("https://cdn.example.com/ext.png"); - expect(screen.getByAltText("local_logo logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg"); + expect(screen.getByAltText("external_logo logo")).toHaveAttribute("src", "https://cdn.example.com/ext.png"); + expect(screen.getByAltText("local_logo logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg"); }); it("renders a colored letter avatar for servers without logo_url", async () => { @@ -83,7 +83,7 @@ describe("MCPAppsPanel logos", () => { fireEvent.click(await screen.findByText("local_logo")); expect(await screen.findByRole("heading", { name: "local_logo" })).toBeInTheDocument(); - expect(screen.getByAltText("local_logo logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg"); + expect(screen.getByAltText("local_logo logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg"); }); }); @@ -239,7 +239,7 @@ describe("MCPAppsPanel connected-app reachability (LIT-4861)", () => { expect(onChange).not.toHaveBeenCalled(); expect(screen.queryByText("revoked_srv")).not.toBeInTheDocument(); - expect(screen.getByText("Connected", { exact: false }).textContent).toBe("Connected"); + expect(screen.getByText("Connected", { exact: false })).toHaveTextContent("Connected"); }); it("does not select a server when Connect resolves in the same tick the refetch drops it", async () => { diff --git a/ui/litellm-dashboard/src/components/chat/MCPConnectPicker.test.tsx b/ui/litellm-dashboard/src/components/chat/MCPConnectPicker.test.tsx index f2912d460f0..4093688fcb9 100644 --- a/ui/litellm-dashboard/src/components/chat/MCPConnectPicker.test.tsx +++ b/ui/litellm-dashboard/src/components/chat/MCPConnectPicker.test.tsx @@ -40,8 +40,8 @@ describe("MCPConnectPicker logos", () => { render(); expect(await screen.findByText("external_logo")).toBeInTheDocument(); - expect(screen.getByAltText("external_logo logo").getAttribute("src")).toBe("https://cdn.example.com/ext.png"); - expect(screen.getByAltText("local_logo logo").getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg"); + expect(screen.getByAltText("external_logo logo")).toHaveAttribute("src", "https://cdn.example.com/ext.png"); + expect(screen.getByAltText("local_logo logo")).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg"); }); it("renders no logo at all for servers without logo_url", async () => { diff --git a/ui/litellm-dashboard/src/components/common_components/DefaultProxyAdminTag.test.tsx b/ui/litellm-dashboard/src/components/common_components/DefaultProxyAdminTag.test.tsx index e330bb2e1b9..9236a56a8b9 100644 --- a/ui/litellm-dashboard/src/components/common_components/DefaultProxyAdminTag.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/DefaultProxyAdminTag.test.tsx @@ -22,6 +22,6 @@ describe("DefaultProxyAdminTag", () => { it("should render empty text when userId is null", () => { const { container } = render(); expect(screen.queryByText("Default Proxy Admin")).not.toBeInTheDocument(); - expect(container.textContent).toBe(""); + expect(container).toHaveTextContent(""); }); }); diff --git a/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx b/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx index 465f7fcfcf0..ebcb8221b1a 100644 --- a/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/DeleteResourceModal.test.tsx @@ -118,7 +118,7 @@ describe("DeleteResourceModal", () => { const input = screen.getByPlaceholderText("DELETE"); await user.type(input, "DELETE"); const deleteButton = screen.getByRole("button", { name: /delete/i }); - expect(deleteButton).not.toBeDisabled(); + expect(deleteButton).toBeEnabled(); }); it("should reset requiredConfirmation input when modal opens", async () => { diff --git a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx index a4263e2f321..5dca1f65874 100644 --- a/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/KeyLifecycleSettings.test.tsx @@ -144,7 +144,7 @@ describe("KeyLifecycleSettings", () => { expect(screen.queryByText("Rotation Interval")).not.toBeInTheDocument(); await user.click(screen.getByRole("switch")); - await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument()); + expect(await screen.findByText("Rotation Interval")).toBeInTheDocument(); }); it("propagates a selected predefined interval", async () => { @@ -152,7 +152,7 @@ describe("KeyLifecycleSettings", () => { renderWithProviders(); await user.click(screen.getByRole("switch")); - await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument()); + expect(await screen.findByText("Rotation Interval")).toBeInTheDocument(); await user.click(screen.getByRole("combobox")); await user.click(await screen.findByText("90 days")); @@ -166,7 +166,7 @@ describe("KeyLifecycleSettings", () => { renderWithProviders(); await user.click(screen.getByRole("switch")); - await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument()); + expect(await screen.findByText("Rotation Interval")).toBeInTheDocument(); await user.click(screen.getByRole("combobox")); await user.click(await screen.findByText("Custom interval")); @@ -181,7 +181,7 @@ describe("KeyLifecycleSettings", () => { renderWithProviders(); await user.click(screen.getByRole("switch")); - await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument()); + expect(await screen.findByText("Rotation Interval")).toBeInTheDocument(); await user.click(screen.getByRole("combobox")); await user.click(await screen.findByText("Custom interval")); @@ -198,7 +198,7 @@ describe("KeyLifecycleSettings", () => { renderWithProviders(); await user.click(screen.getByRole("switch")); - await waitFor(() => expect(screen.getByText("Rotation Interval")).toBeInTheDocument()); + expect(await screen.findByText("Rotation Interval")).toBeInTheDocument(); await user.click(screen.getByRole("combobox")); await user.click(await screen.findByText("Custom interval")); diff --git a/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx b/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx index 2500551d37b..3ae24b16e7b 100644 --- a/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/NewBadge.test.tsx @@ -47,7 +47,7 @@ describe("NewBadge", () => { const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should render badge with dot when dot prop is true", () => { diff --git a/ui/litellm-dashboard/src/components/common_components/chartUtils.test.tsx b/ui/litellm-dashboard/src/components/common_components/chartUtils.test.tsx index 01a4d8373c4..bae11ff5671 100644 --- a/ui/litellm-dashboard/src/components/common_components/chartUtils.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/chartUtils.test.tsx @@ -46,7 +46,7 @@ describe("CustomTooltip", () => { label: "2024-01-15", }; const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should return null when payload is empty", () => { @@ -56,7 +56,7 @@ describe("CustomTooltip", () => { label: "2024-01-15", }; const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should display formatted category names", () => { diff --git a/ui/litellm-dashboard/src/components/common_components/routerSettingsWiring.test.tsx b/ui/litellm-dashboard/src/components/common_components/routerSettingsWiring.test.tsx index 15c52e71e8f..6bfda813eaa 100644 --- a/ui/litellm-dashboard/src/components/common_components/routerSettingsWiring.test.tsx +++ b/ui/litellm-dashboard/src/components/common_components/routerSettingsWiring.test.tsx @@ -58,8 +58,8 @@ describe("key router settings wiring, /key/info payload through to rendered outp it("should not leak a field the accordion has no control for into the editor", async () => { render(renderAccordion(KEY_INFO_ROUTER_SETTINGS)); - await waitFor(() => expect(screen.getByTestId("loadbalancing")).toBeInTheDocument()); - expect(screen.getByTestId("loadbalancing").textContent).not.toContain("tag_routing_prefix"); + expect(await screen.findByTestId("loadbalancing")).toBeInTheDocument(); + expect(screen.getByTestId("loadbalancing")).not.toHaveTextContent(/tag_routing_prefix/); }); it("should render an empty editor for a key holding only fields it cannot show", async () => { diff --git a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx index f8a6f671de0..cd37e05c13b 100644 --- a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx +++ b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.test.tsx @@ -519,6 +519,7 @@ describe("EditAutoRouterModal custom classifier prompt and fallback", () => { await user.click(await screen.findByText("Advanced: Classification Method")); expect(await screen.findByRole("button", { name: "Edit custom prompt" })).toBeInTheDocument(); + // eslint-disable-next-line jest-dom/prefer-checked -- antd sets the checked attribute without the DOM property, so toBeChecked reads false expect(screen.getByRole("radio", { name: /Route to the default model/ })).toHaveAttribute("checked"); await user.click(screen.getByRole("button", { name: /save changes/i })); diff --git a/ui/litellm-dashboard/src/components/email_settings.test.tsx b/ui/litellm-dashboard/src/components/email_settings.test.tsx index 198577e405e..691e0f251f2 100644 --- a/ui/litellm-dashboard/src/components/email_settings.test.tsx +++ b/ui/litellm-dashboard/src/components/email_settings.test.tsx @@ -101,13 +101,13 @@ describe("EmailSettings", () => { renderWithProviders(); expect(inputNamed("EMAIL_LOGO_URL")).toBeDisabled(); - expect(inputNamed("SMTP_HOST")).not.toBeDisabled(); + expect(inputNamed("SMTP_HOST")).toBeEnabled(); }); it("leaves the premium-only fields editable for premium users", () => { renderWithProviders(); - expect(inputNamed("EMAIL_LOGO_URL")).not.toBeDisabled(); + expect(inputNamed("EMAIL_LOGO_URL")).toBeEnabled(); }); it("triggers a live email health check", async () => { diff --git a/ui/litellm-dashboard/src/components/key_team_helpers/BudgetFallbacksEditor.test.tsx b/ui/litellm-dashboard/src/components/key_team_helpers/BudgetFallbacksEditor.test.tsx index 1b5603045e0..6b21421184f 100644 --- a/ui/litellm-dashboard/src/components/key_team_helpers/BudgetFallbacksEditor.test.tsx +++ b/ui/litellm-dashboard/src/components/key_team_helpers/BudgetFallbacksEditor.test.tsx @@ -9,8 +9,8 @@ describe("BudgetFallbacksEditor", () => { it("renders empty state with add button", () => { const onChange = vi.fn(); render(); - expect(screen.getByText("Add Budget Fallback")).toBeTruthy(); - expect(screen.getByText(/reroute to fallback models/)).toBeTruthy(); + expect(screen.getByText("Add Budget Fallback")).toBeInTheDocument(); + expect(screen.getByText(/reroute to fallback models/)).toBeInTheDocument(); }); it("renders existing entries from value prop", () => { @@ -22,9 +22,9 @@ describe("BudgetFallbacksEditor", () => { availableModels={MODELS} />, ); - expect(screen.getByText("IF BUDGET EXCEEDED, TRY")).toBeTruthy(); - expect(screen.getByText("Primary Model")).toBeTruthy(); - expect(screen.getByText("Fallback Models")).toBeTruthy(); + expect(screen.getByText("IF BUDGET EXCEEDED, TRY")).toBeInTheDocument(); + expect(screen.getByText("Primary Model")).toBeInTheDocument(); + expect(screen.getByText("Fallback Models")).toBeInTheDocument(); }); it("adds a new empty entry when clicking add button", async () => { @@ -33,7 +33,7 @@ describe("BudgetFallbacksEditor", () => { render(); await user.click(screen.getByText("Add Budget Fallback")); - expect(screen.getByText("Primary Model")).toBeTruthy(); + expect(screen.getByText("Primary Model")).toBeInTheDocument(); expect(onChange).toHaveBeenCalledWith({}); }); @@ -81,8 +81,8 @@ describe("BudgetFallbacksEditor", () => { expect(screen.getAllByText("Primary Model").length).toBe(1); rerender(); - expect(screen.queryByText("Primary Model")).toBeNull(); - expect(screen.getByText("Add Budget Fallback")).toBeTruthy(); + expect(screen.queryByText("Primary Model")).not.toBeInTheDocument(); + expect(screen.getByText("Add Budget Fallback")).toBeInTheDocument(); }); it("shows ordering hint when multiple fallback models are configured", () => { @@ -94,6 +94,6 @@ describe("BudgetFallbacksEditor", () => { availableModels={MODELS} />, ); - expect(screen.getByText(/first model still within its own budget/)).toBeTruthy(); + expect(screen.getByText(/first model still within its own budget/)).toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/components/leftnav.test.tsx b/ui/litellm-dashboard/src/components/leftnav.test.tsx index 8eca990261c..61b6bf8e515 100644 --- a/ui/litellm-dashboard/src/components/leftnav.test.tsx +++ b/ui/litellm-dashboard/src/components/leftnav.test.tsx @@ -456,8 +456,8 @@ describe("Sidebar (leftnav)", () => { const costOptimization = container.querySelector('a[href*="cost-optimization"]'); expect(costOptimization).not.toBeNull(); - expect(costOptimization!.textContent).toContain("Cost Optimization"); - expect(costOptimization!.textContent).toContain("Beta"); + expect(costOptimization!).toHaveTextContent(/Cost Optimization/); + expect(costOptimization!).toHaveTextContent(/Beta/); expect(container.querySelector('a[href*="projects"]')).toBeNull(); }); diff --git a/ui/litellm-dashboard/src/components/logging_settings_view.test.tsx b/ui/litellm-dashboard/src/components/logging_settings_view.test.tsx index b0a1b54bac7..b21ba396411 100644 --- a/ui/litellm-dashboard/src/components/logging_settings_view.test.tsx +++ b/ui/litellm-dashboard/src/components/logging_settings_view.test.tsx @@ -34,7 +34,7 @@ describe("LoggingSettingsView logos", () => { it("renders a letter avatar for the custom callback API, which has no bundled logo", () => { render(); - expect(screen.queryByAltText("Custom Callback API logo")).toBeNull(); + expect(screen.queryByAltText("Custom Callback API logo")).not.toBeInTheDocument(); expect(screen.getByText("C")).toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/components/model_add/CredentialModal.test.tsx b/ui/litellm-dashboard/src/components/model_add/CredentialModal.test.tsx index 6804d0cba92..c8140765479 100644 --- a/ui/litellm-dashboard/src/components/model_add/CredentialModal.test.tsx +++ b/ui/litellm-dashboard/src/components/model_add/CredentialModal.test.tsx @@ -97,7 +97,7 @@ describe("CredentialModal", () => { expect(screen.getByText("Add Credential")).toBeInTheDocument(); const nameInput = screen.getByLabelText("Credential Name:") as HTMLInputElement; expect(nameInput.value).toBe(""); - expect(nameInput.disabled).toBe(false); + expect(nameInput).toBeEnabled(); }); it("shows provider-specific fields for the selected provider", async () => { @@ -124,7 +124,7 @@ describe("CredentialModal", () => { await waitFor(() => { const nameInput = screen.getByLabelText("Credential Name:") as HTMLInputElement; expect(nameInput.value).toBe("test-credential"); - expect(nameInput.disabled).toBe(true); + expect(nameInput).toBeDisabled(); }); }); @@ -134,7 +134,7 @@ describe("CredentialModal", () => { existingCredential: { ...mockCredential, credential_name: "" }, }); - expect((screen.getByLabelText("Credential Name:") as HTMLInputElement).disabled).toBe(true); + expect(screen.getByLabelText("Credential Name:")).toBeDisabled(); }); }); }); diff --git a/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.test.tsx b/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.test.tsx index 011d0568afd..1b0194b6478 100644 --- a/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.test.tsx +++ b/ui/litellm-dashboard/src/components/model_dashboard/HealthCheckComponent.test.tsx @@ -179,7 +179,7 @@ describe("HealthCheckComponent", () => { await user.click(screen.getByTestId("datatable-select-row-id-alpha")); await user.click(screen.getByTestId("clear-health-selection")); - expect(screen.getByTestId("datatable-select-row-id-alpha")).toHaveAttribute("aria-checked", "false"); + expect(screen.getByTestId("datatable-select-row-id-alpha")).not.toBeChecked(); expect(screen.getByTestId("run-health-checks")).toHaveTextContent("Run All Checks"); }); @@ -195,7 +195,7 @@ describe("HealthCheckComponent", () => { await user.click(screen.getByTestId("pagination-next")); expect(screen.queryByTestId("clear-health-selection")).not.toBeInTheDocument(); - expect(screen.getByTestId("datatable-select-row-id-alpha")).toHaveAttribute("aria-checked", "false"); + expect(screen.getByTestId("datatable-select-row-id-alpha")).not.toBeChecked(); }); }); diff --git a/ui/litellm-dashboard/src/components/model_info_view.test.tsx b/ui/litellm-dashboard/src/components/model_info_view.test.tsx index 46bd80a0bc5..4c8b9153077 100644 --- a/ui/litellm-dashboard/src/components/model_info_view.test.tsx +++ b/ui/litellm-dashboard/src/components/model_info_view.test.tsx @@ -955,8 +955,8 @@ describe("ModelInfoView", () => { await waitFor(() => { expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o-mini", "chat"); - expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat"); }); + expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat"); expect(mockTestConnectionRequest).not.toHaveBeenCalled(); }); @@ -988,8 +988,8 @@ describe("ModelInfoView", () => { await waitFor(() => { expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o-mini", "chat"); - expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat"); }); + expect(mockTestModelGroupConnection).toHaveBeenCalledWith("test-token", "gpt-4o", "chat"); }); it("does not duplicate the default model as a test target when it is already covered by a configured tier", async () => { @@ -1128,7 +1128,7 @@ describe("ModelInfoView", () => { render(, { wrapper }); const logo = await screen.findByAltText("openai logo"); - expect(logo.getAttribute("src")).toContain("openai_small"); + expect(logo).toHaveAttribute("src", expect.stringContaining("openai_small")); }); it("renders a letter avatar instead of an img for an unknown provider slug", async () => { diff --git a/ui/litellm-dashboard/src/components/molecules/cost_optimization_feedback_banner.test.tsx b/ui/litellm-dashboard/src/components/molecules/cost_optimization_feedback_banner.test.tsx index 328c1441fbc..bad92555bd5 100644 --- a/ui/litellm-dashboard/src/components/molecules/cost_optimization_feedback_banner.test.tsx +++ b/ui/litellm-dashboard/src/components/molecules/cost_optimization_feedback_banner.test.tsx @@ -16,8 +16,8 @@ describe("CostOptimizationFeedbackBanner", () => { }); it("hides itself and persists the dismissal when the dismiss button is clicked", () => { - const { queryByText, getByLabelText } = render(); - expect(queryByText("Help shape cost optimization")).toBeInTheDocument(); + const { getByText, queryByText, getByLabelText } = render(); + expect(getByText("Help shape cost optimization")).toBeInTheDocument(); fireEvent.click(getByLabelText("Dismiss banner")); diff --git a/ui/litellm-dashboard/src/components/molecules/logo/Logo.test.tsx b/ui/litellm-dashboard/src/components/molecules/logo/Logo.test.tsx index c0b52e03a30..5e4da208f4e 100644 --- a/ui/litellm-dashboard/src/components/molecules/logo/Logo.test.tsx +++ b/ui/litellm-dashboard/src/components/molecules/logo/Logo.test.tsx @@ -10,8 +10,8 @@ describe("Logo", () => { it("renders the bundled logo untouched by the server root path for a known provider", () => { render(); const img = screen.getByRole("img", { name: "openai logo" }); - expect(img.getAttribute("src")).toBe(providerLogoMap[Providers.OpenAI]); - expect(img.getAttribute("src")).toContain("openai_small"); + expect(img).toHaveAttribute("src", providerLogoMap[Providers.OpenAI]); + expect(img).toHaveAttribute("src", expect.stringContaining("openai_small")); }); it("renders a letter avatar and no img for an unknown provider", () => { @@ -29,12 +29,12 @@ describe("Logo", () => { it("resolves a backend asset path through the server root path in src mode", () => { render(); const img = screen.getByRole("img", { name: "GitHub logo" }); - expect(img.getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg"); + expect(img).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg"); }); it("passes an external https URL through untouched in src mode", () => { render(); - expect(screen.getByRole("img").getAttribute("src")).toBe("https://cdn.example.com/logo.png"); + expect(screen.getByRole("img")).toHaveAttribute("src", "https://cdn.example.com/logo.png"); }); it("swaps to the letter avatar and warns with the failing URL on image error", () => { @@ -63,7 +63,7 @@ describe("Logo", () => { rerender(); const img = screen.getByRole("img", { name: "Agent logo" }); - expect(img.getAttribute("src")).toBe("/litellm/ui/assets/logos/github.svg"); + expect(img).toHaveAttribute("src", "/litellm/ui/assets/logos/github.svg"); rerender(); expect(screen.queryByRole("img")).not.toBeInTheDocument(); diff --git a/ui/litellm-dashboard/src/components/navbar.test.tsx b/ui/litellm-dashboard/src/components/navbar.test.tsx index 72c15990f20..e3d0e4f0b38 100644 --- a/ui/litellm-dashboard/src/components/navbar.test.tsx +++ b/ui/litellm-dashboard/src/components/navbar.test.tsx @@ -96,7 +96,7 @@ vi.mock("./Navbar/CommunityEngagementButtons/CommunityEngagementButtons", () => let mockUseThemeImpl = () => ({ logoUrl: null as string | null }); let mockUseHealthReadinessDetailsImpl = () => ({ data: null as any }); let mockGetLocalStorageItemImpl = (key: string) => null as string | null; -let mockUseAuthorizedImpl = () => ({ +const mockUseAuthorizedImpl = () => ({ userId: "test-user", userEmail: "test@example.com", userRole: "Admin", diff --git a/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx b/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx index 8609bb1f82a..4f3cd4455a1 100644 --- a/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx +++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.test.tsx @@ -611,7 +611,7 @@ describe("CreateKey", () => { }); await waitFor(() => { - expect(screen.getByTestId("org-dropdown")).not.toBeDisabled(); + expect(screen.getByTestId("org-dropdown")).toBeEnabled(); }); }); diff --git a/ui/litellm-dashboard/src/components/organization/organization_view.test.tsx b/ui/litellm-dashboard/src/components/organization/organization_view.test.tsx index ec7baecad2d..4d96fc84ca9 100644 --- a/ui/litellm-dashboard/src/components/organization/organization_view.test.tsx +++ b/ui/litellm-dashboard/src/components/organization/organization_view.test.tsx @@ -124,9 +124,8 @@ test("renders organization view after loading data", async () => { />, ); - await waitFor(() => { - expect(findAllByText("Acme Corp")).toBeTruthy(); - }); + const [orgName] = await findAllByText("Acme Corp"); + expect(orgName).toBeInTheDocument(); }); test("should display empty state when organization has no members", async () => { diff --git a/ui/litellm-dashboard/src/components/per_user_usage.test.tsx b/ui/litellm-dashboard/src/components/per_user_usage.test.tsx index 443ae66af8f..9cd199d786c 100644 --- a/ui/litellm-dashboard/src/components/per_user_usage.test.tsx +++ b/ui/litellm-dashboard/src/components/per_user_usage.test.tsx @@ -117,8 +117,8 @@ describe("PerUserUsage", () => { const xPositions = new Set(rectangles.map((rect) => rect.getAttribute("d")?.match(/^M\s*([\d.]+)/)?.[1])); expect(xPositions.size).toBe(3); - expect(chart.textContent).toContain("curl/8.0"); - expect(chart.textContent).toContain("Unknown"); + expect(chart).toHaveTextContent("curl/8.0"); + expect(chart).toHaveTextContent("Unknown"); for (const bucket of [ "1-9 requests", "10-99 requests", @@ -127,7 +127,7 @@ describe("PerUserUsage", () => { "10K-99.9K requests", "100K+ requests", ]) { - expect(chart.textContent).toContain(bucket); + expect(chart).toHaveTextContent(bucket); } const tickTexts = Array.from(chart.querySelectorAll(".recharts-cartesian-axis-tick-value")).map( diff --git a/ui/litellm-dashboard/src/components/settings.test.tsx b/ui/litellm-dashboard/src/components/settings.test.tsx index 62efa1dc372..dd45521ab4f 100644 --- a/ui/litellm-dashboard/src/components/settings.test.tsx +++ b/ui/litellm-dashboard/src/components/settings.test.tsx @@ -345,7 +345,7 @@ describe("CallbackSelector logos", () => { expect(await screen.findByAltText("Langfuse logo")).toHaveAttribute("src", "/ui/assets/logos/langfuse.png"); expect(screen.getByAltText("Hosted logo")).toHaveAttribute("src", "https://logos.example.com/hosted.png"); - expect(screen.queryByAltText("NoLogo logo")).toBeNull(); + expect(screen.queryByAltText("NoLogo logo")).not.toBeInTheDocument(); expect(screen.getByText("N")).toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx b/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx index 3afdd2849ae..58a0cd94997 100644 --- a/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/DataTable/DataTable.test.tsx @@ -343,7 +343,7 @@ describe("DataTable loading", () => { it("renders skeleton rows while loading and real rows once loaded", () => { const { rerender } = render(); expect(screen.getAllByTestId("skeleton-row").length).toBeGreaterThan(0); - expect(screen.queryByTestId("name-cell")).toBeNull(); + expect(screen.queryByTestId("name-cell")).not.toBeInTheDocument(); rerender(); expect(screen.queryAllByTestId("skeleton-row")).toHaveLength(0); @@ -462,7 +462,7 @@ describe("DataTable column visibility", () => { await user.click(screen.getByTestId("view-options-trigger")); expect(await screen.findByTestId("view-option-email")).toBeInTheDocument(); - expect(screen.queryByTestId("view-option-name")).toBeNull(); + expect(screen.queryByTestId("view-option-name")).not.toBeInTheDocument(); }); }); @@ -615,7 +615,7 @@ describe("DataTable layout", () => { const { container } = render(); expect(container.querySelector("thead")?.className).toContain("sticky"); const scroller = container.querySelector('[data-slot="table-container"]')?.parentElement as HTMLElement; - expect(scroller.style.maxHeight).toBe("240px"); + expect(scroller).toHaveStyle({ maxHeight: "240px" }); }); it("caps fillHeight at the parent's height instead of stretching to it, so a short table stays short", () => { @@ -634,7 +634,7 @@ describe("DataTable layout", () => { expect(frame.className).toContain("flex-col"); expect(scroller.className).toContain("min-h-0"); expect(scroller.className).toContain("overflow-auto"); - expect(scroller.style.maxHeight).toBe(""); + expect(scroller).toHaveStyle({ maxHeight: "" }); // Without this the Table primitive's own overflow container captures the sticky header. expect(scroller.className).toContain("[&_[data-slot=table-container]]:overflow-visible"); @@ -650,7 +650,7 @@ describe("DataTable layout", () => { expect(scroller.className).toContain("overflow-x-auto"); expect(scroller.className).not.toContain("min-h-0"); - expect(scroller.style.maxHeight).toBe(""); + expect(scroller).toHaveStyle({ maxHeight: "" }); expect((scroller.parentElement as HTMLElement).className).not.toContain("flex-col"); expect(container.querySelector("thead")?.className).not.toContain("sticky"); expect(container.querySelector("thead")?.className).not.toContain("bg-background"); diff --git a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableFilterDrawer.test.tsx b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableFilterDrawer.test.tsx index 0770c17cba6..c6a8049de55 100644 --- a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableFilterDrawer.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableFilterDrawer.test.tsx @@ -68,7 +68,7 @@ describe("DataTableFilterDrawer", () => { await user.type(await screen.findByTestId("draft-name"), "Bob"); expect(names()).toEqual(["Alice", "Bob", "Carol"]); - expect(screen.queryByTestId("filter-chip-name")).toBeNull(); + expect(screen.queryByTestId("filter-chip-name")).not.toBeInTheDocument(); await user.click(screen.getByTestId("filter-drawer-apply")); expect(names()).toEqual(["Bob"]); @@ -92,7 +92,7 @@ describe("DataTableFilterDrawer", () => { await user.click(await screen.findByTestId("filter-drawer-reset")); expect(names()).toEqual(["Alice", "Bob", "Carol"]); - expect(screen.queryByTestId("filter-chip-name")).toBeNull(); + expect(screen.queryByTestId("filter-chip-name")).not.toBeInTheDocument(); expect(screen.getByTestId("draft-name")).toHaveValue(""); }); }); diff --git a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx index a6164307a78..70403ba2efe 100644 --- a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableSortHeader.test.tsx @@ -64,7 +64,7 @@ function SortHeaderHarness({ variant, canSort = true, onSortingChange }: Harness describe("DataTableSortHeader", () => { it("renders a plain label and no button when the column cannot sort", () => { render(); - expect(screen.queryByTestId("sort-header-name")).toBeNull(); + expect(screen.queryByTestId("sort-header-name")).not.toBeInTheDocument(); expect(screen.getByText("Name")).toBeInTheDocument(); }); diff --git a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableToolbar.test.tsx b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableToolbar.test.tsx index 8571b13e4d8..c6181cb90dc 100644 --- a/ui/litellm-dashboard/src/components/shared/DataTable/DataTableToolbar.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/DataTable/DataTableToolbar.test.tsx @@ -66,7 +66,7 @@ describe("DataTableToolbar", () => { const user = userEvent.setup(); render(); await user.click(screen.getByTestId("filter-chip-remove-name")); - expect(screen.queryByTestId("filter-chip-name")).toBeNull(); + expect(screen.queryByTestId("filter-chip-name")).not.toBeInTheDocument(); expect(names()).toEqual(["Alice", "Bob"]); }); @@ -74,7 +74,7 @@ describe("DataTableToolbar", () => { const user = userEvent.setup(); render(); await user.click(screen.getByTestId("datatable-clear-filters")); - expect(screen.queryByTestId("filter-chip-name")).toBeNull(); + expect(screen.queryByTestId("filter-chip-name")).not.toBeInTheDocument(); expect(names()).toEqual(["Alice", "Bob"]); }); diff --git a/ui/litellm-dashboard/src/components/shared/charts/area_chart.test.tsx b/ui/litellm-dashboard/src/components/shared/charts/area_chart.test.tsx index f3ef72392b0..6e4ab14be33 100644 --- a/ui/litellm-dashboard/src/components/shared/charts/area_chart.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/charts/area_chart.test.tsx @@ -23,7 +23,7 @@ describe("AreaChart", () => { it("renders the No data placeholder instead of a chart when data is empty", () => { const { container, getByText } = render(); - expect(getByText("No data")).toBeTruthy(); + expect(getByText("No data")).toBeInTheDocument(); expect(container.querySelector('[data-slot="chart"]')).toBeNull(); }); @@ -37,7 +37,7 @@ describe("AreaChart", () => { const areas = Array.from(container.querySelectorAll("path.recharts-area-area")); expect(areas).toHaveLength(2); for (const area of areas) { - expect(area.getAttribute("fill")).toMatch(/^url\(#fill-/); + expect(area).toHaveAttribute("fill", expect.stringMatching(/^url\(#fill-/)); } }); diff --git a/ui/litellm-dashboard/src/components/shared/charts/bar_chart.test.tsx b/ui/litellm-dashboard/src/components/shared/charts/bar_chart.test.tsx index cb0d5c603a4..a322eeb3ad0 100644 --- a/ui/litellm-dashboard/src/components/shared/charts/bar_chart.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/charts/bar_chart.test.tsx @@ -23,7 +23,7 @@ describe("BarChart", () => { it("renders the No data placeholder instead of a chart when data is empty", () => { const { container, getByText } = render(); - expect(getByText("No data")).toBeTruthy(); + expect(getByText("No data")).toBeInTheDocument(); expect(container.querySelector('[data-slot="chart"]')).toBeNull(); }); diff --git a/ui/litellm-dashboard/src/components/shared/charts/chart_tooltip.test.tsx b/ui/litellm-dashboard/src/components/shared/charts/chart_tooltip.test.tsx index 7afc7532760..bb0fa985c42 100644 --- a/ui/litellm-dashboard/src/components/shared/charts/chart_tooltip.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/charts/chart_tooltip.test.tsx @@ -29,10 +29,10 @@ describe("CustomTooltip", () => { const inactive = render( , ); - expect(inactive.container.firstChild).toBeNull(); + expect(inactive.container).toBeEmptyDOMElement(); const empty = render(); - expect(empty.container.firstChild).toBeNull(); + expect(empty.container).toBeEmptyDOMElement(); }); it("renders the label and title-cased category names without the metrics prefix", () => { @@ -82,7 +82,7 @@ describe("ValueTooltip", () => { it("returns null when not active", () => { const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("renders label, series name, and locale-formatted value by default", () => { diff --git a/ui/litellm-dashboard/src/components/shared/form/FormField.test.tsx b/ui/litellm-dashboard/src/components/shared/form/FormField.test.tsx index af9122e2bd5..3b37638b0bc 100644 --- a/ui/litellm-dashboard/src/components/shared/form/FormField.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/form/FormField.test.tsx @@ -101,7 +101,7 @@ describe("FormField", () => { const control = await screen.findByLabelText("Team Name"); await waitFor(() => expect(control).toHaveAttribute("aria-invalid", "true")); - expect(control.getAttribute("aria-describedby")).toBe(screen.getByRole("alert").id); + expect(control).toHaveAttribute("aria-describedby", screen.getByRole("alert").id); }); it("leaves a valid control free of aria-invalid", () => { diff --git a/ui/litellm-dashboard/src/components/shared/table_cells/id_cell.test.tsx b/ui/litellm-dashboard/src/components/shared/table_cells/id_cell.test.tsx index 1a87f17d50b..e02cbdf941c 100644 --- a/ui/litellm-dashboard/src/components/shared/table_cells/id_cell.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/table_cells/id_cell.test.tsx @@ -26,22 +26,22 @@ describe("IdCell", () => { render(); const el = screen.getByText("sk-1234567890abcdef"); expect(el.tagName).toBe("SPAN"); - expect(el.className).toContain("bg-blue-50"); - expect(el.className).toContain("font-mono"); - expect(el.className).toContain("max-w-[15ch]"); - expect(el.className).toContain("truncate"); + expect(el).toHaveClass("bg-blue-50"); + expect(el).toHaveClass("font-mono"); + expect(el).toHaveClass("max-w-[15ch]"); + expect(el).toHaveClass("truncate"); }); it("renders plain mono text without pill styling for the plain variant", () => { render(); const el = screen.getByText("req-123"); - expect(el.className).toContain("font-mono"); - expect(el.className).not.toContain("bg-blue-50"); + expect(el).toHaveClass("font-mono"); + expect(el).not.toHaveClass("bg-blue-50"); }); it("does not truncate when truncate is false", () => { render(); - expect(screen.getByText("audit-object-id").className).not.toContain("truncate"); + expect(screen.getByText("audit-object-id")).not.toHaveClass("truncate"); }); it("becomes a button that fires onClick with the id value", async () => { diff --git a/ui/litellm-dashboard/src/components/shared/table_cells/identity_cell.test.tsx b/ui/litellm-dashboard/src/components/shared/table_cells/identity_cell.test.tsx index 9a91e163baf..1122eede522 100644 --- a/ui/litellm-dashboard/src/components/shared/table_cells/identity_cell.test.tsx +++ b/ui/litellm-dashboard/src/components/shared/table_cells/identity_cell.test.tsx @@ -36,8 +36,8 @@ describe("IdentityCell", () => { const button = screen.getByRole("button"); expect(button.querySelector(".lucide-chevron-right")).not.toBeNull(); // The clickable area must read as clickable: a hover background and a pointer cursor. - expect(button.className).toContain("hover:bg-muted"); - expect(button.className).toContain("cursor-pointer"); + expect(button).toHaveClass("hover:bg-muted"); + expect(button).toHaveClass("cursor-pointer"); await user.click(button); expect(onClick).toHaveBeenCalledTimes(1); }); @@ -48,7 +48,7 @@ describe("IdentityCell", () => { const link = screen.getByRole("link", { name: /routing-qa-key-alpha/ }); expect(link).toHaveAttribute("href", "/api-keys?key=abc123"); expect(link.querySelector(".lucide-chevron-right")).not.toBeNull(); - expect(link.className).toContain("hover:bg-muted"); + expect(link).toHaveClass("hover:bg-muted"); await user.click(link); expect(routerPush).toHaveBeenCalledWith("/api-keys?key=abc123"); }); diff --git a/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx b/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx index f998d7d3ecf..83c541afd15 100644 --- a/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx @@ -135,7 +135,7 @@ describe("LoggingSettings", () => { renderWithProviders(); expect(screen.getByText("Custom Callback API Configuration")).toBeInTheDocument(); - expect(screen.queryByAltText("Custom Callback API logo")).toBeNull(); + expect(screen.queryByAltText("Custom Callback API logo")).not.toBeInTheDocument(); expect(screen.getByText("C")).toBeInTheDocument(); }); diff --git a/ui/litellm-dashboard/src/components/team/TeamInfo.test.tsx b/ui/litellm-dashboard/src/components/team/TeamInfo.test.tsx index 22481eaa4b2..1d6c46dc0c9 100644 --- a/ui/litellm-dashboard/src/components/team/TeamInfo.test.tsx +++ b/ui/litellm-dashboard/src/components/team/TeamInfo.test.tsx @@ -816,7 +816,7 @@ describe("TeamInfoView", () => { const secretField = await screen.findByPlaceholderText( '{"namespace": "admin", "mount": "secret", "path_prefix": "litellm"}', ); - expect(secretField).not.toBeDisabled(); + expect(secretField).toBeEnabled(); }); it("should add team member when form is submitted", async () => { diff --git a/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.test.tsx b/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.test.tsx index f71b2a05f3f..2cefe33eb8d 100644 --- a/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.test.tsx +++ b/ui/litellm-dashboard/src/components/team/TeamVirtualKeysTable.test.tsx @@ -212,7 +212,7 @@ describe("TeamVirtualKeysTable", () => { renderWithProviders(); - await waitFor(() => expect(screen.getByTestId("sort-header-created_at")).toBeInTheDocument()); + expect(await screen.findByTestId("sort-header-created_at")).toBeInTheDocument(); await user.click(screen.getByTestId("sort-header-created_at")); await waitFor(() => diff --git a/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx b/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx index b81495e68e8..cc876758f74 100644 --- a/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx +++ b/ui/litellm-dashboard/src/components/templates/KeyInfoHeader.test.tsx @@ -161,7 +161,7 @@ describe("KeyInfoHeader", () => { it("should not disable Regenerate button by default", () => { render(); - expect(screen.getByRole("button", { name: /regenerate key/i })).not.toBeDisabled(); + expect(screen.getByRole("button", { name: /regenerate key/i })).toBeEnabled(); }); }); diff --git a/ui/litellm-dashboard/src/components/user_agent_activity.test.tsx b/ui/litellm-dashboard/src/components/user_agent_activity.test.tsx index 07a03f4addf..79bb63da31a 100644 --- a/ui/litellm-dashboard/src/components/user_agent_activity.test.tsx +++ b/ui/litellm-dashboard/src/components/user_agent_activity.test.tsx @@ -206,9 +206,9 @@ describe("UserAgentActivity", () => { const xPositions = new Set(rectangles.map((rect) => rect.getAttribute("d")?.match(/^M\s*([\d.]+)/)?.[1])); expect(xPositions.size).toBe(1); - expect(chart.textContent).toContain("Chrome/1.0"); - expect(chart.textContent).toContain("Firefox/2.0"); - expect(chart.textContent).toContain(firstBucketLabel); + expect(chart).toHaveTextContent(/Chrome\/1\.0/); + expect(chart).toHaveTextContent(/Firefox\/2\.0/); + expect(chart).toHaveTextContent(new RegExp(firstBucketLabel)); const tickTexts = Array.from(chart.querySelectorAll(".recharts-cartesian-axis-tick-value")).map( (tick) => tick.textContent ?? "", diff --git a/ui/litellm-dashboard/src/components/vector_store_management/VectorStoreSelector.test.tsx b/ui/litellm-dashboard/src/components/vector_store_management/VectorStoreSelector.test.tsx index 07468abc582..52c51a8ecc4 100644 --- a/ui/litellm-dashboard/src/components/vector_store_management/VectorStoreSelector.test.tsx +++ b/ui/litellm-dashboard/src/components/vector_store_management/VectorStoreSelector.test.tsx @@ -307,21 +307,21 @@ describe("VectorStoreSelector", () => { renderComponent({ value: ["store-1", "store-2"] }); await waitForDataFetch(); - expect(getSelectElement().getAttribute("data-value")).toBe(JSON.stringify(["store-1", "store-2"])); + expect(getSelectElement()).toHaveAttribute("data-value", JSON.stringify(["store-1", "store-2"])); }); it("should handle empty value array", async () => { renderComponent({ value: [] }); await waitForDataFetch(); - expect(getSelectElement().getAttribute("data-value")).toBe(JSON.stringify([])); + expect(getSelectElement()).toHaveAttribute("data-value", JSON.stringify([])); }); it("should handle undefined value", async () => { renderComponent({ value: undefined }); await waitForDataFetch(); - expect(getSelectElement().getAttribute("data-value")).toBeNull(); + expect(getSelectElement()).not.toHaveAttribute("data-value"); }); }); diff --git a/ui/litellm-dashboard/src/components/view_logs/AuditLogsTable.test.tsx b/ui/litellm-dashboard/src/components/view_logs/AuditLogsTable.test.tsx index dbb0a39e2ee..8bc771ee298 100644 --- a/ui/litellm-dashboard/src/components/view_logs/AuditLogsTable.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/AuditLogsTable.test.tsx @@ -95,7 +95,7 @@ describe("AuditLogsTable", () => { renderTable({ isLoading: true, data: [] }); expect(screen.getAllByTestId("skeleton-row").length).toBeGreaterThan(0); - expect(screen.queryByText("No audit logs yet")).toBeNull(); + expect(screen.queryByText("No audit logs yet")).not.toBeInTheDocument(); }); it("uses a distinct empty state for unfiltered vs filtered-empty results", () => { diff --git a/ui/litellm-dashboard/src/components/view_logs/ConfigInfoMessage.test.tsx b/ui/litellm-dashboard/src/components/view_logs/ConfigInfoMessage.test.tsx index ad9b724ba80..2e93b10e3ae 100644 --- a/ui/litellm-dashboard/src/components/view_logs/ConfigInfoMessage.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/ConfigInfoMessage.test.tsx @@ -10,7 +10,7 @@ describe("ConfigInfoMessage", () => { it("should render nothing when show is false", () => { const { container } = render(); - expect(container.innerHTML).toBe(""); + expect(container).toBeEmptyDOMElement(); }); it("should display the YAML config snippet", () => { diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/CollapsibleMessage.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/CollapsibleMessage.test.tsx index 3aa8d21c31c..377615d3cb8 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/CollapsibleMessage.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/CollapsibleMessage.test.tsx @@ -7,12 +7,12 @@ import { CollapsibleMessage } from "./CollapsibleMessage"; describe("CollapsibleMessage", () => { it("should return null when content is empty", () => { const { container } = render(); - expect(container.innerHTML).toBe(""); + expect(container).toBeEmptyDOMElement(); }); it("should return null when content is undefined", () => { const { container } = render(); - expect(container.innerHTML).toBe(""); + expect(container).toBeEmptyDOMElement(); }); it("should render the label and char count", () => { diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/HistoryTree.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/HistoryTree.test.tsx index 0726a9f4b82..07796de6927 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/HistoryTree.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/HistoryTree.test.tsx @@ -8,7 +8,7 @@ import { ParsedMessage } from "./prettyMessagesTypes"; describe("HistoryTree", () => { it("should return null when messages array is empty", () => { const { container } = render(); - expect(container.innerHTML).toBe(""); + expect(container).toBeEmptyDOMElement(); }); it('should render message count with plural "messages" for multiple messages', () => { diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/InputCard.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/InputCard.test.tsx index 5bf97b16233..df9d00a05d6 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/InputCard.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/InputCard.test.tsx @@ -42,7 +42,7 @@ describe("InputCard", () => { it("should return null when messages array is empty", () => { const { container } = render(); - expect(container.firstChild).toBeNull(); + expect(container).toBeEmptyDOMElement(); }); it("should display system message when present", () => { diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.test.tsx index b913f7c8d21..b96e5279722 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/LogDetailsDrawer.test.tsx @@ -153,7 +153,7 @@ describe("LogDetailsDrawer session sidebar auto-router icon", () => { it("marks the auto-routed entry with the router icon and leaves a direct call on the default icon", async () => { renderRoutedSession(); - await waitFor(() => expect(screen.queryByText("claude-opus-4-8")).not.toBeNull()); + expect(await screen.findByText("claude-opus-4-8")).toBeInTheDocument(); const routedRow = rowFor("claude-opus-4-8"); const directRow = rowFor("claude-haiku-4-5"); diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleMessageBlock.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleMessageBlock.test.tsx index c4be05f0e9c..ecd2e0fdf2a 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleMessageBlock.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleMessageBlock.test.tsx @@ -12,12 +12,12 @@ describe("SimpleMessageBlock", () => { it("should return null when content is empty and no tool calls", () => { const { container } = render(); - expect(container.innerHTML).toBe(""); + expect(container).toBeEmptyDOMElement(); }); it('should return null when content is "null" string and no tool calls', () => { const { container } = render(); - expect(container.innerHTML).toBe(""); + expect(container).toBeEmptyDOMElement(); }); it("should render tool calls when present", () => { diff --git a/ui/litellm-dashboard/src/components/view_logs/RequestLogsPanel.test.tsx b/ui/litellm-dashboard/src/components/view_logs/RequestLogsPanel.test.tsx index 852f146c786..9e2abec4716 100644 --- a/ui/litellm-dashboard/src/components/view_logs/RequestLogsPanel.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/RequestLogsPanel.test.tsx @@ -210,15 +210,16 @@ describe("RequestLogsPanel", () => { await user.click(screen.getByRole("button", { name: /Last 24 Hours/i })); await user.click(await screen.findByRole("button", { name: "Last 15 Minutes" })); - await waitFor(() => { + const windowSeconds = () => { const call = lastCall(); if (!call) throw new Error("no call"); - const diff = moment + return moment .utc(call.end_date, "YYYY-MM-DD HH:mm:ss") .diff(moment.utc(call.start_date, "YYYY-MM-DD HH:mm:ss"), "seconds"); - expect(diff).toBeGreaterThanOrEqual(15 * 60); - expect(diff).toBeLessThanOrEqual(16 * 60); - }); + }; + + await waitFor(() => expect(windowSeconds()).toBeGreaterThanOrEqual(15 * 60)); + expect(windowSeconds()).toBeLessThanOrEqual(16 * 60); }); it("restores the default 24 hour window when filters are reset", async () => { @@ -228,7 +229,7 @@ describe("RequestLogsPanel", () => { await waitFor(() => expect(uiSpendLogsCall).toHaveBeenCalled()); await user.click(screen.getByRole("button", { name: /Last 24 Hours/i })); await user.click(await screen.findByRole("button", { name: "Last 15 Minutes" })); - await waitFor(() => expect(screen.getByRole("button", { name: /Last 15 Minutes/i })).toBeInTheDocument()); + expect(await screen.findByRole("button", { name: /Last 15 Minutes/i })).toBeInTheDocument(); await user.click(screen.getByRole("button", { name: "Reset Filters" })); @@ -262,8 +263,8 @@ describe("RequestLogsPanel", () => { expect(historyModes()).toEqual(["push"]); await waitFor(() => { expect(drawer()).toHaveTextContent("open"); - expect(drawer()).toHaveAttribute("data-log-id", "req-1"); }); + expect(drawer()).toHaveAttribute("data-log-id", "req-1"); }); it("opens the drawer on load when ?log_id= matches a log in the loaded page", async () => { @@ -272,8 +273,8 @@ describe("RequestLogsPanel", () => { await waitFor(() => { expect(drawer()).toHaveTextContent("open"); - expect(drawer()).toHaveAttribute("data-log-id", "req-2"); }); + expect(drawer()).toHaveAttribute("data-log-id", "req-2"); }); it("fetches the log by request_id and opens the drawer when it is not in the loaded page", async () => { @@ -286,8 +287,8 @@ describe("RequestLogsPanel", () => { await waitFor(() => { expect(drawer()).toHaveTextContent("open"); - expect(drawer()).toHaveAttribute("data-log-id", "req-old"); }); + expect(drawer()).toHaveAttribute("data-log-id", "req-old"); const byIdCall = vi .mocked(uiSpendLogsCall) @@ -344,8 +345,8 @@ describe("RequestLogsPanel", () => { expect(historyModes()).toEqual(["push"]); await waitFor(() => { expect(drawer()).toHaveTextContent("open"); - expect(drawer()).toHaveAttribute("data-session-id", "sess-solo"); }); + expect(drawer()).toHaveAttribute("data-session-id", "sess-solo"); }); it("clicking a log row clears a lingering ?session_id= so the drawer shows the clicked log", async () => { @@ -366,8 +367,8 @@ describe("RequestLogsPanel", () => { expect(urlParams().get("session_id")).toBeNull(); await waitFor(() => { expect(drawer()).toHaveAttribute("data-log-id", "req-b"); - expect(drawer()).toHaveAttribute("data-session-id", ""); }); + expect(drawer()).toHaveAttribute("data-session-id", ""); }); it("closing a drawer opened via a session id clears both params", async () => { @@ -394,9 +395,9 @@ describe("RequestLogsPanel", () => { await waitFor(() => { expect(drawer()).toHaveTextContent("open"); - expect(drawer()).toHaveAttribute("data-log-id", "req-llm"); - expect(drawer()).toHaveAttribute("data-session-id", "sess-1"); }); + expect(drawer()).toHaveAttribute("data-session-id", "sess-1"); + expect(drawer()).toHaveAttribute("data-log-id", "req-llm"); }); it("clicking a multi-call session's row writes ?session_id= alongside ?log_id=", async () => { @@ -442,7 +443,7 @@ describe("RequestLogsPanel", () => { await user.click(screen.getByRole("button", { name: "Stop" })); - expect(screen.queryByText("Auto-refreshing every 15 seconds")).toBeNull(); + expect(screen.queryByText("Auto-refreshing every 15 seconds")).not.toBeInTheDocument(); }); }); }); diff --git a/ui/litellm-dashboard/src/components/view_logs/RequestLogsTableColumns.test.tsx b/ui/litellm-dashboard/src/components/view_logs/RequestLogsTableColumns.test.tsx index 2fdc8455ca1..3d0ea03c5d5 100644 --- a/ui/litellm-dashboard/src/components/view_logs/RequestLogsTableColumns.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/RequestLogsTableColumns.test.tsx @@ -103,7 +103,7 @@ describe("sortable headers", () => { expect(screen.getByTestId(`sort-trigger-${field}`)).toBeInTheDocument(); } for (const field of ["request_id", "session_id", "status", "type", "end_user"]) { - expect(screen.queryByTestId(`sort-trigger-${field}`)).toBeNull(); + expect(screen.queryByTestId(`sort-trigger-${field}`)).not.toBeInTheDocument(); } }); }); diff --git a/ui/litellm-dashboard/src/contexts/PluginModeContext.test.tsx b/ui/litellm-dashboard/src/contexts/PluginModeContext.test.tsx index 96576269fbe..f0af7313a2c 100644 --- a/ui/litellm-dashboard/src/contexts/PluginModeContext.test.tsx +++ b/ui/litellm-dashboard/src/contexts/PluginModeContext.test.tsx @@ -39,15 +39,15 @@ describe("PluginModeProvider effectiveMode fallback", () => { renderWithPlugins([]); await waitFor(() => expect(getMock).toHaveBeenCalled()); - await waitFor(() => expect(screen.getByTestId("mode").textContent).toBe("ai-gateway")); - expect(screen.getByTestId("active").textContent).toBe("none"); + await waitFor(() => expect(screen.getByTestId("mode")).toHaveTextContent("ai-gateway")); + expect(screen.getByTestId("active")).toHaveTextContent("none"); }); it("keeps the stored mode when it is still registered", async () => { renderWithPlugins([{ name: "my-plugin", display_name: "My Plugin", url: "https://p.example.com" }]); - await waitFor(() => expect(screen.getByTestId("active").textContent).toBe("my-plugin")); - expect(screen.getByTestId("mode").textContent).toBe("my-plugin"); + await waitFor(() => expect(screen.getByTestId("active")).toHaveTextContent("my-plugin")); + expect(screen.getByTestId("mode")).toHaveTextContent("my-plugin"); }); it("falls back to ai-gateway when the plugins fetch fails, never stranding the user", async () => { @@ -59,6 +59,6 @@ describe("PluginModeProvider effectiveMode fallback", () => { ); await waitFor(() => expect(getMock).toHaveBeenCalled()); - await waitFor(() => expect(screen.getByTestId("mode").textContent).toBe("ai-gateway")); + await waitFor(() => expect(screen.getByTestId("mode")).toHaveTextContent("ai-gateway")); }); }); diff --git a/ui/litellm-dashboard/src/utils/dataUtils.test.ts b/ui/litellm-dashboard/src/utils/dataUtils.test.ts index 14eba8a7edd..f9e2be81163 100644 --- a/ui/litellm-dashboard/src/utils/dataUtils.test.ts +++ b/ui/litellm-dashboard/src/utils/dataUtils.test.ts @@ -225,9 +225,11 @@ describe("dataUtils", () => { await copyToClipboard("test text"); expect(mockTextArea.value).toBe("test text"); + /* eslint-disable jest-dom/prefer-to-have-style -- the subject is a plain mock object, not a DOM node, so toHaveStyle cannot read it */ expect(mockTextArea.style.position).toBe("fixed"); expect(mockTextArea.style.left).toBe("-999999px"); expect(mockTextArea.style.top).toBe("-999999px"); + /* eslint-enable jest-dom/prefer-to-have-style */ expect(mockTextArea.setAttribute).toHaveBeenCalledWith("readonly", ""); expect(mockTextArea.focus).toHaveBeenCalled(); expect(mockTextArea.select).toHaveBeenCalled();