mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-04-07 00:15:23 +02:00
test: add tests for MCPAddRedirect and useMCPDeepLink
This commit is contained in:
parent
d67669768a
commit
c17cb9a85d
2 changed files with 182 additions and 0 deletions
108
client/src/hooks/MCP/__tests__/useMCPDeepLink.spec.tsx
Normal file
108
client/src/hooks/MCP/__tests__/useMCPDeepLink.spec.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import React from 'react';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { createMemoryRouter, RouterProvider } from 'react-router-dom';
|
||||
import useMCPDeepLink from '../useMCPDeepLink';
|
||||
|
||||
if (typeof Request === 'undefined') {
|
||||
global.Request = class Request {
|
||||
constructor(
|
||||
public url: string,
|
||||
public init?: RequestInit,
|
||||
) {}
|
||||
} as any;
|
||||
}
|
||||
|
||||
function TestWrapper({ router }: { router: ReturnType<typeof createMemoryRouter> }) {
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
|
||||
function renderDeepLinkHook(state?: Record<string, unknown>) {
|
||||
let hookResult: { current: ReturnType<typeof useMCPDeepLink> };
|
||||
|
||||
function HookConsumer() {
|
||||
hookResult = { current: useMCPDeepLink() };
|
||||
return null;
|
||||
}
|
||||
|
||||
const router = createMemoryRouter(
|
||||
[
|
||||
{
|
||||
path: 'c/:conversationId',
|
||||
element: <HookConsumer />,
|
||||
},
|
||||
],
|
||||
{
|
||||
initialEntries: [{ pathname: '/c/new', state }],
|
||||
},
|
||||
);
|
||||
|
||||
const renderResult = renderHook(() => hookResult!.current, {
|
||||
wrapper: ({ children }) => (
|
||||
<>
|
||||
<TestWrapper router={router} />
|
||||
{children}
|
||||
</>
|
||||
),
|
||||
});
|
||||
|
||||
return { ...renderResult, router, getHook: () => hookResult!.current };
|
||||
}
|
||||
|
||||
describe('useMCPDeepLink', () => {
|
||||
it('should open dialog with initialValues from route state including valid transport', async () => {
|
||||
const { getHook } = renderDeepLinkHook({
|
||||
mcpName: 'My Server',
|
||||
mcpUrl: 'https://example.com/mcp',
|
||||
mcpTransport: 'sse',
|
||||
});
|
||||
|
||||
await act(async () => {});
|
||||
|
||||
const result = getHook();
|
||||
expect(result.isOpen).toBe(true);
|
||||
expect(result.initialValues).toEqual({
|
||||
title: 'My Server',
|
||||
url: 'https://example.com/mcp',
|
||||
type: 'sse',
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore an invalid mcpTransport value', async () => {
|
||||
const { getHook } = renderDeepLinkHook({
|
||||
mcpName: 'Server',
|
||||
mcpTransport: 'websocket',
|
||||
});
|
||||
|
||||
await act(async () => {});
|
||||
|
||||
const result = getHook();
|
||||
expect(result.isOpen).toBe(true);
|
||||
expect(result.initialValues).toEqual({ title: 'Server' });
|
||||
expect(result.initialValues).not.toHaveProperty('type');
|
||||
});
|
||||
|
||||
it('should not open the dialog when route state has no MCP params', async () => {
|
||||
const { getHook } = renderDeepLinkHook(undefined);
|
||||
|
||||
await act(async () => {});
|
||||
|
||||
const result = getHook();
|
||||
expect(result.isOpen).toBe(false);
|
||||
expect(result.initialValues).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should clear initialValues when dialog is closed via onOpenChange', async () => {
|
||||
const { getHook } = renderDeepLinkHook({ mcpName: 'Server' });
|
||||
|
||||
await act(async () => {});
|
||||
expect(getHook().isOpen).toBe(true);
|
||||
expect(getHook().initialValues).toEqual({ title: 'Server' });
|
||||
|
||||
act(() => {
|
||||
getHook().onOpenChange(false);
|
||||
});
|
||||
|
||||
expect(getHook().isOpen).toBe(false);
|
||||
expect(getHook().initialValues).toBeUndefined();
|
||||
});
|
||||
});
|
||||
74
client/src/routes/__tests__/MCPAddRedirect.spec.tsx
Normal file
74
client/src/routes/__tests__/MCPAddRedirect.spec.tsx
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import React from 'react';
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { createMemoryRouter, RouterProvider, useLocation } from 'react-router-dom';
|
||||
import MCPAddRedirect from '../MCPAddRedirect';
|
||||
|
||||
if (typeof Request === 'undefined') {
|
||||
global.Request = class Request {
|
||||
constructor(
|
||||
public url: string,
|
||||
public init?: RequestInit,
|
||||
) {}
|
||||
} as any;
|
||||
}
|
||||
|
||||
function CaptureState() {
|
||||
const location = useLocation();
|
||||
(window as any).__capturedState = location.state;
|
||||
// eslint-disable-next-line i18next/no-literal-string
|
||||
return <div data-testid="chat-page">Chat</div>;
|
||||
}
|
||||
|
||||
const createTestRouter = (initialEntry: string) =>
|
||||
createMemoryRouter(
|
||||
[
|
||||
{
|
||||
path: 'mcps/add',
|
||||
element: <MCPAddRedirect />,
|
||||
},
|
||||
{
|
||||
path: 'c/:conversationId',
|
||||
element: <CaptureState />,
|
||||
},
|
||||
],
|
||||
{ initialEntries: [initialEntry] },
|
||||
);
|
||||
|
||||
describe('MCPAddRedirect', () => {
|
||||
afterEach(() => {
|
||||
(window as any).__capturedState = undefined;
|
||||
});
|
||||
|
||||
it('should redirect to /c/new forwarding all params via route state', async () => {
|
||||
const router = createTestRouter(
|
||||
'/mcps/add?name=My+Server&url=https://example.com/mcp&transport=sse',
|
||||
);
|
||||
render(<RouterProvider router={router} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(router.state.location.pathname).toBe('/c/new');
|
||||
});
|
||||
|
||||
expect(router.state.historyAction).toBe('REPLACE');
|
||||
expect((window as any).__capturedState).toEqual({
|
||||
mcpName: 'My Server',
|
||||
mcpUrl: 'https://example.com/mcp',
|
||||
mcpTransport: 'sse',
|
||||
});
|
||||
});
|
||||
|
||||
it('should redirect to /c/new even when no query params are provided', async () => {
|
||||
const router = createTestRouter('/mcps/add');
|
||||
render(<RouterProvider router={router} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(router.state.location.pathname).toBe('/c/new');
|
||||
});
|
||||
|
||||
expect((window as any).__capturedState).toEqual({
|
||||
mcpName: undefined,
|
||||
mcpUrl: undefined,
|
||||
mcpTransport: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue