File size: 4,011 Bytes
9332ccf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import { act } from 'react';
import type { EventEmitter } from 'node:events';
import { renderWithProviders } from '../../test-utils/render.js';
import { waitFor } from '../../test-utils/async.js';
import { ConfigInitDisplay } from './ConfigInitDisplay.js';
import {
  describe,
  it,
  expect,
  vi,
  beforeEach,
  afterEach,
  type MockInstance,
} from 'vitest';
import {
  CoreEvent,
  MCPServerStatus,
  type McpClient,
  coreEvents,
} from '@google/gemini-cli-core';
import { Text } from 'ink';

// Mock GeminiSpinner
vi.mock('./GeminiSpinner.js', () => ({
  GeminiSpinner: () => <Text>Spinner</Text>,
}));

describe('ConfigInitDisplay', () => {
  let onSpy: MockInstance<EventEmitter['on']>;

  beforeEach(() => {
    onSpy = vi.spyOn(coreEvents as EventEmitter, 'on');
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  it('renders initial state', async () => {
    const { lastFrame } = await renderWithProviders(<ConfigInitDisplay />);
    expect(lastFrame()).toMatchSnapshot();
  });

  it('updates message on McpClientUpdate event', async () => {
    let listener: ((clients?: Map<string, McpClient>) => void) | undefined;
    onSpy.mockImplementation((event: unknown, fn: unknown) => {
      if (event === CoreEvent.McpClientUpdate) {
        listener = fn as (clients?: Map<string, McpClient>) => void;
      }
      return coreEvents;
    });

    const { lastFrame } = await renderWithProviders(<ConfigInitDisplay />);

    // Wait for listener to be registered
    await waitFor(() => {
      if (!listener) throw new Error('Listener not registered yet');
    });

    const mockClient1 = {
      getStatus: () => MCPServerStatus.CONNECTED,
    } as McpClient;
    const mockClient2 = {
      getStatus: () => MCPServerStatus.CONNECTING,
    } as McpClient;
    const clients = new Map<string, McpClient>([
      ['server1', mockClient1],
      ['server2', mockClient2],
    ]);

    // Trigger the listener manually since we mocked the event emitter
    act(() => {
      listener!(clients);
    });

    // Wait for the UI to update
    await waitFor(() => {
      expect(lastFrame()).toMatchSnapshot();
    });
  });

  it('truncates list of waiting servers if too many', async () => {
    let listener: ((clients?: Map<string, McpClient>) => void) | undefined;
    onSpy.mockImplementation((event: unknown, fn: unknown) => {
      if (event === CoreEvent.McpClientUpdate) {
        listener = fn as (clients?: Map<string, McpClient>) => void;
      }
      return coreEvents;
    });

    const { lastFrame } = await renderWithProviders(<ConfigInitDisplay />);

    await waitFor(() => {
      if (!listener) throw new Error('Listener not registered yet');
    });

    const mockClientConnecting = {
      getStatus: () => MCPServerStatus.CONNECTING,
    } as McpClient;

    const clients = new Map<string, McpClient>([
      ['s1', mockClientConnecting],
      ['s2', mockClientConnecting],
      ['s3', mockClientConnecting],
      ['s4', mockClientConnecting],
      ['s5', mockClientConnecting],
    ]);

    act(() => {
      listener!(clients);
    });

    await waitFor(() => {
      expect(lastFrame()).toMatchSnapshot();
    });
  });

  it('handles empty clients map', async () => {
    let listener: ((clients?: Map<string, McpClient>) => void) | undefined;
    onSpy.mockImplementation((event: unknown, fn: unknown) => {
      if (event === CoreEvent.McpClientUpdate) {
        listener = fn as (clients?: Map<string, McpClient>) => void;
      }
      return coreEvents;
    });

    const { lastFrame } = await renderWithProviders(<ConfigInitDisplay />);

    await waitFor(() => {
      if (!listener) throw new Error('Listener not registered yet');
    });

    if (listener) {
      const safeListener = listener;
      act(() => {
        safeListener(new Map());
      });
    }

    await waitFor(() => {
      expect(lastFrame()).toMatchSnapshot();
    });
  });
});