Path: blob/main/src/vs/workbench/contrib/externalUriOpener/test/common/externalUriOpenerService.test.ts
4780 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 { CancellationToken } from '../../../../../base/common/cancellation.js';7import { Disposable, DisposableStore } from '../../../../../base/common/lifecycle.js';8import { URI } from '../../../../../base/common/uri.js';9import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';10import { ExternalUriOpenerPriority } from '../../../../../editor/common/languages.js';11import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';12import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';13import { TestInstantiationService } from '../../../../../platform/instantiation/test/common/instantiationServiceMock.js';14import { IOpenerService } from '../../../../../platform/opener/common/opener.js';15import { IPickOptions, IQuickInputService, IQuickPickItem, QuickPickInput } from '../../../../../platform/quickinput/common/quickInput.js';16import { ExternalUriOpenerService, IExternalOpenerProvider, IExternalUriOpener } from '../../common/externalUriOpenerService.js';171819class MockQuickInputService implements Partial<IQuickInputService> {2021constructor(22private readonly pickIndex: number23) { }2425public pick<T extends IQuickPickItem>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: true }, token?: CancellationToken): Promise<T[]>;26public pick<T extends IQuickPickItem>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: IPickOptions<T> & { canPickMany: false }, token?: CancellationToken): Promise<T>;27public async pick<T extends IQuickPickItem>(picks: Promise<QuickPickInput<T>[]> | QuickPickInput<T>[], options?: Omit<IPickOptions<T>, 'canPickMany'>, token?: CancellationToken): Promise<T | undefined> {28const resolvedPicks = await picks;29const item = resolvedPicks[this.pickIndex];30if (item.type === 'separator') {31return undefined;32}33return item;34}3536}3738suite('ExternalUriOpenerService', () => {39let disposables: DisposableStore;40let instantiationService: TestInstantiationService;4142setup(() => {43disposables = new DisposableStore();44instantiationService = disposables.add(new TestInstantiationService());4546instantiationService.stub(IConfigurationService, new TestConfigurationService());47instantiationService.stub(IOpenerService, {48registerExternalOpener: () => { return Disposable.None; }49});50});5152teardown(() => {53disposables.dispose();54});5556ensureNoDisposablesAreLeakedInTestSuite();5758test('Should not open if there are no openers', async () => {59const externalUriOpenerService = disposables.add(instantiationService.createInstance(ExternalUriOpenerService));6061externalUriOpenerService.registerExternalOpenerProvider(new class implements IExternalOpenerProvider {62async *getOpeners(_targetUri: URI): AsyncGenerator<IExternalUriOpener> {63// noop64}65});6667const uri = URI.parse('http://contoso.com');68const didOpen = await externalUriOpenerService.openExternal(uri.toString(), { sourceUri: uri }, CancellationToken.None);69assert.strictEqual(didOpen, false);70});7172test('Should prompt if there is at least one enabled opener', async () => {73instantiationService.stub(IQuickInputService, new MockQuickInputService(0));7475const externalUriOpenerService = disposables.add(instantiationService.createInstance(ExternalUriOpenerService));7677let openedWithEnabled = false;78externalUriOpenerService.registerExternalOpenerProvider(new class implements IExternalOpenerProvider {79async *getOpeners(_targetUri: URI): AsyncGenerator<IExternalUriOpener> {80yield {81id: 'disabled-id',82label: 'disabled',83canOpen: async () => ExternalUriOpenerPriority.None,84openExternalUri: async () => true,85};86yield {87id: 'enabled-id',88label: 'enabled',89canOpen: async () => ExternalUriOpenerPriority.Default,90openExternalUri: async () => {91openedWithEnabled = true;92return true;93}94};95}96});9798const uri = URI.parse('http://contoso.com');99const didOpen = await externalUriOpenerService.openExternal(uri.toString(), { sourceUri: uri }, CancellationToken.None);100assert.strictEqual(didOpen, true);101assert.strictEqual(openedWithEnabled, true);102});103104test('Should automatically pick single preferred opener without prompt', async () => {105const externalUriOpenerService = disposables.add(instantiationService.createInstance(ExternalUriOpenerService));106107let openedWithPreferred = false;108externalUriOpenerService.registerExternalOpenerProvider(new class implements IExternalOpenerProvider {109async *getOpeners(_targetUri: URI): AsyncGenerator<IExternalUriOpener> {110yield {111id: 'other-id',112label: 'other',113canOpen: async () => ExternalUriOpenerPriority.Default,114openExternalUri: async () => {115return true;116}117};118yield {119id: 'preferred-id',120label: 'preferred',121canOpen: async () => ExternalUriOpenerPriority.Preferred,122openExternalUri: async () => {123openedWithPreferred = true;124return true;125}126};127}128});129130const uri = URI.parse('http://contoso.com');131const didOpen = await externalUriOpenerService.openExternal(uri.toString(), { sourceUri: uri }, CancellationToken.None);132assert.strictEqual(didOpen, true);133assert.strictEqual(openedWithPreferred, true);134});135});136137138