mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-05 02:41:56 +00:00
MessageManager and NotificationManager were thin facades over lib/toast since #37207. This rewrites their ~750 call sites (226 files) to import { toast } from @/lib/toast directly: success/info/warning/error keep their names, fromBackend becomes fromError, destroy/clear become dismiss. The one config-object caller (CreateMCPServer's admin-review branch) becomes an explicit toast.success(message, { description }). Behaviour is unchanged: no production caller passed a duration, so every toast keeps the same kind, title and default duration. Tests: the global vitest mock now targets @/lib/toast (toast.test.ts opts back out with vi.unmock), so the per-file vi.mock boilerplate for the facades is deleted and assertions read toast.success / toast.fromError. The two facade files, their test and their filename-case suppressions are removed, along with the commented-out facade calls left in networking.tsx
85 lines
3.3 KiB
TypeScript
85 lines
3.3 KiB
TypeScript
import { act, renderHook } from "@testing-library/react";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
import * as networking from "@/components/networking";
|
|
import { useToolsOAuthFlow } from "./useToolsOAuthFlow";
|
|
|
|
vi.mock("@/components/networking", () => ({
|
|
exchangeMcpOAuthToken: vi.fn(),
|
|
registerMcpOAuthClient: vi.fn(),
|
|
buildMcpOAuthAuthorizeUrl: vi.fn(() => "https://gw.example.com/v1/mcp/server/oauth/server-1/authorize"),
|
|
getProxyBaseUrl: vi.fn(() => ""),
|
|
serverRootPath: "",
|
|
}));
|
|
|
|
vi.mock("@/utils/pkce", () => ({
|
|
generateCodeVerifier: () => "verifier-1",
|
|
generateCodeChallenge: async () => "challenge-1",
|
|
}));
|
|
|
|
function renderFlow(options: { gatewayMintsClient?: boolean }) {
|
|
return renderHook(() =>
|
|
useToolsOAuthFlow({
|
|
accessToken: "user-token",
|
|
serverId: "server-1",
|
|
serverAlias: "server one",
|
|
userId: "user-1",
|
|
gatewayMintsClient: options.gatewayMintsClient,
|
|
onSuccess: vi.fn(),
|
|
}),
|
|
);
|
|
}
|
|
|
|
describe("useToolsOAuthFlow client registration", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
window.sessionStorage.clear();
|
|
window.localStorage.clear();
|
|
Object.defineProperty(window, "location", {
|
|
value: { href: "https://app.example.com/ui?page=mcp-servers" },
|
|
writable: true,
|
|
configurable: true,
|
|
});
|
|
});
|
|
|
|
it("skips browser-side client registration when the gateway mints the client", async () => {
|
|
// Client-forwarded token modes: the gateway's /authorize mints and carries the
|
|
// OAuth client itself, so a browser-side registration would only create an
|
|
// extra orphan client at the IdP. The authorize URL must go out clientless.
|
|
const { result } = renderFlow({ gatewayMintsClient: true });
|
|
|
|
await act(async () => {
|
|
await result.current.startOAuthFlow();
|
|
});
|
|
|
|
expect(networking.registerMcpOAuthClient).not.toHaveBeenCalled();
|
|
expect(networking.buildMcpOAuthAuthorizeUrl).toHaveBeenCalledWith(
|
|
expect.objectContaining({ serverId: "server-1", clientId: undefined }),
|
|
);
|
|
expect(window.location.href).toBe("https://gw.example.com/v1/mcp/server/oauth/server-1/authorize");
|
|
});
|
|
|
|
it("still registers browser-side for servers the gateway does not mint for", async () => {
|
|
// The cells where gatewayMintsClientFor is false keep the browser-held client: an
|
|
// oauth_delegate dcr_bridge server (interactive sign-in) and the legacy oauth2 passthrough both
|
|
// register first, so the minted client_id rides the authorize URL through the front-door relay.
|
|
vi.mocked(networking.registerMcpOAuthClient).mockResolvedValue({ client_id: "reg-client-1" });
|
|
|
|
const { result } = renderFlow({});
|
|
|
|
await act(async () => {
|
|
await result.current.startOAuthFlow();
|
|
});
|
|
|
|
expect(networking.registerMcpOAuthClient).toHaveBeenCalledTimes(1);
|
|
// The dcr_bridge relay rejects registrations without the client's own
|
|
// callback, so the browser must bind its minted client to it.
|
|
expect(networking.registerMcpOAuthClient).toHaveBeenCalledWith(
|
|
"user-token",
|
|
"server-1",
|
|
expect.objectContaining({ redirect_uris: [expect.stringContaining("callback")] }),
|
|
);
|
|
expect(networking.buildMcpOAuthAuthorizeUrl).toHaveBeenCalledWith(
|
|
expect.objectContaining({ serverId: "server-1", clientId: "reg-client-1" }),
|
|
);
|
|
});
|
|
});
|