Path: blob/main/src/vs/workbench/test/browser/contributions.test.ts
4778 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 { DeferredPromise } from '../../../base/common/async.js';7import { DisposableStore } from '../../../base/common/lifecycle.js';8import { isCI } from '../../../base/common/platform.js';9import { URI } from '../../../base/common/uri.js';10import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../base/test/common/utils.js';11import { SyncDescriptor } from '../../../platform/instantiation/common/descriptors.js';12import { ServiceCollection } from '../../../platform/instantiation/common/serviceCollection.js';13import { EditorPart } from '../../browser/parts/editor/editorPart.js';14import { WorkbenchPhase, WorkbenchContributionsRegistry } from '../../common/contributions.js';15import { EditorService } from '../../services/editor/browser/editorService.js';16import { IEditorGroupsService } from '../../services/editor/common/editorGroupsService.js';17import { IEditorService, SIDE_GROUP } from '../../services/editor/common/editorService.js';18import { LifecyclePhase } from '../../services/lifecycle/common/lifecycle.js';19import { ITestInstantiationService, TestFileEditorInput, TestServiceAccessor, TestSingletonFileEditorInput, createEditorPart, registerTestEditor, workbenchInstantiationService } from './workbenchTestServices.js';2021suite('Contributions', () => {22const disposables = new DisposableStore();2324let aCreated: boolean;25let aCreatedPromise: DeferredPromise<void>;2627let bCreated: boolean;28let bCreatedPromise: DeferredPromise<void>;2930const TEST_EDITOR_ID = 'MyTestEditorForContributions';31const TEST_EDITOR_INPUT_ID = 'testEditorInputForContributions';3233async function createEditorService(instantiationService: ITestInstantiationService = workbenchInstantiationService(undefined, disposables)): Promise<[EditorPart, EditorService]> {34const part = await createEditorPart(instantiationService, disposables);35instantiationService.stub(IEditorGroupsService, part);3637const editorService = disposables.add(instantiationService.createInstance(EditorService, undefined));38instantiationService.stub(IEditorService, editorService);3940return [part, editorService];41}4243setup(() => {44aCreated = false;45aCreatedPromise = new DeferredPromise<void>();4647bCreated = false;48bCreatedPromise = new DeferredPromise<void>();4950disposables.add(registerTestEditor(TEST_EDITOR_ID, [new SyncDescriptor(TestFileEditorInput), new SyncDescriptor(TestSingletonFileEditorInput)], TEST_EDITOR_INPUT_ID));51});5253teardown(async () => {54disposables.clear();55});5657class TestContributionA {58constructor() {59aCreated = true;60aCreatedPromise.complete();61}62}63class TestContributionB {64constructor() {65bCreated = true;66bCreatedPromise.complete();67}68}69class TestContributionError {70constructor() {71throw new Error();72}73}7475test('getWorkbenchContribution() - with lazy contributions', () => {76const registry = disposables.add(new WorkbenchContributionsRegistry());7778assert.throws(() => registry.getWorkbenchContribution('a'));7980registry.registerWorkbenchContribution2('a', TestContributionA, { lazy: true });81assert.throws(() => registry.getWorkbenchContribution('a'));8283registry.registerWorkbenchContribution2('b', TestContributionB, { lazy: true });84registry.registerWorkbenchContribution2('c', TestContributionError, { lazy: true });8586const instantiationService = workbenchInstantiationService(undefined, disposables);87registry.start(instantiationService);8889const instanceA = registry.getWorkbenchContribution('a');90assert.ok(instanceA instanceof TestContributionA);91assert.ok(aCreated);92assert.strictEqual(instanceA, registry.getWorkbenchContribution('a'));9394const instanceB = registry.getWorkbenchContribution('b');95assert.ok(instanceB instanceof TestContributionB);9697assert.throws(() => registry.getWorkbenchContribution('c'));98});99100test('getWorkbenchContribution() - with non-lazy contributions', async () => {101const registry = disposables.add(new WorkbenchContributionsRegistry());102103const instantiationService = workbenchInstantiationService(undefined, disposables);104const accessor = instantiationService.createInstance(TestServiceAccessor);105accessor.lifecycleService.usePhases = true;106registry.start(instantiationService);107108assert.throws(() => registry.getWorkbenchContribution('a'));109110registry.registerWorkbenchContribution2('a', TestContributionA, WorkbenchPhase.BlockRestore);111112const instanceA = registry.getWorkbenchContribution('a');113assert.ok(instanceA instanceof TestContributionA);114assert.ok(aCreated);115116accessor.lifecycleService.phase = LifecyclePhase.Ready;117await aCreatedPromise.p;118119assert.strictEqual(instanceA, registry.getWorkbenchContribution('a'));120});121122test('lifecycle phase instantiation works when phase changes', async () => {123const registry = disposables.add(new WorkbenchContributionsRegistry());124125const instantiationService = workbenchInstantiationService(undefined, disposables);126const accessor = instantiationService.createInstance(TestServiceAccessor);127registry.start(instantiationService);128129registry.registerWorkbenchContribution2('a', TestContributionA, WorkbenchPhase.BlockRestore);130assert.ok(!aCreated);131132accessor.lifecycleService.phase = LifecyclePhase.Ready;133await aCreatedPromise.p;134assert.ok(aCreated);135});136137test('lifecycle phase instantiation works when phase was already met', async () => {138const registry = disposables.add(new WorkbenchContributionsRegistry());139140const instantiationService = workbenchInstantiationService(undefined, disposables);141const accessor = instantiationService.createInstance(TestServiceAccessor);142accessor.lifecycleService.usePhases = true;143accessor.lifecycleService.phase = LifecyclePhase.Restored;144145registry.registerWorkbenchContribution2('a', TestContributionA, WorkbenchPhase.BlockRestore);146registry.start(instantiationService);147148await aCreatedPromise.p;149assert.ok(aCreated);150});151152(isCI ? test.skip /* runWhenIdle seems flaky in CI on Windows */ : test)('lifecycle phase instantiation works for late phases', async () => {153const registry = disposables.add(new WorkbenchContributionsRegistry());154155const instantiationService = workbenchInstantiationService(undefined, disposables);156const accessor = instantiationService.createInstance(TestServiceAccessor);157accessor.lifecycleService.usePhases = true;158registry.start(instantiationService);159160registry.registerWorkbenchContribution2('a', TestContributionA, WorkbenchPhase.AfterRestored);161registry.registerWorkbenchContribution2('b', TestContributionB, WorkbenchPhase.Eventually);162assert.ok(!aCreated);163assert.ok(!bCreated);164165accessor.lifecycleService.phase = LifecyclePhase.Starting;166accessor.lifecycleService.phase = LifecyclePhase.Ready;167accessor.lifecycleService.phase = LifecyclePhase.Restored;168await aCreatedPromise.p;169assert.ok(aCreated);170171accessor.lifecycleService.phase = LifecyclePhase.Eventually;172await bCreatedPromise.p;173assert.ok(bCreated);174});175176test('contribution on editor - editor exists before start', async function () {177const registry = disposables.add(new WorkbenchContributionsRegistry());178179const instantiationService = workbenchInstantiationService(undefined, disposables);180181const [, editorService] = await createEditorService(instantiationService);182183const input = disposables.add(new TestFileEditorInput(URI.parse('my://resource-basics'), TEST_EDITOR_INPUT_ID));184await editorService.openEditor(input, { pinned: true });185186registry.registerWorkbenchContribution2('a', TestContributionA, { editorTypeId: TEST_EDITOR_ID });187registry.start(instantiationService.createChild(new ServiceCollection([IEditorService, editorService])));188189await aCreatedPromise.p;190assert.ok(aCreated);191192registry.registerWorkbenchContribution2('b', TestContributionB, { editorTypeId: TEST_EDITOR_ID });193194const input2 = disposables.add(new TestFileEditorInput(URI.parse('my://resource-basics2'), TEST_EDITOR_INPUT_ID));195await editorService.openEditor(input2, { pinned: true }, SIDE_GROUP);196197await bCreatedPromise.p;198assert.ok(bCreated);199});200201test('contribution on editor - editor does not exist before start', async function () {202const registry = disposables.add(new WorkbenchContributionsRegistry());203204const instantiationService = workbenchInstantiationService(undefined, disposables);205206const [, editorService] = await createEditorService(instantiationService);207208const input = disposables.add(new TestFileEditorInput(URI.parse('my://resource-basics'), TEST_EDITOR_INPUT_ID));209210registry.registerWorkbenchContribution2('a', TestContributionA, { editorTypeId: TEST_EDITOR_ID });211registry.start(instantiationService.createChild(new ServiceCollection([IEditorService, editorService])));212213await editorService.openEditor(input, { pinned: true });214215await aCreatedPromise.p;216assert.ok(aCreated);217});218219ensureNoDisposablesAreLeakedInTestSuite();220});221222223