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/addSelection.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 type { InProcHttpServer } from '../inProcHttpServer';
9
import { MockHttpServer, MockSessionTracker, createMockEditor, createMockEditorWithScheme } from './testHelpers';
10
11
const { mockRegisterCommand, mockActiveTextEditor, mockShowQuickPick } = vi.hoisted(() => ({
12
mockRegisterCommand: vi.fn(),
13
mockActiveTextEditor: { value: null as unknown },
14
mockShowQuickPick: vi.fn(),
15
}));
16
17
vi.mock('vscode', () => ({
18
window: {
19
get activeTextEditor() { return mockActiveTextEditor.value; },
20
showWarningMessage: vi.fn(),
21
showQuickPick: (...args: unknown[]) => mockShowQuickPick(...args),
22
},
23
commands: {
24
registerCommand: (...args: unknown[]) => mockRegisterCommand(...args),
25
},
26
}));
27
28
import * as vscode from 'vscode';
29
import { ADD_SELECTION_COMMAND, registerAddSelectionCommand } from '../commands/addSelection';
30
import { ADD_FILE_REFERENCE_NOTIFICATION } from '../commands/sendContext';
31
32
describe('addSelection command', () => {
33
const logger = new TestLogService();
34
let httpServer: MockHttpServer;
35
let sessionTracker: MockSessionTracker;
36
let registeredCommands: Map<string, (...args: unknown[]) => unknown>;
37
38
beforeEach(() => {
39
vi.clearAllMocks();
40
httpServer = new MockHttpServer();
41
sessionTracker = new MockSessionTracker();
42
registeredCommands = new Map();
43
mockActiveTextEditor.value = null;
44
45
// Default: one connected session
46
httpServer.setConnectedSessionIds(['session-1']);
47
48
mockRegisterCommand.mockImplementation((name: string, callback: (...args: unknown[]) => unknown) => {
49
registeredCommands.set(name, callback);
50
return { dispose: () => { } };
51
});
52
});
53
54
it('should register the command', () => {
55
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
56
expect(registeredCommands.has(ADD_SELECTION_COMMAND)).toBe(true);
57
});
58
59
it('should send selection notification from active editor with selection', async () => {
60
mockActiveTextEditor.value = createMockEditor('/test/file.ts', 'line 0\nline 1\nline 2', 1, 0, 1, 6);
61
62
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
63
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
64
65
expect(httpServer.sendNotification).toHaveBeenCalledWith(
66
'session-1',
67
ADD_FILE_REFERENCE_NOTIFICATION,
68
expect.objectContaining({
69
filePath: '/test/file.ts',
70
selection: {
71
start: { line: 1, character: 0 },
72
end: { line: 1, character: 6 },
73
},
74
selectedText: 'line 1',
75
}),
76
);
77
});
78
79
it('should send context with null selection when no text is selected (fallback to file)', async () => {
80
mockActiveTextEditor.value = createMockEditor('/test/file.ts', 'Hello World', 0, 0, 0, 0);
81
82
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
83
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
84
85
expect(httpServer.sendNotification).toHaveBeenCalledWith(
86
'session-1',
87
ADD_FILE_REFERENCE_NOTIFICATION,
88
expect.objectContaining({
89
filePath: '/test/file.ts',
90
selection: null,
91
selectedText: null,
92
}),
93
);
94
});
95
96
it('should show warning when no active editor', async () => {
97
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
98
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
99
100
expect(httpServer.sendNotification).not.toHaveBeenCalled();
101
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
102
'No active editor. Open a file to add a reference.',
103
);
104
});
105
106
it('should show warning when no sessions are connected', async () => {
107
httpServer.setConnectedSessionIds([]);
108
mockActiveTextEditor.value = createMockEditor('/test/file.ts', 'content', 0, 0, 0, 0);
109
110
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
111
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
112
113
expect(httpServer.sendNotification).not.toHaveBeenCalled();
114
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
115
'No Copilot CLI sessions are connected.',
116
);
117
});
118
119
it('should show picker when multiple sessions are connected', async () => {
120
httpServer.setConnectedSessionIds(['session-1', 'session-2']);
121
mockShowQuickPick.mockResolvedValue({ sessionId: 'session-2', label: 'session-2' });
122
mockActiveTextEditor.value = createMockEditor('/test/file.ts', 'content', 0, 0, 0, 7);
123
124
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
125
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
126
127
expect(mockShowQuickPick).toHaveBeenCalled();
128
expect(httpServer.sendNotification).toHaveBeenCalledWith(
129
'session-2',
130
ADD_FILE_REFERENCE_NOTIFICATION,
131
expect.objectContaining({ filePath: '/test/file.ts' }),
132
);
133
});
134
135
describe('URI scheme validation', () => {
136
it('should allow file scheme', async () => {
137
mockActiveTextEditor.value = createMockEditorWithScheme('/test/file.ts', 'content', 0, 0, 0, 7, 'file');
138
139
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
140
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
141
142
expect(httpServer.sendNotification).toHaveBeenCalled();
143
});
144
145
it('should reject vscode-remote scheme with warning', async () => {
146
mockActiveTextEditor.value = createMockEditorWithScheme('/test/file.ts', 'content', 0, 0, 0, 7, 'vscode-remote');
147
148
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
149
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
150
151
expect(httpServer.sendNotification).not.toHaveBeenCalled();
152
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
153
'Cannot send virtual files to Copilot CLI.',
154
);
155
});
156
157
it('should reject output scheme with warning', async () => {
158
mockActiveTextEditor.value = createMockEditorWithScheme('/Output', 'content', 0, 0, 0, 7, 'output');
159
160
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
161
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
162
163
expect(httpServer.sendNotification).not.toHaveBeenCalled();
164
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
165
'Cannot send virtual files to Copilot CLI.',
166
);
167
});
168
169
it('should reject untitled scheme with warning', async () => {
170
mockActiveTextEditor.value = createMockEditorWithScheme('/Untitled-1', 'content', 0, 0, 0, 7, 'untitled');
171
172
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
173
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
174
175
expect(httpServer.sendNotification).not.toHaveBeenCalled();
176
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
177
'Cannot send virtual files to Copilot CLI.',
178
);
179
});
180
181
it('should reject vscode-chat-code-block scheme with warning', async () => {
182
mockActiveTextEditor.value = createMockEditorWithScheme('/block', 'content', 0, 0, 0, 7, 'vscode-chat-code-block');
183
184
registerAddSelectionCommand(logger, httpServer as unknown as InProcHttpServer, sessionTracker.asTracker());
185
await registeredCommands.get(ADD_SELECTION_COMMAND)!();
186
187
expect(httpServer.sendNotification).not.toHaveBeenCalled();
188
expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(
189
'Cannot send virtual files to Copilot CLI.',
190
);
191
});
192
});
193
});
194
195