@xiaozhi-client/cli 1.9.4-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/fix-imports.js +32 -0
- package/package.json +26 -0
- package/project.json +75 -0
- package/src/Constants.ts +105 -0
- package/src/Container.ts +212 -0
- package/src/Types.ts +79 -0
- package/src/commands/CommandHandlerFactory.ts +98 -0
- package/src/commands/ConfigCommandHandler.ts +279 -0
- package/src/commands/EndpointCommandHandler.ts +158 -0
- package/src/commands/McpCommandHandler.ts +778 -0
- package/src/commands/ProjectCommandHandler.ts +254 -0
- package/src/commands/ServiceCommandHandler.ts +182 -0
- package/src/commands/__tests__/CommandHandlerFactory.test.ts +323 -0
- package/src/commands/__tests__/CommandRegistry.test.ts +287 -0
- package/src/commands/__tests__/ConfigCommandHandler.test.ts +844 -0
- package/src/commands/__tests__/EndpointCommandHandler.test.ts +426 -0
- package/src/commands/__tests__/McpCommandHandler.test.ts +753 -0
- package/src/commands/__tests__/ProjectCommandHandler.test.ts +230 -0
- package/src/commands/__tests__/ServiceCommands.integration.test.ts +408 -0
- package/src/commands/index.ts +351 -0
- package/src/errors/ErrorHandlers.ts +141 -0
- package/src/errors/ErrorMessages.ts +121 -0
- package/src/errors/__tests__/index.test.ts +186 -0
- package/src/errors/index.ts +163 -0
- package/src/global.d.ts +19 -0
- package/src/index.ts +53 -0
- package/src/interfaces/Command.ts +128 -0
- package/src/interfaces/CommandTypes.ts +95 -0
- package/src/interfaces/Config.ts +25 -0
- package/src/interfaces/Service.ts +99 -0
- package/src/services/DaemonManager.ts +318 -0
- package/src/services/ProcessManager.ts +235 -0
- package/src/services/ServiceManager.ts +319 -0
- package/src/services/TemplateManager.ts +382 -0
- package/src/services/__tests__/DaemonManager.test.ts +378 -0
- package/src/services/__tests__/DaemonMode.integration.test.ts +321 -0
- package/src/services/__tests__/ProcessManager.test.ts +296 -0
- package/src/services/__tests__/ServiceManager.test.ts +774 -0
- package/src/services/__tests__/TemplateManager.test.ts +337 -0
- package/src/types/backend.d.ts +48 -0
- package/src/utils/FileUtils.ts +320 -0
- package/src/utils/FormatUtils.ts +198 -0
- package/src/utils/PathUtils.ts +255 -0
- package/src/utils/PlatformUtils.ts +217 -0
- package/src/utils/Validation.ts +274 -0
- package/src/utils/VersionUtils.ts +141 -0
- package/src/utils/__tests__/FileUtils.test.ts +728 -0
- package/src/utils/__tests__/FormatUtils.test.ts +243 -0
- package/src/utils/__tests__/PathUtils.test.ts +1165 -0
- package/src/utils/__tests__/PlatformUtils.test.ts +723 -0
- package/src/utils/__tests__/Validation.test.ts +560 -0
- package/src/utils/__tests__/VersionUtils.test.ts +410 -0
- package/tsconfig.json +32 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsup.config.ts +107 -0
- package/vitest.config.ts +97 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EndpointCommandHandler 测试
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import type { IDIContainer } from "../../interfaces/Config";
|
|
7
|
+
import { EndpointCommandHandler } from "../EndpointCommandHandler";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 测试用的 EndpointCommandHandler 子类,用于访问受保护的方法
|
|
11
|
+
*/
|
|
12
|
+
class TestableEndpointCommandHandler extends EndpointCommandHandler {
|
|
13
|
+
// 暴露受保护的方法供测试使用
|
|
14
|
+
public async testHandleList(): Promise<void> {
|
|
15
|
+
return this.handleList();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public async testHandleAdd(url: string): Promise<void> {
|
|
19
|
+
return this.handleAdd(url);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public async testHandleRemove(url: string): Promise<void> {
|
|
23
|
+
return this.handleRemove(url);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public async testHandleSet(urls: string[]): Promise<void> {
|
|
27
|
+
return this.handleSet(urls);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public testValidateArgs(args: any[], expectedCount: number): void {
|
|
31
|
+
this.validateArgs(args, expectedCount);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Mock ora
|
|
36
|
+
vi.mock("ora", () => ({
|
|
37
|
+
default: vi.fn().mockImplementation((text) => ({
|
|
38
|
+
start: () => ({
|
|
39
|
+
succeed: (message: string) => {
|
|
40
|
+
console.log(`✅ ${message}`);
|
|
41
|
+
},
|
|
42
|
+
fail: (message: string) => {
|
|
43
|
+
console.log(`✖ ${message}`);
|
|
44
|
+
},
|
|
45
|
+
warn: (message: string) => {
|
|
46
|
+
console.log(`⚠ ${message}`);
|
|
47
|
+
},
|
|
48
|
+
}),
|
|
49
|
+
})),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
// Mock chalk
|
|
53
|
+
vi.mock("chalk", () => ({
|
|
54
|
+
default: {
|
|
55
|
+
green: (text: string) => text,
|
|
56
|
+
yellow: (text: string) => text,
|
|
57
|
+
gray: (text: string) => text,
|
|
58
|
+
},
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
// Mock dependencies
|
|
62
|
+
const mockConfigManager = {
|
|
63
|
+
getMcpEndpoints: vi.fn(),
|
|
64
|
+
addMcpEndpoint: vi.fn(),
|
|
65
|
+
removeMcpEndpoint: vi.fn(),
|
|
66
|
+
updateMcpEndpoint: vi.fn(),
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const mockErrorHandler = {
|
|
70
|
+
handle: vi.fn(),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Mock container
|
|
74
|
+
const mockContainer = {
|
|
75
|
+
get: vi.fn((name: string) => {
|
|
76
|
+
if (name === "configManager") {
|
|
77
|
+
return mockConfigManager;
|
|
78
|
+
}
|
|
79
|
+
if (name === "errorHandler") {
|
|
80
|
+
return mockErrorHandler;
|
|
81
|
+
}
|
|
82
|
+
return undefined;
|
|
83
|
+
}),
|
|
84
|
+
} as unknown as IDIContainer;
|
|
85
|
+
|
|
86
|
+
describe("EndpointCommandHandler", () => {
|
|
87
|
+
let handler: TestableEndpointCommandHandler;
|
|
88
|
+
let consoleSpy: ReturnType<typeof vi.spyOn>;
|
|
89
|
+
|
|
90
|
+
beforeEach(() => {
|
|
91
|
+
handler = new TestableEndpointCommandHandler(mockContainer);
|
|
92
|
+
consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {});
|
|
93
|
+
vi.clearAllMocks();
|
|
94
|
+
mockErrorHandler.handle.mockReset();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
afterEach(() => {
|
|
98
|
+
consoleSpy.mockRestore();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe("主命令执行", () => {
|
|
102
|
+
it("应该显示帮助信息", async () => {
|
|
103
|
+
await handler.execute([], {});
|
|
104
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
105
|
+
"MCP 端点管理命令。使用 --help 查看可用的子命令。"
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
describe("endpoint list 命令", () => {
|
|
111
|
+
it("应该显示空端点列表", async () => {
|
|
112
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue([]);
|
|
113
|
+
|
|
114
|
+
await handler.testHandleList();
|
|
115
|
+
|
|
116
|
+
expect(consoleSpy).toHaveBeenCalledWith("未配置任何 MCP 端点");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("应该显示非空端点列表", async () => {
|
|
120
|
+
const endpoints = ["http://localhost:3000", "http://localhost:3001"];
|
|
121
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue(endpoints);
|
|
122
|
+
|
|
123
|
+
await handler.testHandleList();
|
|
124
|
+
|
|
125
|
+
expect(consoleSpy).toHaveBeenCalledWith("共 2 个端点:");
|
|
126
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 1. http://localhost:3000");
|
|
127
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 2. http://localhost:3001");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("应该处理获取端点列表时的错误", async () => {
|
|
131
|
+
const error = new Error("配置文件不存在");
|
|
132
|
+
mockConfigManager.getMcpEndpoints.mockImplementation(() => {
|
|
133
|
+
throw error;
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await handler.testHandleList();
|
|
137
|
+
|
|
138
|
+
expect(mockErrorHandler.handle).toHaveBeenCalledWith(error);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe("endpoint add 命令", () => {
|
|
143
|
+
it("应该成功添加端点", async () => {
|
|
144
|
+
const url = "http://localhost:3000";
|
|
145
|
+
mockConfigManager.addMcpEndpoint.mockImplementation(() => {});
|
|
146
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue([url]);
|
|
147
|
+
|
|
148
|
+
await handler.testHandleAdd(url);
|
|
149
|
+
|
|
150
|
+
expect(mockConfigManager.addMcpEndpoint).toHaveBeenCalledWith(url);
|
|
151
|
+
expect(consoleSpy).toHaveBeenCalledWith("当前共 1 个端点");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("应该处理添加端点时的错误", async () => {
|
|
155
|
+
const url = "invalid-url";
|
|
156
|
+
const error = new Error("无效的端点URL");
|
|
157
|
+
mockConfigManager.addMcpEndpoint.mockImplementation(() => {
|
|
158
|
+
throw error;
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
await handler.testHandleAdd(url);
|
|
162
|
+
|
|
163
|
+
expect(mockErrorHandler.handle).toHaveBeenCalledWith(error);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe("endpoint remove 命令", () => {
|
|
168
|
+
it("应该成功移除端点", async () => {
|
|
169
|
+
const url = "http://localhost:3000";
|
|
170
|
+
mockConfigManager.removeMcpEndpoint.mockImplementation(() => {});
|
|
171
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue([]);
|
|
172
|
+
|
|
173
|
+
await handler.testHandleRemove(url);
|
|
174
|
+
|
|
175
|
+
expect(mockConfigManager.removeMcpEndpoint).toHaveBeenCalledWith(url);
|
|
176
|
+
expect(consoleSpy).toHaveBeenCalledWith("当前剩余 0 个端点");
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("应该处理移除端点时的错误", async () => {
|
|
180
|
+
const url = "http://localhost:3000";
|
|
181
|
+
const error = new Error("端点不存在");
|
|
182
|
+
mockConfigManager.removeMcpEndpoint.mockImplementation(() => {
|
|
183
|
+
throw error;
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
await handler.testHandleRemove(url);
|
|
187
|
+
|
|
188
|
+
expect(mockErrorHandler.handle).toHaveBeenCalledWith(error);
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
describe("endpoint set 命令", () => {
|
|
193
|
+
it("应该成功设置单个端点", async () => {
|
|
194
|
+
const urls = ["http://localhost:3000"];
|
|
195
|
+
mockConfigManager.updateMcpEndpoint.mockImplementation(() => {});
|
|
196
|
+
|
|
197
|
+
await handler.testHandleSet(urls);
|
|
198
|
+
|
|
199
|
+
expect(mockConfigManager.updateMcpEndpoint).toHaveBeenCalledWith(urls[0]);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("应该成功设置多个端点", async () => {
|
|
203
|
+
const urls = ["http://localhost:3000", "http://localhost:3001"];
|
|
204
|
+
mockConfigManager.updateMcpEndpoint.mockImplementation(() => {});
|
|
205
|
+
|
|
206
|
+
await handler.testHandleSet(urls);
|
|
207
|
+
|
|
208
|
+
expect(mockConfigManager.updateMcpEndpoint).toHaveBeenCalledWith(urls);
|
|
209
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 1. http://localhost:3000");
|
|
210
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 2. http://localhost:3001");
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("应该处理设置端点时的错误", async () => {
|
|
214
|
+
const urls = ["http://localhost:3000"];
|
|
215
|
+
const error = new Error("无效的端点配置");
|
|
216
|
+
mockConfigManager.updateMcpEndpoint.mockImplementation(() => {
|
|
217
|
+
throw error;
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
await handler.testHandleSet(urls);
|
|
221
|
+
|
|
222
|
+
expect(mockErrorHandler.handle).toHaveBeenCalledWith(error);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe("子命令参数验证", () => {
|
|
227
|
+
it("add 命令应该验证参数数量", () => {
|
|
228
|
+
expect(() => {
|
|
229
|
+
handler.testValidateArgs([], 1);
|
|
230
|
+
}).toThrow();
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it("remove 命令应该验证参数数量", () => {
|
|
234
|
+
expect(() => {
|
|
235
|
+
handler.testValidateArgs([], 1);
|
|
236
|
+
}).toThrow();
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("set 命令应该验证参数数量", () => {
|
|
240
|
+
expect(() => {
|
|
241
|
+
handler.testValidateArgs([], 1);
|
|
242
|
+
}).toThrow();
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
describe("边界情况测试", () => {
|
|
247
|
+
it("应该处理大量端点的列表显示", async () => {
|
|
248
|
+
const endpoints = Array.from(
|
|
249
|
+
{ length: 100 },
|
|
250
|
+
(_, i) => `http://localhost:${3000 + i}`
|
|
251
|
+
);
|
|
252
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue(endpoints);
|
|
253
|
+
|
|
254
|
+
await handler.testHandleList();
|
|
255
|
+
|
|
256
|
+
expect(consoleSpy).toHaveBeenCalledWith("共 100 个端点:");
|
|
257
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 1. http://localhost:3000");
|
|
258
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 100. http://localhost:3099");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("应该处理空字符串端点", async () => {
|
|
262
|
+
const emptyUrl = "";
|
|
263
|
+
const error = new Error("端点URL不能为空");
|
|
264
|
+
mockConfigManager.addMcpEndpoint.mockImplementation(() => {
|
|
265
|
+
throw error;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
await handler.testHandleAdd(emptyUrl);
|
|
269
|
+
|
|
270
|
+
expect(mockErrorHandler.handle).toHaveBeenCalledWith(error);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("应该处理特殊字符的端点URL", async () => {
|
|
274
|
+
const specialUrl = "http://localhost:3000/api/v1/test?param=value#anchor";
|
|
275
|
+
mockConfigManager.addMcpEndpoint.mockImplementation(() => {});
|
|
276
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue([specialUrl]);
|
|
277
|
+
|
|
278
|
+
await handler.testHandleAdd(specialUrl);
|
|
279
|
+
|
|
280
|
+
expect(mockConfigManager.addMcpEndpoint).toHaveBeenCalledWith(specialUrl);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("应该处理设置空数组端点(边界情况)", async () => {
|
|
284
|
+
const emptyUrls: string[] = [];
|
|
285
|
+
const error = new Error("端点列表不能为空");
|
|
286
|
+
mockConfigManager.updateMcpEndpoint.mockImplementation(() => {
|
|
287
|
+
throw error;
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
await handler.testHandleSet(emptyUrls);
|
|
291
|
+
|
|
292
|
+
expect(mockErrorHandler.handle).toHaveBeenCalledWith(error);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
describe("子命令执行函数测试", () => {
|
|
297
|
+
it("应该执行 list 子命令", async () => {
|
|
298
|
+
const listCommand = handler.subcommands.find(
|
|
299
|
+
(cmd) => cmd.name === "list"
|
|
300
|
+
);
|
|
301
|
+
expect(listCommand).toBeDefined();
|
|
302
|
+
|
|
303
|
+
if (listCommand) {
|
|
304
|
+
const handleListSpy = vi.spyOn(handler, "handleList" as any);
|
|
305
|
+
await listCommand.execute([], {});
|
|
306
|
+
expect(handleListSpy).toHaveBeenCalled();
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it("应该执行 add 子命令", async () => {
|
|
311
|
+
const addCommand = handler.subcommands.find((cmd) => cmd.name === "add");
|
|
312
|
+
expect(addCommand).toBeDefined();
|
|
313
|
+
|
|
314
|
+
if (addCommand) {
|
|
315
|
+
const handleAddSpy = vi.spyOn(handler, "handleAdd" as any);
|
|
316
|
+
await addCommand.execute(["http://localhost:3000"], {});
|
|
317
|
+
expect(handleAddSpy).toHaveBeenCalledWith("http://localhost:3000");
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("应该执行 remove 子命令", async () => {
|
|
322
|
+
const removeCommand = handler.subcommands.find(
|
|
323
|
+
(cmd) => cmd.name === "remove"
|
|
324
|
+
);
|
|
325
|
+
expect(removeCommand).toBeDefined();
|
|
326
|
+
|
|
327
|
+
if (removeCommand) {
|
|
328
|
+
const handleRemoveSpy = vi.spyOn(handler, "handleRemove" as any);
|
|
329
|
+
await removeCommand.execute(["http://localhost:3000"], {});
|
|
330
|
+
expect(handleRemoveSpy).toHaveBeenCalledWith("http://localhost:3000");
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it("应该执行 set 子命令", async () => {
|
|
335
|
+
const setCommand = handler.subcommands.find((cmd) => cmd.name === "set");
|
|
336
|
+
expect(setCommand).toBeDefined();
|
|
337
|
+
|
|
338
|
+
if (setCommand) {
|
|
339
|
+
const handleSetSpy = vi.spyOn(handler, "handleSet" as any);
|
|
340
|
+
await setCommand.execute(["http://localhost:3000"], {});
|
|
341
|
+
expect(handleSetSpy).toHaveBeenCalledWith(["http://localhost:3000"]);
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it("add 子命令应该处理参数不足的情况", async () => {
|
|
346
|
+
const addCommand = handler.subcommands.find((cmd) => cmd.name === "add");
|
|
347
|
+
expect(addCommand).toBeDefined();
|
|
348
|
+
|
|
349
|
+
if (addCommand) {
|
|
350
|
+
const validateArgsSpy = vi.spyOn(handler, "validateArgs" as any);
|
|
351
|
+
await expect(addCommand.execute([], {})).rejects.toThrow();
|
|
352
|
+
expect(validateArgsSpy).toHaveBeenCalledWith([], 1);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
it("remove 子命令应该处理参数不足的情况", async () => {
|
|
357
|
+
const removeCommand = handler.subcommands.find(
|
|
358
|
+
(cmd) => cmd.name === "remove"
|
|
359
|
+
);
|
|
360
|
+
expect(removeCommand).toBeDefined();
|
|
361
|
+
|
|
362
|
+
if (removeCommand) {
|
|
363
|
+
const validateArgsSpy = vi.spyOn(handler, "validateArgs" as any);
|
|
364
|
+
await expect(removeCommand.execute([], {})).rejects.toThrow();
|
|
365
|
+
expect(validateArgsSpy).toHaveBeenCalledWith([], 1);
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it("set 子命令应该处理参数不足的情况", async () => {
|
|
370
|
+
const setCommand = handler.subcommands.find((cmd) => cmd.name === "set");
|
|
371
|
+
expect(setCommand).toBeDefined();
|
|
372
|
+
|
|
373
|
+
if (setCommand) {
|
|
374
|
+
const validateArgsSpy = vi.spyOn(handler, "validateArgs" as any);
|
|
375
|
+
await expect(setCommand.execute([], {})).rejects.toThrow();
|
|
376
|
+
expect(validateArgsSpy).toHaveBeenCalledWith([], 1);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
describe("集成测试", () => {
|
|
382
|
+
it("应该完整测试添加和列出端点的流程", async () => {
|
|
383
|
+
const url = "http://localhost:3000";
|
|
384
|
+
|
|
385
|
+
// 添加端点
|
|
386
|
+
mockConfigManager.addMcpEndpoint.mockImplementation(() => {});
|
|
387
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue([url]);
|
|
388
|
+
await handler.testHandleAdd(url);
|
|
389
|
+
|
|
390
|
+
// 验证添加成功
|
|
391
|
+
expect(mockConfigManager.addMcpEndpoint).toHaveBeenCalledWith(url);
|
|
392
|
+
expect(consoleSpy).toHaveBeenCalledWith("当前共 1 个端点");
|
|
393
|
+
|
|
394
|
+
// 列出端点
|
|
395
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue([url]);
|
|
396
|
+
await handler.testHandleList();
|
|
397
|
+
|
|
398
|
+
// 验证列表显示
|
|
399
|
+
expect(consoleSpy).toHaveBeenCalledWith("共 1 个端点:");
|
|
400
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 1. http://localhost:3000");
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it("应该完整测试设置和移除端点的流程", async () => {
|
|
404
|
+
const urls = ["http://localhost:3000", "http://localhost:3001"];
|
|
405
|
+
|
|
406
|
+
// 设置端点
|
|
407
|
+
mockConfigManager.updateMcpEndpoint.mockImplementation(() => {});
|
|
408
|
+
await handler.testHandleSet(urls);
|
|
409
|
+
|
|
410
|
+
// 验证设置成功
|
|
411
|
+
expect(mockConfigManager.updateMcpEndpoint).toHaveBeenCalledWith(urls);
|
|
412
|
+
expect(consoleSpy).toHaveBeenCalledWith("✅ 成功设置 2 个端点");
|
|
413
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 1. http://localhost:3000");
|
|
414
|
+
expect(consoleSpy).toHaveBeenCalledWith(" 2. http://localhost:3001");
|
|
415
|
+
|
|
416
|
+
// 移除端点
|
|
417
|
+
mockConfigManager.removeMcpEndpoint.mockImplementation(() => {});
|
|
418
|
+
mockConfigManager.getMcpEndpoints.mockReturnValue([urls[1]]);
|
|
419
|
+
await handler.testHandleRemove(urls[0]);
|
|
420
|
+
|
|
421
|
+
// 验证移除成功
|
|
422
|
+
expect(mockConfigManager.removeMcpEndpoint).toHaveBeenCalledWith(urls[0]);
|
|
423
|
+
expect(consoleSpy).toHaveBeenCalledWith("当前剩余 1 个端点");
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
});
|