mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
* chore(ui): upgrade the dashboard to React 19 Bumps react and react-dom from 18.3.1 to 19.2.8 with matching @types. Next 16 already required a React 19 peer, so this aligns the dashboard with what the framework expects and unblocks Base UI and shadcn work that assumes the React 19 ref model. React 19 passes ref through as a regular prop, so the setup file's forwardRef tripwire and the ref-forwarding test's forwardRef case no longer describe real behavior; both now assert the React 19 contract instead. useRef<T>(null) now yields RefObject<T | null>, which is the one prop type MessageList had to widen. * test(ui): wait for a Base UI select popup to open before clicking an option The option lands in the DOM one render before the popup finishes entering, while its positioner still carries pointer-events: none, so clicking it throws. Waiting on the option's text alone was a race that React 19's flush timing loses, which is why four ToolPolicies cases went red on the bump. chooseSelectOption in test-utils opens the trigger, finds the option by role, waits for it to stop being pointer-blocked, then clicks. It also replaces the last-match-by-text hack, which only worked because the popup happens to portal after the table.
65 lines
2.3 KiB
TypeScript
65 lines
2.3 KiB
TypeScript
import React, { PropsWithChildren } from "react";
|
|
import { render, RenderOptions, screen, waitFor } from "@testing-library/react";
|
|
import type userEvent from "@testing-library/user-event";
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
import { NuqsTestingAdapter, OnUrlUpdateFunction } from "nuqs/adapters/testing";
|
|
import { expect } from "vitest";
|
|
|
|
// Create a client for testing
|
|
export const testQueryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
gcTime: Infinity,
|
|
staleTime: Infinity,
|
|
refetchOnWindowFocus: false,
|
|
refetchOnReconnect: false,
|
|
refetchOnMount: false,
|
|
},
|
|
mutations: {
|
|
retry: false,
|
|
},
|
|
},
|
|
});
|
|
|
|
interface ProviderOptions {
|
|
searchParams?: string | Record<string, string> | URLSearchParams;
|
|
onUrlUpdate?: OnUrlUpdateFunction;
|
|
}
|
|
|
|
export const renderWithProviders = (ui: React.ReactElement, options?: RenderOptions & ProviderOptions) => {
|
|
const { searchParams, onUrlUpdate, ...renderOptions } = options ?? {};
|
|
const Providers: React.FC<PropsWithChildren> = ({ children }) => (
|
|
<NuqsTestingAdapter searchParams={searchParams} onUrlUpdate={onUrlUpdate} hasMemory>
|
|
<QueryClientProvider client={testQueryClient}>{children}</QueryClientProvider>
|
|
</NuqsTestingAdapter>
|
|
);
|
|
return render(ui, { wrapper: Providers, ...renderOptions });
|
|
};
|
|
|
|
const pointerBlocked = (element: HTMLElement): boolean => {
|
|
for (let node: HTMLElement | null = element; node !== null; node = node.parentElement) {
|
|
if (node.style.pointerEvents === "none") return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Opens a Base UI Select and picks an option by its accessible name.
|
|
*
|
|
* The option is in the DOM one render before the popup finishes entering, and until then its
|
|
* positioner still carries `pointer-events: none`, which user-event refuses to click. Waiting on
|
|
* the option text alone is a race that React 19's flush timing loses.
|
|
*/
|
|
export const chooseSelectOption = async (
|
|
user: ReturnType<typeof userEvent.setup>,
|
|
trigger: HTMLElement,
|
|
optionName: string | RegExp,
|
|
) => {
|
|
await user.click(trigger);
|
|
const option = await screen.findByRole("option", { name: optionName });
|
|
await waitFor(() => expect(pointerBlocked(option)).toBe(false));
|
|
await user.click(option);
|
|
};
|
|
|
|
export * from "@testing-library/react";
|