Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/extension/chatSessions/copilotcli/vscode-node/test/inProcHttpServer.spec.ts
13406 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { beforeEach, describe, expect, it, vi } from 'vitest';
7
import { TestLogService } from '../../../../../platform/testing/common/testLogService';
8
import { CopilotCLISessionTracker } from '../copilotCLISessionTracker';
9
import { InProcHttpServer } from '../inProcHttpServer';
10
11
vi.mock('vscode', () => ({
12
Uri: {
13
from: (components: { scheme: string; path: string; fragment: string }) => ({
14
scheme: components.scheme,
15
path: components.path,
16
fragment: components.fragment,
17
}),
18
},
19
window: {
20
onDidCloseTerminal: () => ({ dispose: () => { } }),
21
},
22
EventEmitter: class MockEventEmitter<T> {
23
private readonly listeners: Array<(e: T) => void> = [];
24
readonly event = (listener: (e: T) => void) => {
25
this.listeners.push(listener);
26
return {
27
dispose: () => {
28
const idx = this.listeners.indexOf(listener);
29
if (idx >= 0) {
30
this.listeners.splice(idx, 1);
31
}
32
},
33
};
34
};
35
fire(data: T): void {
36
for (const listener of this.listeners) {
37
listener(data);
38
}
39
}
40
dispose(): void {
41
this.listeners.length = 0;
42
}
43
},
44
}));
45
46
describe('InProcHttpServer.onDidClientDisconnect', () => {
47
let server: InProcHttpServer;
48
49
beforeEach(() => {
50
server = new InProcHttpServer(new TestLogService(), new CopilotCLISessionTracker());
51
});
52
53
it('should return a disposable', () => {
54
const disposable = server.onDidClientDisconnect(() => { });
55
expect(disposable).toBeDefined();
56
expect(disposable.dispose).toBeInstanceOf(Function);
57
});
58
59
it('should remove the listener on dispose', () => {
60
const listener = vi.fn();
61
const disposable = server.onDidClientDisconnect(listener);
62
disposable.dispose();
63
64
// Trigger _unregisterTransport indirectly by accessing private state
65
// Since _unregisterTransport is private, we verify via the listener not being called
66
// after dispose by checking the listener array is empty
67
expect(listener).not.toHaveBeenCalled();
68
});
69
70
it('should support multiple listeners', () => {
71
const listener1 = vi.fn();
72
const listener2 = vi.fn();
73
server.onDidClientDisconnect(listener1);
74
server.onDidClientDisconnect(listener2);
75
76
// Both should be registered (we can't easily trigger them without
77
// going through the full MCP flow, but at least we verify registration)
78
expect(listener1).not.toHaveBeenCalled();
79
expect(listener2).not.toHaveBeenCalled();
80
});
81
82
it('should only remove the disposed listener', () => {
83
const listener1 = vi.fn();
84
const listener2 = vi.fn();
85
const disposable1 = server.onDidClientDisconnect(listener1);
86
server.onDidClientDisconnect(listener2);
87
88
disposable1.dispose();
89
90
// listener2 should still be registered
91
expect(listener1).not.toHaveBeenCalled();
92
expect(listener2).not.toHaveBeenCalled();
93
});
94
95
it('should handle double dispose gracefully', () => {
96
const listener = vi.fn();
97
const disposable = server.onDidClientDisconnect(listener);
98
disposable.dispose();
99
expect(() => disposable.dispose()).not.toThrow();
100
});
101
});
102
103