Skip to content

Commit 8d6f89b

Browse files
committed
test: improve tests for clarity and functionality
1 parent e328613 commit 8d6f89b

File tree

2 files changed

+33
-112
lines changed

2 files changed

+33
-112
lines changed

packages/core/src/mcp/client/index.spec.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ describe("MCPClient", () => {
109109
clientInfo: mockClientInfo,
110110
server: { type: "unknown" } as any,
111111
});
112-
}).toThrow("Unsupported MCP server configuration type");
112+
}).toThrow("Unsupported server configuration type: unknown");
113113
});
114114
});
115115

@@ -151,36 +151,48 @@ describe("MCPClient", () => {
151151

152152
describe("disconnect", () => {
153153
let client: MCPClient;
154+
let mockClientInstance: any;
154155

155156
beforeEach(async () => {
157+
(Client as any).mockImplementation(() => {
158+
mockClientInstance = mockClient;
159+
return mockClientInstance;
160+
});
156161
client = new MCPClient({
157162
clientInfo: mockClientInfo,
158163
server: mockHttpServerConfig,
159164
});
160165
await client.connect();
166+
// Verify that the constructor set the onclose handler
167+
expect(mockClientInstance.onclose).toBeInstanceOf(Function);
161168
});
162169

163-
it("should disconnect from the server", async () => {
164-
const disconnectSpy = jest.spyOn(client, "emit");
165-
await client.disconnect();
166-
167-
expect(mockClose).toHaveBeenCalled();
168-
expect(disconnectSpy).toHaveBeenCalledWith("disconnect");
170+
it("should disconnect from the server and emit event", async () => {
171+
const disconnectEmitSpy = jest.spyOn(client, "emit");
172+
const closePromise = client.disconnect();
173+
expect(mockClose).toHaveBeenCalledTimes(1);
174+
if (mockClientInstance.onclose) {
175+
mockClientInstance.onclose();
176+
}
177+
await closePromise;
178+
expect(disconnectEmitSpy).toHaveBeenCalledWith("disconnect");
169179
});
170180

171-
it("should not disconnect if not connected", async () => {
172-
await client.disconnect();
181+
it("should not call close if not connected", async () => {
182+
const firstDisconnectPromise = client.disconnect();
183+
if (mockClientInstance.onclose) {
184+
mockClientInstance.onclose();
185+
}
186+
await firstDisconnectPromise;
173187
mockClose.mockClear();
174188
await client.disconnect();
175-
176189
expect(mockClose).not.toHaveBeenCalled();
177190
});
178191

179192
it("should emit error if disconnection fails", async () => {
180193
const error = new Error("Disconnection failed");
181194
mockClose.mockRejectedValueOnce(error);
182195
const errorSpy = jest.spyOn(client, "emit");
183-
184196
await expect(client.disconnect()).rejects.toThrow("Disconnection failed");
185197
expect(errorSpy).toHaveBeenCalledWith("error", error);
186198
});
@@ -328,7 +340,7 @@ describe("MCPClient", () => {
328340
mockCallTool.mockResolvedValue({ content: "result" });
329341

330342
const agentTools = (await client.getAgentTools()) as Record<string, any>;
331-
const result = await agentTools["TestClient_tool1"].execute({
343+
const result = await agentTools.TestClient_tool1.execute({
332344
param: "value",
333345
});
334346

@@ -346,19 +358,16 @@ describe("MCPClient", () => {
346358
it("should handle errors in execute functions", async () => {
347359
const error = new Error("Tool execution failed");
348360
mockCallTool.mockRejectedValueOnce(error);
349-
const consoleLogSpy = jest.spyOn(console, "log").mockImplementation(() => {});
350361
const consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {});
351362

352363
const agentTools = (await client.getAgentTools()) as Record<string, any>;
353364

354-
await expect(agentTools["TestClient_tool1"].execute({ param: "value" })).rejects.toThrow(
365+
await expect(agentTools.TestClient_tool1.execute({ param: "value" })).rejects.toThrow(
355366
"Tool execution failed",
356367
);
357368

358-
expect(consoleLogSpy).toHaveBeenCalled();
359369
expect(consoleErrorSpy).toHaveBeenCalled();
360370

361-
consoleLogSpy.mockRestore();
362371
consoleErrorSpy.mockRestore();
363372
});
364373
});

packages/core/src/mcp/registry/index.spec.ts

Lines changed: 8 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -75,116 +75,38 @@ describe("MCPConfiguration", () => {
7575
const testId = "test1";
7676
const testServers = createTestServers(testId);
7777
const config = new MCPConfiguration({
78-
id: `unique-id-${testId}`,
7978
servers: testServers,
8079
});
8180
configInstances.push(config);
8281

8382
expect(config).toBeInstanceOf(MCPConfiguration);
84-
});
85-
86-
it("should use provided ID if given", () => {
87-
const testId = "test2";
88-
const testServers = createTestServers(testId);
89-
const customId = `custom-id-${testId}`;
90-
91-
const config = new MCPConfiguration({
92-
id: customId,
93-
servers: testServers,
94-
});
95-
configInstances.push(config);
96-
97-
// We can't directly test the private id property, but we can test that
98-
// creating another instance with the same ID returns the same instance
99-
const config2 = new MCPConfiguration({
100-
id: customId,
101-
servers: testServers,
102-
});
103-
// Don't add config2 to configInstances as it's the same as config
104-
105-
// Here we use toEqual instead of toBe because we should get the same instance with the same ID
106-
expect(config).toEqual(config2);
107-
});
108-
109-
it("should throw error when creating duplicate instance without explicit ID", async () => {
110-
const testId = "test3";
111-
const testServers = createTestServers(testId);
112-
113-
// Create the first instance
114-
const firstConfig = new MCPConfiguration({
115-
id: `custom-id-${testId}`,
116-
servers: testServers,
117-
});
118-
configInstances.push(firstConfig);
119-
120-
// We'll test this in a different way
121-
// We need to test the control mechanism in the MCPConfiguration class
122-
// Let's try to create a second instance with the same server configuration
123-
124-
// First let's remove the existing instance and create a new one with the same configuration
125-
// And before doing that, let's mock the generateId method so it doesn't generate independent IDs
126-
127-
// Since we can't know the ID created from our first instance,
128-
// we'll use a different approach
129-
130-
// First, get the original generateId method
131-
const originalGenerateId = (MCPConfiguration.prototype as any).generateId;
132-
133-
try {
134-
// Mock the generateId method to return a fixed ID
135-
// This way we'll try to create a new instance with the same ID
136-
(MCPConfiguration.prototype as any).generateId = () => {
137-
return "fixed-test-id";
138-
};
139-
140-
// Remove the first instance and create a new one with the same ID
141-
await firstConfig.disconnect();
142-
configInstances.pop();
143-
144-
// Create a new instance with the same ID
145-
const config1 = new MCPConfiguration({
146-
servers: testServers,
147-
});
148-
configInstances.push(config1);
149-
150-
// Now try to create a second instance with the same generated ID
151-
// this should throw an error
152-
expect(() => {
153-
new MCPConfiguration({
154-
servers: testServers,
155-
});
156-
}).toThrow(/MCPConfiguration was initialized multiple times/);
157-
} finally {
158-
// Restore the original generateId method
159-
(MCPConfiguration.prototype as any).generateId = originalGenerateId;
160-
}
83+
// Cannot check private serverConfigs directly easily
16184
});
16285
});
16386

16487
describe("disconnect", () => {
165-
it("should disconnect all clients and remove from instance cache", async () => {
88+
it("should disconnect all clients and clear local cache", async () => {
16689
const testId = "test4";
16790
const testServers = createTestServers(testId);
16891
const config = new MCPConfiguration({
169-
id: `unique-id-${testId}`,
17092
servers: testServers,
17193
});
17294
configInstances.push(config);
17395

174-
// Force client creation
96+
// Force client creation for testing disconnect
17597
await config.getClients();
17698

177-
// Spy on internal methods
178-
const deleteMapSpy = jest.spyOn(Map.prototype, "delete");
99+
// Spy only on the clear method, as delete is no longer relevant for the global map
179100
const clearMapSpy = jest.spyOn(Map.prototype, "clear");
180101

181102
await config.disconnect();
182103

183-
// Check if client disconnect method was called directly
104+
// Check if client disconnect method was called
105+
// Need to ensure MCPClient mock setup allows spying on prototype
184106
expect(MCPClient.prototype.disconnect).toHaveBeenCalled();
185107

186-
// Verify instance was removed from cache and clients were cleared
187-
expect(deleteMapSpy).toHaveBeenCalled();
108+
// Verify the local client map (mcpClientsById) was cleared
109+
// The spy on Map.prototype.clear should catch this call
188110
expect(clearMapSpy).toHaveBeenCalled();
189111
});
190112
});
@@ -194,7 +116,6 @@ describe("MCPConfiguration", () => {
194116
const testId = "test5";
195117
const testServers = createTestServers(testId);
196118
const config = new MCPConfiguration({
197-
id: `unique-id-${testId}`,
198119
servers: testServers,
199120
});
200121
configInstances.push(config);
@@ -231,7 +152,6 @@ describe("MCPConfiguration", () => {
231152
const testId = "test6";
232153
const testServers = createTestServers(testId);
233154
const config = new MCPConfiguration({
234-
id: `unique-id-${testId}`,
235155
servers: testServers,
236156
});
237157
configInstances.push(config);
@@ -275,7 +195,6 @@ describe("MCPConfiguration", () => {
275195
const testId = "test7";
276196
const testServers = createTestServers(testId);
277197
const config = new MCPConfiguration({
278-
id: `unique-id-${testId}`,
279198
servers: testServers,
280199
});
281200
configInstances.push(config);
@@ -333,7 +252,6 @@ describe("MCPConfiguration", () => {
333252
const testId = "test8";
334253
const testServers = createTestServers(testId);
335254
const config = new MCPConfiguration({
336-
id: `unique-id-${testId}`,
337255
servers: testServers,
338256
});
339257
configInstances.push(config);
@@ -372,7 +290,6 @@ describe("MCPConfiguration", () => {
372290
const testId = "test9";
373291
const testServers = createTestServers(testId);
374292
const config = new MCPConfiguration({
375-
id: `unique-id-${testId}`,
376293
servers: testServers,
377294
});
378295
configInstances.push(config);
@@ -415,7 +332,6 @@ describe("MCPConfiguration", () => {
415332
const testId = "test10";
416333
const testServers = createTestServers(testId);
417334
const config = new MCPConfiguration({
418-
id: `unique-id-${testId}`,
419335
servers: testServers,
420336
});
421337
configInstances.push(config);
@@ -472,7 +388,6 @@ describe("MCPConfiguration", () => {
472388
const testId = "test11";
473389
const testServers = createTestServers(testId);
474390
const config = new MCPConfiguration({
475-
id: `unique-id-${testId}`,
476391
servers: testServers,
477392
});
478393
configInstances.push(config);
@@ -494,7 +409,6 @@ describe("MCPConfiguration", () => {
494409
const testId = "test12";
495410
const testServers = createTestServers(testId);
496411
const config = new MCPConfiguration({
497-
id: `unique-id-${testId}`,
498412
servers: testServers,
499413
});
500414
configInstances.push(config);
@@ -508,7 +422,6 @@ describe("MCPConfiguration", () => {
508422
const testId = "test13";
509423
const testServers = createTestServers(testId);
510424
const config = new MCPConfiguration({
511-
id: `unique-id-${testId}`,
512425
servers: testServers,
513426
});
514427
configInstances.push(config);
@@ -531,7 +444,6 @@ describe("MCPConfiguration", () => {
531444
const testId = "test14";
532445
const testServers = createTestServers(testId);
533446
const config = new MCPConfiguration({
534-
id: `unique-id-${testId}`,
535447
servers: testServers,
536448
});
537449
configInstances.push(config);

0 commit comments

Comments
 (0)