diff --git a/client/e2e/startup-state.spec.ts b/client/e2e/startup-state.spec.ts new file mode 100644 index 00000000..414ebd3e --- /dev/null +++ b/client/e2e/startup-state.spec.ts @@ -0,0 +1,16 @@ +import { test, expect } from "@playwright/test"; + +// Adjust the URL if your dev server runs on a different port +const APP_URL = "http://localhost:6274/"; + +test.describe("Startup State", () => { + test("should not navigate to a tab when Inspector first opens", async ({ + page, + }) => { + await page.goto(APP_URL); + + // Check that there is no hash fragment in the URL + const url = page.url(); + expect(url).not.toContain("#"); + }); +}); diff --git a/client/src/__tests__/App.routing.test.tsx b/client/src/__tests__/App.routing.test.tsx new file mode 100644 index 00000000..dbd463f9 --- /dev/null +++ b/client/src/__tests__/App.routing.test.tsx @@ -0,0 +1,159 @@ +import { render, waitFor } from "@testing-library/react"; +import App from "../App"; +import { useConnection } from "../lib/hooks/useConnection"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; + +// Mock auth dependencies first +jest.mock("@modelcontextprotocol/sdk/client/auth.js", () => ({ + auth: jest.fn(), +})); + +jest.mock("../lib/oauth-state-machine", () => ({ + OAuthStateMachine: jest.fn(), +})); + +jest.mock("../lib/auth", () => ({ + InspectorOAuthClientProvider: jest.fn().mockImplementation(() => ({ + tokens: jest.fn().mockResolvedValue(null), + clear: jest.fn(), + })), + DebugInspectorOAuthClientProvider: jest.fn(), +})); + +// Mock the config utils +jest.mock("../utils/configUtils", () => ({ + ...jest.requireActual("../utils/configUtils"), + getMCPProxyAddress: jest.fn(() => "http://localhost:6277"), + getMCPProxyAuthToken: jest.fn(() => ({ + token: "", + header: "X-MCP-Proxy-Auth", + })), + getInitialTransportType: jest.fn(() => "stdio"), + getInitialSseUrl: jest.fn(() => "http://localhost:3001/sse"), + getInitialCommand: jest.fn(() => "mcp-server-everything"), + getInitialArgs: jest.fn(() => ""), + initializeInspectorConfig: jest.fn(() => ({})), + saveInspectorConfig: jest.fn(), +})); + +// Default connection state is disconnected +const disconnectedConnectionState = { + connectionStatus: "disconnected" as const, + serverCapabilities: null, + mcpClient: null, + requestHistory: [], + makeRequest: jest.fn(), + sendNotification: jest.fn(), + handleCompletion: jest.fn(), + completionsSupported: false, + connect: jest.fn(), + disconnect: jest.fn(), +}; + +// Connected state for tests that need an active connection +const connectedConnectionState = { + ...disconnectedConnectionState, + connectionStatus: "connected" as const, + serverCapabilities: {}, + mcpClient: { + request: jest.fn(), + notification: jest.fn(), + close: jest.fn(), + } as unknown as Client, +}; + +// Mock required dependencies, but unrelated to routing. +jest.mock("../lib/hooks/useDraggablePane", () => ({ + useDraggablePane: () => ({ + height: 300, + handleDragStart: jest.fn(), + }), + useDraggableSidebar: () => ({ + width: 320, + isDragging: false, + handleDragStart: jest.fn(), + }), +})); + +jest.mock("../components/Sidebar", () => ({ + __esModule: true, + default: () =>