Skip to content

Commit cc60343

Browse files
authored
Auto expand first level of the test explorer tree view (microsoft#5023)
For microsoft#4767
1 parent 1edd99d commit cc60343

File tree

4 files changed

+112
-11
lines changed

4 files changed

+112
-11
lines changed

news/1 Enhancements/4767.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Auto-expand the first level of the test explorer tree view.

src/client/unittests/explorer/testTreeViewItem.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ import { getTestType, isSubtestsParent } from '../common/testUtils';
1414
import { TestResult, TestStatus, TestSuite, TestType } from '../common/types';
1515
import { TestDataItem } from '../types';
1616

17+
function getDefaultCollapsibleState(data: TestDataItem): TreeItemCollapsibleState {
18+
return getTestType(data) === TestType.testFunction ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed;
19+
}
20+
1721
/**
1822
* Class that represents a visual node on the
1923
* Test Explorer tree view. Is essentially a wrapper for the underlying
@@ -24,15 +28,13 @@ export class TestTreeItem extends TreeItem {
2428

2529
constructor(
2630
public readonly resource: Uri,
27-
public readonly data: Readonly<TestDataItem>
31+
public readonly data: Readonly<TestDataItem>,
32+
collapsibleStatue: TreeItemCollapsibleState = getDefaultCollapsibleState(data)
2833
) {
29-
super(data.name, TestTreeItem.getCollapsibleState(data));
34+
super(data.name, collapsibleStatue);
3035
this.testType = getTestType(this.data);
3136
this.setCommand();
3237
}
33-
private static getCollapsibleState(data: TestDataItem): TreeItemCollapsibleState {
34-
return getTestType(data) === TestType.testFunction ? TreeItemCollapsibleState.None : TreeItemCollapsibleState.Collapsed;
35-
}
3638
public get contextValue(): string {
3739
return this.testType;
3840
}

src/client/unittests/explorer/testTreeViewProvider.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
'use strict';
55

66
import { inject, injectable } from 'inversify';
7-
import { Event, EventEmitter, TreeItem, Uri } from 'vscode';
7+
import { Event, EventEmitter, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode';
88
import { ICommandManager, IWorkspaceService } from '../../common/application/types';
99
import { Commands } from '../../common/constants';
1010
import { IDisposable, IDisposableRegistry } from '../../common/types';
1111
import { sendTelemetryEvent } from '../../telemetry';
1212
import { EventName } from '../../telemetry/constants';
1313
import { CommandSource } from '../common/constants';
14-
import { getChildren, getParent } from '../common/testUtils';
15-
import { ITestCollectionStorageService, TestStatus } from '../common/types';
14+
import { getChildren, getParent, getTestType } from '../common/testUtils';
15+
import { ITestCollectionStorageService, TestStatus, TestType } from '../common/types';
1616
import { ITestDataItemResource, ITestTreeViewProvider, IUnitTestManagementService, TestDataItem, TestWorkspaceFolder, WorkspaceTestStatus } from '../types';
1717
import { TestTreeItem } from './testTreeViewItem';
1818

@@ -73,7 +73,8 @@ export class TestTreeViewProvider implements ITestTreeViewProvider, ITestDataIte
7373
* @return [TreeItem](#TreeItem) representation of the element
7474
*/
7575
public async getTreeItem(element: TestDataItem): Promise<TreeItem> {
76-
return new TestTreeItem(element.resource, element);
76+
const defaultCollapsibleState = await this.shouldElementBeExpandedByDefault(element) ? TreeItemCollapsibleState.Expanded : undefined;
77+
return new TestTreeItem(element.resource, element, defaultCollapsibleState);
7778
}
7879

7980
/**
@@ -164,4 +165,12 @@ export class TestTreeViewProvider implements ITestTreeViewProvider, ITestDataIte
164165
this.testsAreBeingDiscovered.set(e.workspace.fsPath, false);
165166
this.refresh(e.workspace);
166167
}
168+
169+
private async shouldElementBeExpandedByDefault(element: TestDataItem) {
170+
const parent = await this.getParent(element);
171+
if (!parent || getTestType(parent) === TestType.testWorkspaceFolder) {
172+
return true;
173+
}
174+
return false;
175+
}
167176
}

src/test/unittests/explorer/testTreeViewProvider.unit.test.ts

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import { expect } from 'chai';
77
import { instance, mock, verify, when } from 'ts-mockito';
88
import * as typemoq from 'typemoq';
9-
import { Uri } from 'vscode';
9+
import { TreeItemCollapsibleState, Uri } from 'vscode';
1010
import { CommandManager } from '../../../client/common/application/commandManager';
1111
import { WorkspaceService } from '../../../client/common/application/workspace';
1212
import { Commands } from '../../../client/common/constants';
@@ -15,7 +15,7 @@ import { CommandSource } from '../../../client/unittests/common/constants';
1515
import { TestCollectionStorageService } from '../../../client/unittests/common/services/storageService';
1616
import { getTestType } from '../../../client/unittests/common/testUtils';
1717
import {
18-
ITestCollectionStorageService, TestStatus, TestType
18+
ITestCollectionStorageService, TestFile, TestFolder, TestStatus, TestType
1919
} from '../../../client/unittests/common/types';
2020
import { TestTreeItem } from '../../../client/unittests/explorer/testTreeViewItem';
2121
import { TestTreeViewProvider } from '../../../client/unittests/explorer/testTreeViewProvider';
@@ -611,4 +611,93 @@ suite('Unit Tests Test Explorer TestTreeViewProvider', () => {
611611
verify(commandManager.executeCommand(Commands.Tests_Discover, testWorkspaceFolder, CommandSource.testExplorer, undefined)).once();
612612
});
613613
});
614+
test('Expand tree item if it does not have any parent', async () => {
615+
const commandManager = mock(CommandManager);
616+
const testStore = mock(TestCollectionStorageService);
617+
const testWorkspaceFolder = new TestWorkspaceFolder({ uri: Uri.file(__filename), name: '', index: 0 });
618+
when(testStore.getTests(testWorkspaceFolder.workspaceFolder.uri)).thenReturn();
619+
when(testStore.onDidChange).thenReturn(noop as any);
620+
const testTreeProvider = createMockTestTreeProvider(instance(testStore), undefined, undefined, undefined, instance(commandManager));
621+
622+
// No parent
623+
testTreeProvider.getParent = () => Promise.resolve(undefined);
624+
625+
const element: TestFile = {
626+
fullPath: __filename,
627+
functions: [],
628+
suites: [],
629+
name: 'name',
630+
time: 0,
631+
resource: Uri.file(__filename),
632+
xmlName: '',
633+
nameToRun: ''
634+
};
635+
636+
const node = await testTreeProvider.getTreeItem(element);
637+
638+
expect(node.collapsibleState).to.equal(TreeItemCollapsibleState.Expanded);
639+
});
640+
test('Expand tree item if the parent is the Workspace Folder in a multiroot scenario', async () => {
641+
const commandManager = mock(CommandManager);
642+
const testStore = mock(TestCollectionStorageService);
643+
const testWorkspaceFolder = new TestWorkspaceFolder({ uri: Uri.file(__filename), name: '', index: 0 });
644+
when(testStore.getTests(testWorkspaceFolder.workspaceFolder.uri)).thenReturn();
645+
when(testStore.onDidChange).thenReturn(noop as any);
646+
const testTreeProvider = createMockTestTreeProvider(instance(testStore), undefined, undefined, undefined, instance(commandManager));
647+
648+
// Has a workspace folder as parent.
649+
const parentFolder = new TestWorkspaceFolder({ name: '', index: 0, uri: Uri.file(__filename) });
650+
651+
testTreeProvider.getParent = () => Promise.resolve(parentFolder);
652+
653+
const element: TestFile = {
654+
fullPath: __filename,
655+
functions: [],
656+
suites: [],
657+
name: 'name',
658+
time: 0,
659+
resource: Uri.file(__filename),
660+
xmlName: '',
661+
nameToRun: ''
662+
};
663+
664+
const node = await testTreeProvider.getTreeItem(element);
665+
666+
expect(node.collapsibleState).to.equal(TreeItemCollapsibleState.Expanded);
667+
});
668+
test('Do not expand tree item if it does not have any parent', async () => {
669+
const commandManager = mock(CommandManager);
670+
const testStore = mock(TestCollectionStorageService);
671+
const testWorkspaceFolder = new TestWorkspaceFolder({ uri: Uri.file(__filename), name: '', index: 0 });
672+
when(testStore.getTests(testWorkspaceFolder.workspaceFolder.uri)).thenReturn();
673+
when(testStore.onDidChange).thenReturn(noop as any);
674+
const testTreeProvider = createMockTestTreeProvider(instance(testStore), undefined, undefined, undefined, instance(commandManager));
675+
676+
// Has a parent folder
677+
const parentFolder: TestFolder = {
678+
name: '',
679+
nameToRun: '',
680+
resource: Uri.file(__filename),
681+
time: 0,
682+
testFiles: [],
683+
folders: []
684+
};
685+
686+
testTreeProvider.getParent = () => Promise.resolve(parentFolder);
687+
688+
const element: TestFile = {
689+
fullPath: __filename,
690+
functions: [],
691+
suites: [],
692+
name: 'name',
693+
time: 0,
694+
resource: Uri.file(__filename),
695+
xmlName: '',
696+
nameToRun: ''
697+
};
698+
699+
const node = await testTreeProvider.getTreeItem(element);
700+
701+
expect(node.collapsibleState).to.not.equal(TreeItemCollapsibleState.Expanded);
702+
});
614703
});

0 commit comments

Comments
 (0)