test: add comprehensive MCP UI test coverage with MSW infrastructure

## MSW Infrastructure Enhancement
- Add 5 MCP API handlers to tests/msw/handlers.ts:
  - get_mcp_config: Fetch MCP configuration for app type
  - import_mcp_from_claude/codex: Mock import operations (returns count: 1)
  - set_mcp_enabled: Toggle MCP server enabled state
  - upsert_mcp_server_in_config: Create/update MCP server
  - delete_mcp_server_in_config: Remove MCP server
- Add MCP state management to tests/msw/state.ts:
  - McpConfigState type with per-app server storage
  - Default test data (stdio server for Claude, http server for Codex)
  - CRUD functions: getMcpConfig, setMcpServerEnabled, upsertMcpServer, deleteMcpServer
  - Immutable state operations with deep cloning

## McpFormModal Component Tests (4 tests)
- Test preset application: Verify ID and config JSON auto-fill from preset selection
- Test conflict detection: Async validation shows warning when syncing to conflicting ID
- Test field sanitization: Verify trim whitespace, split tags, clean URLs before save
- Test validation errors: Block submit and show toast error for invalid stdio config (missing command)

## McpPanel Integration Tests (3 tests)
- Test toggle enabled state: Click toggle button triggers useMcpActions.toggleEnabled with correct params
- Test create server flow: Open form → submit → saveServer called with syncOtherSide option
- Test delete server flow: Click delete → confirm dialog → deleteServer called with ID

## Test Utilities
- Add createTestQueryClient helper with retry: false for faster test execution

## Test Coverage
- Test files: 15 → 17 (+2)
- Total tests: 105 → 112 (+6.7%)
- All 112 tests passing
- Execution time: 3.15s
This commit is contained in:
Jason
2025-10-26 13:52:42 +08:00
parent c8c4656e0e
commit c3f712bc18
5 changed files with 602 additions and 2 deletions

View File

@@ -1,6 +1,6 @@
import { http, HttpResponse } from "msw";
import type { AppType } from "@/lib/api/types";
import type { Provider, Settings } from "@/types";
import type { McpServer, Provider, Settings } from "@/types";
import {
addProvider,
deleteProvider,
@@ -15,6 +15,11 @@ import {
setSettings,
getAppConfigDirOverride,
setAppConfigDirOverrideState,
getMcpConfig,
setMcpConfig,
setMcpServerEnabled,
upsertMcpServer,
deleteMcpServer,
} from "./state";
const TAURI_ENDPOINT = "http://tauri.local";
@@ -100,6 +105,41 @@ export const handlers = [
http.post(`${TAURI_ENDPOINT}/open_external`, () => success(true)),
// MCP APIs
http.post(`${TAURI_ENDPOINT}/get_mcp_config`, async ({ request }) => {
const { app } = await withJson<{ app: AppType }>(request);
return success(getMcpConfig(app));
}),
http.post(`${TAURI_ENDPOINT}/import_mcp_from_claude`, () => success(1)),
http.post(`${TAURI_ENDPOINT}/import_mcp_from_codex`, () => success(1)),
http.post(`${TAURI_ENDPOINT}/set_mcp_enabled`, async ({ request }) => {
const { app, id, enabled } = await withJson<{
app: AppType;
id: string;
enabled: boolean;
}>(request);
setMcpServerEnabled(app, id, enabled);
return success(true);
}),
http.post(`${TAURI_ENDPOINT}/upsert_mcp_server_in_config`, async ({ request }) => {
const { app, id, spec } = await withJson<{
app: AppType;
id: string;
spec: McpServer;
}>(request);
upsertMcpServer(app, id, spec);
return success(true);
}),
http.post(`${TAURI_ENDPOINT}/delete_mcp_server_in_config`, async ({ request }) => {
const { app, id } = await withJson<{ app: AppType; id: string }>(request);
deleteMcpServer(app, id);
return success(true);
}),
http.post(`${TAURI_ENDPOINT}/restart_app`, () => success(true)),
http.post(`${TAURI_ENDPOINT}/get_settings`, () => success(getSettings())),