diff options
Diffstat (limited to 'packages/cli/src/ui/hooks/slashCommandProcessor.test.ts')
| -rw-r--r-- | packages/cli/src/ui/hooks/slashCommandProcessor.test.ts | 129 |
1 files changed, 113 insertions, 16 deletions
diff --git a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts index cc6be49e..7466e2a6 100644 --- a/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts +++ b/packages/cli/src/ui/hooks/slashCommandProcessor.test.ts @@ -60,6 +60,8 @@ import { type Config, MCPServerStatus, getMCPServerStatus, + MCPDiscoveryState, + getMCPDiscoveryState, } from '@gemini-cli/core'; import { useSessionStats } from '../contexts/SessionContext.js'; @@ -525,7 +527,7 @@ Add any other context about the problem here. describe('/mcp command', () => { beforeEach(() => { - // Mock the core module with getMCPServerStatus + // Mock the core module with getMCPServerStatus and getMCPDiscoveryState vi.mock('@gemini-cli/core', async (importOriginal) => { const actual = await importOriginal(); return { @@ -535,7 +537,13 @@ Add any other context about the problem here. CONNECTING: 'connecting', DISCONNECTED: 'disconnected', }, + MCPDiscoveryState: { + NOT_STARTED: 'not_started', + IN_PROGRESS: 'in_progress', + COMPLETED: 'completed', + }, getMCPServerStatus: vi.fn(), + getMCPDiscoveryState: vi.fn(), }; }); }); @@ -596,13 +604,18 @@ Add any other context about the problem here. server3: { command: 'cmd3' }, }; - // Setup getMCPServerStatus mock implementation + // Setup getMCPServerStatus mock implementation - use all CONNECTED to avoid startup message in this test vi.mocked(getMCPServerStatus).mockImplementation((serverName) => { if (serverName === 'server1') return MCPServerStatus.CONNECTED; - if (serverName === 'server2') return MCPServerStatus.CONNECTING; + if (serverName === 'server2') return MCPServerStatus.CONNECTED; return MCPServerStatus.DISCONNECTED; // Default for server3 and others }); + // Setup getMCPDiscoveryState mock to return completed so no startup message is shown + vi.mocked(getMCPDiscoveryState).mockReturnValue( + MCPDiscoveryState.COMPLETED, + ); + // Mock tools from each server const mockServer1Tools = [ { name: 'server1_tool1' }, @@ -638,24 +651,30 @@ Add any other context about the problem here. 2, expect.objectContaining({ type: MessageType.INFO, - text: expect.stringContaining('Configured MCP servers and tools:'), + text: expect.stringContaining('Configured MCP servers:'), }), expect.any(Number), ); - // Check that the message contains details about both servers and their tools + // Check that the message contains details about servers and their tools const message = mockAddItem.mock.calls[1][0].text; - // Server 1 - Connected (green dot) - expect(message).toContain('🟢 \u001b[1mserver1\u001b[0m (2 tools)'); + // Server 1 - Connected + expect(message).toContain( + '🟢 \u001b[1mserver1\u001b[0m - Ready (2 tools)', + ); expect(message).toContain('\u001b[36mserver1_tool1\u001b[0m'); expect(message).toContain('\u001b[36mserver1_tool2\u001b[0m'); - // Server 2 - Connecting (yellow dot) - expect(message).toContain('🟡 \u001b[1mserver2\u001b[0m (1 tools)'); + // Server 2 - Connected + expect(message).toContain( + '🟢 \u001b[1mserver2\u001b[0m - Ready (1 tools)', + ); expect(message).toContain('\u001b[36mserver2_tool1\u001b[0m'); - // Server 3 - No status, should default to Disconnected (red dot) - expect(message).toContain('🔴 \u001b[1mserver3\u001b[0m (1 tools)'); + // Server 3 - Disconnected + expect(message).toContain( + '🔴 \u001b[1mserver3\u001b[0m - Disconnected (1 tools cached)', + ); expect(message).toContain('\u001b[36mserver3_tool1\u001b[0m'); expect(commandResult).toBe(true); @@ -676,6 +695,11 @@ Add any other context about the problem here. return MCPServerStatus.DISCONNECTED; }); + // Setup getMCPDiscoveryState mock to return completed + vi.mocked(getMCPDiscoveryState).mockReturnValue( + MCPDiscoveryState.COMPLETED, + ); + // Mock tools from server with descriptions const mockServerTools = [ { name: 'tool1', description: 'This is tool 1 description' }, @@ -700,7 +724,7 @@ Add any other context about the problem here. 2, expect.objectContaining({ type: MessageType.INFO, - text: expect.stringContaining('Configured MCP servers and tools:'), + text: expect.stringContaining('Configured MCP servers:'), }), expect.any(Number), ); @@ -708,7 +732,7 @@ Add any other context about the problem here. const message = mockAddItem.mock.calls[1][0].text; // Check that server description is included (with ANSI color codes) - expect(message).toContain('\u001b[1mserver1\u001b[0m (2 tools)'); + expect(message).toContain('\u001b[1mserver1\u001b[0m - Ready (2 tools)'); expect(message).toContain( '\u001b[32mThis is a server description\u001b[0m', ); @@ -740,6 +764,11 @@ Add any other context about the problem here. return MCPServerStatus.DISCONNECTED; }); + // Setup getMCPDiscoveryState mock to return completed + vi.mocked(getMCPDiscoveryState).mockReturnValue( + MCPDiscoveryState.COMPLETED, + ); + // Mock tools from each server - server2 has no tools const mockServer1Tools = [{ name: 'server1_tool1' }]; @@ -769,19 +798,87 @@ Add any other context about the problem here. 2, expect.objectContaining({ type: MessageType.INFO, - text: expect.stringContaining('Configured MCP servers and tools:'), + text: expect.stringContaining('Configured MCP servers:'), }), expect.any(Number), ); // Check that the message contains details about both servers and their tools const message = mockAddItem.mock.calls[1][0].text; - expect(message).toContain('🟢 \u001b[1mserver1\u001b[0m (1 tools)'); + expect(message).toContain( + '🟢 \u001b[1mserver1\u001b[0m - Ready (1 tools)', + ); expect(message).toContain('\u001b[36mserver1_tool1\u001b[0m'); - expect(message).toContain('🔴 \u001b[1mserver2\u001b[0m (0 tools)'); + expect(message).toContain( + '🔴 \u001b[1mserver2\u001b[0m - Disconnected (0 tools cached)', + ); expect(message).toContain('No tools available'); expect(commandResult).toBe(true); }); + + it('should show startup indicator when servers are connecting', async () => { + // Mock MCP servers configuration + const mockMcpServers = { + server1: { command: 'cmd1' }, + server2: { command: 'cmd2' }, + }; + + // Setup getMCPServerStatus mock implementation with one server connecting + vi.mocked(getMCPServerStatus).mockImplementation((serverName) => { + if (serverName === 'server1') return MCPServerStatus.CONNECTED; + if (serverName === 'server2') return MCPServerStatus.CONNECTING; + return MCPServerStatus.DISCONNECTED; + }); + + // Setup getMCPDiscoveryState mock to return in progress + vi.mocked(getMCPDiscoveryState).mockReturnValue( + MCPDiscoveryState.IN_PROGRESS, + ); + + // Mock tools from each server + const mockServer1Tools = [{ name: 'server1_tool1' }]; + const mockServer2Tools = [{ name: 'server2_tool1' }]; + + const mockGetToolsByServer = vi.fn().mockImplementation((serverName) => { + if (serverName === 'server1') return mockServer1Tools; + if (serverName === 'server2') return mockServer2Tools; + return []; + }); + + mockConfig = { + ...mockConfig, + getToolRegistry: vi.fn().mockResolvedValue({ + getToolsByServer: mockGetToolsByServer, + }), + getMcpServers: vi.fn().mockReturnValue(mockMcpServers), + } as unknown as Config; + + const { handleSlashCommand } = getProcessor(); + let commandResult: SlashCommandActionReturn | boolean = false; + await act(async () => { + commandResult = handleSlashCommand('/mcp'); + }); + + const message = mockAddItem.mock.calls[1][0].text; + + // Check that startup indicator is shown + expect(message).toContain( + '⏳ MCP servers are starting up (1 initializing)...', + ); + expect(message).toContain( + 'Note: First startup may take longer. Tool availability will update automatically.', + ); + + // Check server statuses + expect(message).toContain( + '🟢 \u001b[1mserver1\u001b[0m - Ready (1 tools)', + ); + expect(message).toContain( + '🔄 \u001b[1mserver2\u001b[0m - Starting... (first startup may take longer) (tools will appear when ready)', + ); + + expect(commandResult).toBe(true); + }); }); }); |
