Path: blob/main/src/vs/workbench/contrib/externalTerminal/test/electron-browser/externalTerminal.contribution.test.ts
13406 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { URI } from '../../../../../base/common/uri.js';7import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';8import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';9import { mock } from '../../../../../base/test/common/mock.js';10import { IHistoryService } from '../../../../services/history/common/history.js';11import { IExternalTerminalService } from '../../../../../platform/externalTerminal/electron-browser/externalTerminalService.js';12import { IExternalTerminalSettings } from '../../../../../platform/externalTerminal/common/externalTerminal.js';13import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';14import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';15import { IRemoteAuthorityResolverService } from '../../../../../platform/remote/common/remoteAuthorityResolver.js';16import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder } from '../../../../../platform/workspace/common/workspace.js';17import { CommandsRegistry } from '../../../../../platform/commands/common/commands.js';18import { IQuickInputService, IQuickPickItem } from '../../../../../platform/quickinput/common/quickInput.js';19import { ILabelService } from '../../../../../platform/label/common/label.js';20import '../../electron-browser/externalTerminal.contribution.js';2122suite('ExternalTerminal contribution', () => {23const store = ensureNoDisposablesAreLeakedInTestSuite();2425let instantiationService: TestInstantiationService;26let openTerminalCalls: { cwd: string | undefined }[];27let pickCalls: IQuickPickItem[][];2829function createWorkspaceFolder(uri: URI, name: string, index: number): IWorkspaceFolder {30return {31uri,32name,33index,34toResource: (relativePath: string) => URI.joinPath(uri, relativePath)35};36}3738function setupServices(options: {39folders: IWorkspaceFolder[];40lastActiveRoot?: URI;41lastActiveFile?: URI;42pickedFolder?: IWorkspaceFolder | undefined;43}) {44instantiationService = store.add(new TestInstantiationService());4546openTerminalCalls = [];47pickCalls = [];4849instantiationService.stub(IHistoryService, new class extends mock<IHistoryService>() {50override getLastActiveWorkspaceRoot() {51return options.lastActiveRoot;52}53override getLastActiveFile(_schemeFilter: string) {54return options.lastActiveFile;55}56});5758instantiationService.stub(IExternalTerminalService, new class extends mock<IExternalTerminalService>() {59override async openTerminal(_config: IExternalTerminalSettings, cwd: string | undefined) {60openTerminalCalls.push({ cwd });61}62});6364instantiationService.stub(IConfigurationService, new TestConfigurationService({65terminal: { external: { linuxExec: 'xterm', osxExec: 'Terminal.app', windowsExec: 'cmd' } }66}));6768instantiationService.stub(IRemoteAuthorityResolverService, new class extends mock<IRemoteAuthorityResolverService>() {69});7071instantiationService.stub(IWorkspaceContextService, new class extends mock<IWorkspaceContextService>() {72override getWorkspace(): IWorkspace {73return {74id: 'test-workspace',75folders: options.folders,76};77}78});7980instantiationService.stub(IQuickInputService, new class extends mock<IQuickInputService>() {81override async pick<T extends IQuickPickItem>(picks: T[]): Promise<T | undefined> {82pickCalls.push(picks);83if (options.pickedFolder) {84const index = options.folders.indexOf(options.pickedFolder);85return picks[index];86}87return undefined;88}89});9091instantiationService.stub(ILabelService, new class extends mock<ILabelService>() {92override getUriLabel(uri: URI) {93return uri.fsPath;94}95});96}9798test('single folder - uses last active workspace root', async () => {99const folderUri = URI.file('/workspace/project');100const folder = createWorkspaceFolder(folderUri, 'project', 0);101102setupServices({103folders: [folder],104lastActiveRoot: folderUri,105});106107const handler = CommandsRegistry.getCommand('workbench.action.terminal.openNativeConsole')!.handler;108await instantiationService.invokeFunction(handler);109110assert.deepStrictEqual(openTerminalCalls, [{ cwd: folderUri.fsPath }]);111assert.deepStrictEqual(pickCalls, []);112});113114test('multiple folders - shows picker and opens selected folder', async () => {115const folder1Uri = URI.file('/workspace/project1');116const folder2Uri = URI.file('/workspace/project2');117const folder1 = createWorkspaceFolder(folder1Uri, 'project1', 0);118const folder2 = createWorkspaceFolder(folder2Uri, 'project2', 1);119120setupServices({121folders: [folder1, folder2],122pickedFolder: folder2,123});124125const handler = CommandsRegistry.getCommand('workbench.action.terminal.openNativeConsole')!.handler;126await instantiationService.invokeFunction(handler);127128assert.strictEqual(pickCalls.length, 1);129assert.deepStrictEqual(openTerminalCalls, [{ cwd: folder2Uri.fsPath }]);130});131132test('multiple folders - picker cancelled does not open terminal', async () => {133const folder1Uri = URI.file('/workspace/project1');134const folder2Uri = URI.file('/workspace/project2');135const folder1 = createWorkspaceFolder(folder1Uri, 'project1', 0);136const folder2 = createWorkspaceFolder(folder2Uri, 'project2', 1);137138setupServices({139folders: [folder1, folder2],140pickedFolder: undefined,141});142143const handler = CommandsRegistry.getCommand('workbench.action.terminal.openNativeConsole')!.handler;144await instantiationService.invokeFunction(handler);145146assert.strictEqual(pickCalls.length, 1);147assert.deepStrictEqual(openTerminalCalls, []);148});149150test('no workspace root - falls back to active file directory', async () => {151const fileUri = URI.file('/workspace/project/src/file.ts');152const expectedDir = URI.file('/workspace/project/src').fsPath;153154setupServices({155folders: [],156lastActiveRoot: undefined,157lastActiveFile: fileUri,158});159160const handler = CommandsRegistry.getCommand('workbench.action.terminal.openNativeConsole')!.handler;161await instantiationService.invokeFunction(handler);162163assert.deepStrictEqual(openTerminalCalls, [{ cwd: expectedDir }]);164});165166test('no workspace, no file - opens terminal without cwd', async () => {167setupServices({168folders: [],169lastActiveRoot: undefined,170lastActiveFile: undefined,171});172173const handler = CommandsRegistry.getCommand('workbench.action.terminal.openNativeConsole')!.handler;174await instantiationService.invokeFunction(handler);175176assert.deepStrictEqual(openTerminalCalls, [{ cwd: undefined }]);177});178});179180181