diff --git a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/ModelRetrySettingsTab.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/ModelRetrySettingsTab.test.tsx index 5b756a833d..6f89a41034 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/ModelRetrySettingsTab.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/models-and-endpoints/components/ModelRetrySettingsTab.test.tsx @@ -8,9 +8,17 @@ import ModelRetrySettingsTab from "./ModelRetrySettingsTab"; // directly so the component can be tested in isolation. vi.mock("@tremor/react", async (importOriginal) => { const actual = await importOriginal(); + // Re-apply the global Button/Tooltip overrides from tests/setupTests.ts. A file-level + // vi.mock fully replaces the setup-level mock, so without this the real Tremor Button + // leaks through and its useTooltip(300) schedules a native setTimeout that can fire + // post-teardown -> "window is not defined". return { ...actual, TabPanel: ({ children }: { children: React.ReactNode }) => React.createElement("div", null, children), + Button: React.forwardRef(({ children, ...props }, ref) => + React.createElement("button", { ...props, ref }, children), + ), + Tooltip: ({ children }: { children?: React.ReactNode }) => React.createElement(React.Fragment, null, children), // Keep Select/SelectItem as the real implementation so scope-switching is testable }; }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.test.tsx index 2b487d6532..1d466a7a18 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/teams/components/TeamsTable/ModelsCell.test.tsx @@ -9,10 +9,18 @@ import ModelsCell from "./ModelsCell"; // interaction can be tested end-to-end. vi.mock("@tremor/react", async (importOriginal) => { const actual = await importOriginal(); + // Re-apply the global Button/Tooltip overrides from tests/setupTests.ts. A file-level + // vi.mock fully replaces the setup-level mock, so without this the real Tremor Button + // leaks through and its useTooltip(300) schedules a native setTimeout that can fire + // post-teardown -> "window is not defined". return { ...actual, Icon: ({ onClick, "aria-label": ariaLabel }: { onClick?: () => void; "aria-label"?: string }) => React.createElement("button", { onClick, "aria-label": ariaLabel ?? "accordion-toggle", type: "button" }), + Button: React.forwardRef(({ children, ...props }, ref) => + React.createElement("button", { ...props, ref }, children), + ), + Tooltip: ({ children }: { children?: React.ReactNode }) => React.createElement(React.Fragment, null, children), }; }); 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 b0228e9e86..08dc64767f 100644 --- a/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.test.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/forms/MakeMCPPublicForm.test.tsx @@ -63,9 +63,15 @@ vi.mock("antd", () => ({ ), })); -// Additional @tremor/react mocks (Button is already mocked globally) +// Additional @tremor/react mocks. +// NOTE: the comment used to say "Button is already mocked globally" — that was +// incorrect. A file-level vi.mock fully replaces the setup-level mock from +// tests/setupTests.ts, so we must re-apply the Button/Tooltip overrides here. +// Without them, the real Tremor Button leaks through and its useTooltip(300) +// schedules a native setTimeout that can fire post-teardown -> "window is not defined". vi.mock("@tremor/react", async (importOriginal) => { const actual = await importOriginal(); + const React = await import("react"); return { ...actual, Text: ({ children, className }: any) => {children}, @@ -75,6 +81,12 @@ vi.mock("@tremor/react", async (importOriginal) => { {children} ), + Button: React.forwardRef(({ children, ...props }, ref) => ( + + )), + Tooltip: ({ children }: any) => <>{children}, }; }); diff --git a/ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx b/ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx index 848807ce5a..934d4ea394 100644 --- a/ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx +++ b/ui/litellm-dashboard/src/components/GuardrailsMonitor/ScoreChart.test.tsx @@ -6,6 +6,10 @@ import { ScoreChart } from "./ScoreChart"; vi.mock("@tremor/react", async (importOriginal) => { const actual = await importOriginal(); + // Re-apply the global Button/Tooltip overrides from tests/setupTests.ts. A file-level + // vi.mock fully replaces the setup-level mock, so without this the real Tremor Button + // leaks through and its useTooltip(300) schedules a native setTimeout that can fire + // post-teardown -> "window is not defined". return { ...actual, BarChart: ({ data, categories }: { data: any[]; categories: string[] }) => ( @@ -17,6 +21,12 @@ vi.mock("@tremor/react", async (importOriginal) => { ))} ), + Button: React.forwardRef(({ children, ...props }, ref) => ( + + )), + Tooltip: ({ children }: { children?: React.ReactNode }) => <>{children}, }; }); diff --git a/ui/litellm-dashboard/src/components/molecules/models/columns.test.tsx b/ui/litellm-dashboard/src/components/molecules/models/columns.test.tsx index b20c85ecb3..a3dbbb2783 100644 --- a/ui/litellm-dashboard/src/components/molecules/models/columns.test.tsx +++ b/ui/litellm-dashboard/src/components/molecules/models/columns.test.tsx @@ -23,9 +23,19 @@ vi.mock("@tremor/react", async (importOriginal) => { ); }); IconComponent.displayName = "Icon"; + // Re-apply the global Button/Tooltip overrides from tests/setupTests.ts. A file-level + // vi.mock fully replaces the setup-level mock, so without this the real Tremor Button + // leaks through and its useTooltip(300) schedules a native setTimeout that can fire + // post-teardown -> "window is not defined". + const Button = React.forwardRef(({ children, ...props }, ref) => + React.createElement("button", { ...props, ref }, children), + ); + const Tooltip = ({ children }: any) => React.createElement(React.Fragment, null, children); return { ...actual, Icon: IconComponent, + Button, + Tooltip, }; }); diff --git a/ui/litellm-dashboard/src/components/policies/impact_popover.test.tsx b/ui/litellm-dashboard/src/components/policies/impact_popover.test.tsx index b875892779..bcc67888f9 100644 --- a/ui/litellm-dashboard/src/components/policies/impact_popover.test.tsx +++ b/ui/litellm-dashboard/src/components/policies/impact_popover.test.tsx @@ -15,10 +15,18 @@ vi.mock("@heroicons/react/outline", () => ({ vi.mock("@tremor/react", async (importOriginal) => { const actual = await importOriginal(); + // Re-apply the global Button/Tooltip overrides from tests/setupTests.ts. A file-level + // vi.mock fully replaces the setup-level mock, so without this the real Tremor Button + // leaks through and its useTooltip(300) schedules a native setTimeout that can fire + // post-teardown -> "window is not defined". return { ...actual, Icon: ({ icon: IconComp, onClick, className }: any) => React.createElement("button", { type: "button", onClick, className }, IconComp?.displayName ?? IconComp?.name ?? "icon"), + Button: React.forwardRef(({ children, ...props }, ref) => + React.createElement("button", { ...props, ref }, children), + ), + Tooltip: ({ children }: { children?: React.ReactNode }) => React.createElement(React.Fragment, null, children), }; }); diff --git a/ui/litellm-dashboard/src/components/user_edit_view.test.tsx b/ui/litellm-dashboard/src/components/user_edit_view.test.tsx index 7aeaae94fa..69ef8dd95e 100644 --- a/ui/litellm-dashboard/src/components/user_edit_view.test.tsx +++ b/ui/litellm-dashboard/src/components/user_edit_view.test.tsx @@ -85,9 +85,19 @@ vi.mock("@tremor/react", async (importOriginal) => { return React.createElement("option", { value, title }, childText || title || value); }; SelectItem.displayName = "SelectItem"; + // Re-apply the global Button/Tooltip overrides from tests/setupTests.ts. + // A file-level vi.mock fully replaces the setup-level mock, so without this + // the real Tremor Button leaks through and its useTooltip(300) schedules a + // native setTimeout that fires post-teardown -> "window is not defined". + const Button = React.forwardRef(({ children, ...props }, ref) => + React.createElement("button", { ...props, ref }, children), + ); + const TremorTooltip = ({ children }: any) => React.createElement(React.Fragment, null, children); return { ...actual, SelectItem, + Button, + Tooltip: TremorTooltip, }; }); @@ -141,11 +151,6 @@ describe("UserEditView", () => { }); afterEach(() => { - // Tremor's internal Tooltip sets a setTimeout that fires after teardown, - // causing "window is not defined". Flush pending timers before cleanup. - vi.useFakeTimers(); - vi.runAllTimers(); - vi.useRealTimers(); cleanup(); });