mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-17 15:24:40 +01:00
Mocks + full workflow scenario
This commit is contained in:
@@ -99,9 +99,14 @@ export class SessionsTerminalContribution extends Disposable implements IWorkben
|
||||
let existing = await this._findTerminalsForKey(key);
|
||||
|
||||
if (existing.length === 0) {
|
||||
existing = [await this._terminalService.createTerminal({ config: { cwd } })];
|
||||
this._terminalService.setActiveInstance(existing[0]);
|
||||
this._logService.trace(`[SessionsTerminal] Created terminal ${existing[0].instanceId} for ${cwd.fsPath}`);
|
||||
try {
|
||||
existing = [await this._terminalService.createTerminal({ config: { cwd } })];
|
||||
this._terminalService.setActiveInstance(existing[0]);
|
||||
this._logService.trace(`[SessionsTerminal] Created terminal ${existing[0].instanceId} for ${cwd.fsPath}`);
|
||||
} catch (e) {
|
||||
this._logService.trace(`[SessionsTerminal] Cannot create terminal for ${cwd.fsPath}: ${e}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if (focus) {
|
||||
|
||||
@@ -154,6 +154,7 @@ import './contrib/accountMenu/browser/account.contribution.js';
|
||||
import './contrib/aiCustomizationTreeView/browser/aiCustomizationTreeView.contribution.js';
|
||||
import './contrib/applyCommitsToParentRepo/browser/applyChangesToParentRepo.js';
|
||||
import './contrib/chat/browser/chat.contribution.js';
|
||||
import './contrib/terminal/browser/sessionsTerminalContribution.js';
|
||||
import './contrib/sessions/browser/sessions.contribution.js';
|
||||
import './contrib/sessions/browser/customizationsToolbar.contribution.js';
|
||||
import './contrib/changes/browser/changesView.contribution.js';
|
||||
|
||||
@@ -102,23 +102,6 @@ function registerMockAuth(vscode) {
|
||||
function registerMockCommands(vscode) {
|
||||
const disposables = [];
|
||||
|
||||
// Mock code review — returns canned review comments
|
||||
disposables.push(vscode.commands.registerCommand(
|
||||
'github.copilot.chat.codeReview.run',
|
||||
(args) => {
|
||||
console.log('[sessions-e2e-mock] Mock code review invoked', args);
|
||||
const files = args?.files ?? [];
|
||||
const comments = files.slice(0, 2).map((file, i) => ({
|
||||
uri: file.currentUri,
|
||||
range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 },
|
||||
body: `Mock review comment ${i + 1}: Consider improving this code.`,
|
||||
kind: 'suggestion',
|
||||
severity: 'info',
|
||||
}));
|
||||
return { type: 'success', comments };
|
||||
}
|
||||
));
|
||||
|
||||
// Mock create PR — simulates successful PR creation
|
||||
disposables.push(vscode.commands.registerCommand(
|
||||
'github.copilot.chat.createPullRequestCopilotCLIAgentSession.createPR',
|
||||
@@ -178,7 +161,7 @@ function registerMockCommands(vscode) {
|
||||
'github.copilot.chat.updateCopilotCLIAgentSessionChanges.update',
|
||||
() => {
|
||||
console.log('[sessions-e2e-mock] Mock Update Changes invoked');
|
||||
vscode.window.showInformationMessage('Mock: Changes updated successfully');
|
||||
vscode.window.showInformationMessage('Mock: Changes updated successfully',);
|
||||
}
|
||||
));
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Scenario: Full workflow
|
||||
|
||||
## Steps
|
||||
1. Type "build the project" in the chat input
|
||||
2. Press Enter to submit
|
||||
3. Verify there is a response in the chat
|
||||
4. Toggle the secondary side bar
|
||||
5. Verify the changes view shows "CHANGES" with a badge
|
||||
6. Verify "package.json" is visible in the changes list
|
||||
7. Verify "build.ts" is visible in the changes list
|
||||
8. Verify "index.ts" is visible in the changes list
|
||||
9. Click on "index.ts" in the changes list
|
||||
10. Verify a diff editor opens with modified content
|
||||
11. Press Escape to close the diff editor
|
||||
12. Verify "Merge" button is visible in changes view header
|
||||
13. Verify the "Open Terminal" button is visible
|
||||
14. Click the "Open Terminal" button
|
||||
15. Verify the terminal panel becomes visible
|
||||
16. Verify the terminal tab shows "session-1" in its label
|
||||
17. Click "New Session" to create a new session
|
||||
18. Type "fix the bug" in the chat input
|
||||
19. Press Enter to submit
|
||||
20. Verify the terminal tab label changes to show "session-2"
|
||||
21. Click back on the first session in the sessions list
|
||||
22. Verify the terminal tab label changes back to show "session-1"
|
||||
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"scenario": "Scenario: Full workflow",
|
||||
"generatedAt": "2026-03-12T22:48:50.725Z",
|
||||
"steps": [
|
||||
{
|
||||
"description": "Type \"build the project\" in the chat input",
|
||||
"commands": [
|
||||
"click textbox \"Chat input\"",
|
||||
"type \"build the project\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Press Enter to submit",
|
||||
"commands": [
|
||||
"press Enter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify there is a response in the chat",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: I'll help you build the project. Here are the changes:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Toggle the secondary side bar",
|
||||
"commands": [
|
||||
"click button \"Toggle Secondary Side Bar Visibility\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify the changes view shows \"CHANGES\" with a badge",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: Changes - 3 files changed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify \"package.json\" is visible in the changes list",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: package.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify \"build.ts\" is visible in the changes list",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: build.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify \"index.ts\" is visible in the changes list",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: index.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Click on \"index.ts\" in the changes list",
|
||||
"commands": [
|
||||
"click treeitem \"index.ts\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify a diff editor opens with modified content",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: index.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Press Escape to close the diff editor",
|
||||
"commands": [
|
||||
"press Escape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify \"Merge\" button is visible in changes view header",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: Merge"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify the \"Open Terminal\" button is visible",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: Open Terminal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Click the \"Open Terminal\" button",
|
||||
"commands": [
|
||||
"click button \"Open Terminal\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify the terminal panel becomes visible",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: Terminal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify the terminal tab shows \"session-1\" in its label",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: bash - session-1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Click \"New Session\" to create a new session",
|
||||
"commands": [
|
||||
"click button \"New Session\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Type \"fix the bug\" in the chat input",
|
||||
"commands": [
|
||||
"click textbox \"Chat input\"",
|
||||
"type \"fix the bug\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Press Enter to submit",
|
||||
"commands": [
|
||||
"press Enter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify the terminal tab label changes to show \"session-2\"",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: bash - session-2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Click back on the first session in the sessions list",
|
||||
"commands": [
|
||||
"click listitem \"build the project\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Verify the terminal tab label changes back to show \"session-1\"",
|
||||
"commands": [
|
||||
"# ASSERT_VISIBLE: bash - session-1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -25,6 +25,10 @@ import { IChatProgress } from '../../workbench/contrib/chat/common/chatService/c
|
||||
import { IChatSessionsService, IChatSessionItem, IChatSessionFileChange, ChatSessionStatus, IChatSessionHistoryItem } from '../../workbench/contrib/chat/common/chatSessionsService.js';
|
||||
import { IGitService, IGitExtensionDelegate, IGitRepository } from '../../workbench/contrib/git/common/gitService.js';
|
||||
import { IFileService } from '../../platform/files/common/files.js';
|
||||
import { ITerminalService } from '../../workbench/contrib/terminal/browser/terminal.js';
|
||||
import { ITerminalBackend, ITerminalBackendRegistry, IProcessReadyEvent, IProcessProperty, ProcessPropertyType, TerminalExtensions, ITerminalProcessOptions, IShellLaunchConfig } from '../../platform/terminal/common/terminal.js';
|
||||
import { IProcessEnvironment } from '../../base/common/platform.js';
|
||||
import { Registry } from '../../platform/registry/common/platform.js';
|
||||
import { InMemoryFileSystemProvider } from '../../platform/files/common/inMemoryFilesystemProvider.js';
|
||||
import { VSBuffer } from '../../base/common/buffer.js';
|
||||
|
||||
@@ -230,16 +234,19 @@ class MockChatAgentContribution extends Disposable implements IWorkbenchContribu
|
||||
private readonly _sessionItems: IChatSessionItem[] = [];
|
||||
private readonly _itemsChangedEmitter = new Emitter<void>();
|
||||
private readonly _sessionHistory = new Map<string, IChatSessionHistoryItem[]>();
|
||||
private _worktreeCounter = 0;
|
||||
|
||||
constructor(
|
||||
@IChatAgentService private readonly chatAgentService: IChatAgentService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IChatSessionsService private readonly chatSessionsService: IChatSessionsService,
|
||||
@ITerminalService private readonly terminalService: ITerminalService,
|
||||
) {
|
||||
super();
|
||||
this._register(this._itemsChangedEmitter);
|
||||
this.registerMockAgents();
|
||||
this.registerMockSessionProvider();
|
||||
this.registerMockTerminalBackend();
|
||||
this.preseedFolder();
|
||||
}
|
||||
|
||||
@@ -285,6 +292,7 @@ class MockChatAgentContribution extends Disposable implements IWorkbenchContribu
|
||||
label: message.slice(0, 50) || 'Mock Session',
|
||||
status: ChatSessionStatus.Completed,
|
||||
timing: { created: now, lastRequestStarted: now, lastRequestEnded: now },
|
||||
metadata: { worktreePath: `/mock-worktrees/session-${++this._worktreeCounter}` },
|
||||
...(changes ? { changes } : {}),
|
||||
});
|
||||
}
|
||||
@@ -380,11 +388,15 @@ class MockChatAgentContribution extends Disposable implements IWorkbenchContribu
|
||||
},
|
||||
}));
|
||||
|
||||
// Register an item controller so sessions appear in the sidebar list
|
||||
const items = this._sessionItems;
|
||||
// Register an item controller so sessions appear in the sidebar list.
|
||||
// Only copilotcli (Background) sessions need real items — the
|
||||
// copilot-cloud-agent controller must return an empty array to
|
||||
// prevent it from overwriting sessions with the wrong providerType
|
||||
// during a full model resolve.
|
||||
const controllerItems = scheme === 'copilotcli' ? this._sessionItems : [];
|
||||
this._register(this.chatSessionsService.registerChatSessionItemController(scheme, {
|
||||
onDidChangeChatSessionItems: this._itemsChangedEmitter.event,
|
||||
get items() { return items; },
|
||||
get items() { return controllerItems; },
|
||||
async refresh() { /* in-memory, no-op */ },
|
||||
}));
|
||||
|
||||
@@ -395,6 +407,83 @@ class MockChatAgentContribution extends Disposable implements IWorkbenchContribu
|
||||
}
|
||||
}
|
||||
|
||||
private registerMockTerminalBackend(): void {
|
||||
const terminalService = this.terminalService;
|
||||
const backend = this.createMockTerminalBackend();
|
||||
Registry.as<ITerminalBackendRegistry>(TerminalExtensions.Backend).registerTerminalBackend(backend);
|
||||
terminalService.registerProcessSupport(true);
|
||||
console.log('[Sessions Web Test] Registered mock terminal backend');
|
||||
}
|
||||
|
||||
private createMockTerminalBackend(): ITerminalBackend {
|
||||
return {
|
||||
remoteAuthority: undefined,
|
||||
isVirtualProcess: false,
|
||||
onDidRequestDetach: Event.None,
|
||||
attachToProcess: async () => { throw new Error('Not supported'); },
|
||||
attachToRevivedProcess: async () => { throw new Error('Not supported'); },
|
||||
listProcesses: async () => [],
|
||||
getProfiles: async () => [],
|
||||
getDefaultProfile: async () => undefined,
|
||||
getDefaultSystemShell: async () => '/bin/mock-shell',
|
||||
getShellEnvironment: async () => ({}),
|
||||
setTerminalLayoutInfo: async () => { },
|
||||
getTerminalLayoutInfo: async () => undefined,
|
||||
reduceConnectionGraceTime: () => { },
|
||||
requestDetachInstance: () => { },
|
||||
acceptDetachInstanceReply: () => { },
|
||||
persistTerminalState: () => { },
|
||||
createProcess: async (_shellLaunchConfig: IShellLaunchConfig, _cwd: string | URI, _cols: number, _rows: number, _unicodeVersion: string, _env: IProcessEnvironment, _options: ITerminalProcessOptions, _shouldPersist: boolean) => {
|
||||
const onProcessData = new Emitter<string>();
|
||||
const onProcessReady = new Emitter<IProcessReadyEvent>();
|
||||
const onProcessExit = new Emitter<number | undefined>();
|
||||
const onDidChangeHasChildProcesses = new Emitter<boolean>();
|
||||
const onDidChangeProperty = new Emitter<IProcessProperty<ProcessPropertyType>>();
|
||||
|
||||
// Resolve cwd from createProcess arg or shellLaunchConfig
|
||||
const rawCwd = _cwd || _shellLaunchConfig.cwd;
|
||||
const cwd = !rawCwd ? '/' : typeof rawCwd === 'string' ? rawCwd : rawCwd.path;
|
||||
console.log(`[Sessions Web Test] Mock terminal createProcess cwd: '${cwd}' (raw _cwd: '${_cwd}', slc.cwd: '${_shellLaunchConfig.cwd}')`);
|
||||
|
||||
// Fire ready after a microtask so the terminal service can wire up listeners
|
||||
setTimeout(() => {
|
||||
onProcessReady.fire({ pid: 1, cwd, windowsPty: undefined });
|
||||
}, 0);
|
||||
|
||||
return {
|
||||
id: 0,
|
||||
shouldPersist: false,
|
||||
onProcessData: onProcessData.event,
|
||||
onProcessReady: onProcessReady.event,
|
||||
onDidChangeHasChildProcesses: onDidChangeHasChildProcesses.event,
|
||||
onDidChangeProperty: onDidChangeProperty.event,
|
||||
onProcessExit: onProcessExit.event,
|
||||
start: async () => undefined,
|
||||
shutdown: async () => { },
|
||||
input: async () => { },
|
||||
resize: () => { },
|
||||
clearBuffer: () => { },
|
||||
acknowledgeDataEvent: () => { },
|
||||
setUnicodeVersion: async () => { },
|
||||
getInitialCwd: async () => cwd,
|
||||
getCwd: async () => cwd,
|
||||
getLatency: async () => [],
|
||||
processBinary: async () => { },
|
||||
refreshProperty: async (property: ProcessPropertyType) => { throw new Error(`Not supported: ${property}`); },
|
||||
updateProperty: async () => { },
|
||||
clearUnrespondedRequest: () => { },
|
||||
};
|
||||
},
|
||||
getWslPath: async (original: string, _direction: 'unix-to-win' | 'win-to-unix') => original,
|
||||
getEnvironment: async () => ({}),
|
||||
getPerformanceMarks: () => [],
|
||||
onPtyHostUnresponsive: Event.None,
|
||||
onPtyHostResponsive: Event.None,
|
||||
onPtyHostRestart: Event.None,
|
||||
onPtyHostConnected: Event.None,
|
||||
} as unknown as ITerminalBackend;
|
||||
}
|
||||
|
||||
private preseedFolder(): void {
|
||||
const mockFolderUri = URI.from({ scheme: 'mock-fs', authority: 'mock-repo', path: '/mock-repo' }).toString();
|
||||
this.storageService.store('agentSessions.lastPickedFolder', mockFolderUri, StorageScope.PROFILE, StorageTarget.MACHINE);
|
||||
|
||||
Reference in New Issue
Block a user