diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index c00cef45a27..39e05d7fe73 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -24,6 +24,7 @@ import Severity from 'vs/base/common/severity'; import { IPaneComposite } from 'vs/workbench/common/panecomposite'; import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility'; import { IMarkdownString } from 'vs/base/common/htmlContent'; +import { mixin } from 'vs/base/common/objects'; export const TEST_VIEW_CONTAINER_ID = 'workbench.view.extension.test'; @@ -650,9 +651,9 @@ export interface ITreeItem { } export class ResolvableTreeItem implements ITreeItem { - handle: string; + handle!: string; parentHandle?: string; - collapsibleState: TreeItemCollapsibleState; + collapsibleState!: TreeItemCollapsibleState; label?: ITreeItemLabel; description?: string | boolean; icon?: UriComponents; @@ -668,20 +669,7 @@ export class ResolvableTreeItem implements ITreeItem { private resolved: boolean = false; private _hasResolve: boolean = false; constructor(treeItem: ITreeItem, resolve?: (() => Promise)) { - this.handle = treeItem.handle; - this.parentHandle = treeItem.parentHandle; - this.collapsibleState = treeItem.collapsibleState; - this.label = treeItem.label; - this.description = treeItem.description; - this.icon = treeItem.icon; - this.iconDark = treeItem.iconDark; - this.themeIcon = treeItem.themeIcon; - this.resourceUri = treeItem.resourceUri; - this.tooltip = treeItem.tooltip; - this.contextValue = treeItem.contextValue; - this.command = treeItem.command; - this.children = treeItem.children; - this.accessibilityInformation = treeItem.accessibilityInformation; + mixin(this, treeItem); this._hasResolve = !!resolve; this.resolve = async () => { if (resolve && !this.resolved) { diff --git a/src/vs/workbench/test/browser/api/mainThreadTreeViews.test.ts b/src/vs/workbench/test/browser/api/mainThreadTreeViews.test.ts new file mode 100644 index 00000000000..936a51b094f --- /dev/null +++ b/src/vs/workbench/test/browser/api/mainThreadTreeViews.test.ts @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { ExtHostTreeViewsShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; +import { mock } from 'vs/base/test/common/mock'; +import { ITreeItem, IViewsRegistry, Extensions, ViewContainerLocation, IViewContainersRegistry, ITreeViewDescriptor, ITreeView, ViewContainer, IViewDescriptorService, TreeItemCollapsibleState } from 'vs/workbench/common/views'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { MainThreadTreeViews } from 'vs/workbench/api/browser/mainThreadTreeViews'; +import { TestViewsService, workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices'; +import { TestExtensionService } from 'vs/workbench/test/common/workbenchTestServices'; +import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; +import { CustomTreeView } from 'vs/workbench/contrib/views/browser/treeView'; +import { ViewDescriptorService } from 'vs/workbench/services/views/browser/viewDescriptorService'; + +suite('MainThreadHostTreeView', function () { + const testTreeViewId = 'testTreeView'; + const customValue = 'customValue'; + const ViewsRegistry = Registry.as(Extensions.ViewsRegistry); + + interface CustomTreeItem extends ITreeItem { + customProp: string; + } + + class MockExtHostTreeViewsShape extends mock() { + async $getChildren(treeViewId: string, treeItemHandle?: string): Promise { + return [{ handle: 'testItem1', collapsibleState: TreeItemCollapsibleState.Expanded, customProp: customValue }]; + } + + async $hasResolve(): Promise { + return false; + } + + $setVisible(): void { } + } + + let container: ViewContainer; + let mainThreadTreeViews: MainThreadTreeViews; + let extHostTreeViewsShape: MockExtHostTreeViewsShape; + + setup(async () => { + const instantiationService: TestInstantiationService = workbenchInstantiationService(); + const viewDescriptorService = instantiationService.createInstance(ViewDescriptorService); + instantiationService.stub(IViewDescriptorService, viewDescriptorService); + container = Registry.as(Extensions.ViewContainersRegistry).registerViewContainer({ id: 'testContainer', name: 'test', ctorDescriptor: new SyncDescriptor({}) }, ViewContainerLocation.Sidebar); + const viewDescriptor: ITreeViewDescriptor = { + id: testTreeViewId, + ctorDescriptor: null!, + name: 'Test View 1', + treeView: instantiationService.createInstance(CustomTreeView, 'testTree', 'Test Title'), + }; + ViewsRegistry.registerViews([viewDescriptor], container); + + const testExtensionService = new TestExtensionService(); + extHostTreeViewsShape = new MockExtHostTreeViewsShape(); + mainThreadTreeViews = new MainThreadTreeViews( + new class implements IExtHostContext { + remoteAuthority = ''; + assertRegistered() { } + set(v: any): any { return null; } + getProxy(): any { + return extHostTreeViewsShape; + } + }, new TestViewsService(), new TestNotificationService(), testExtensionService, new NullLogService()); + mainThreadTreeViews.$registerTreeViewDataProvider(testTreeViewId, { showCollapseAll: false, canSelectMany: false }); + await testExtensionService.whenInstalledExtensionsRegistered(); + }); + + teardown(() => { + ViewsRegistry.deregisterViews(ViewsRegistry.getViews(container), container); + }); + + test('getChildren keeps custom properties', async () => { + const treeView: ITreeView = (ViewsRegistry.getView(testTreeViewId)).treeView; + const children = await treeView.dataProvider?.getChildren({ handle: 'root', collapsibleState: TreeItemCollapsibleState.Expanded }); + assert(children!.length === 1, 'Exactly one child should be returned'); + assert((children![0]).customProp === customValue, 'Tree Items should keep custom properties'); + }); + + +});