44'use strict' ;
55
66import { inject , injectable } from 'inversify' ;
7+ import * as path from 'path' ;
78import { Event , EventEmitter , TreeItem , TreeItemCollapsibleState , Uri } from 'vscode' ;
89import { ICommandManager , IWorkspaceService } from '../../common/application/types' ;
910import { Commands } from '../../common/constants' ;
11+ import { IFileSystem } from '../../common/platform/types' ;
1012import { IDisposable , IDisposableRegistry } from '../../common/types' ;
1113import { sendTelemetryEvent } from '../../telemetry' ;
1214import { EventName } from '../../telemetry/constants' ;
1315import { CommandSource } from '../common/constants' ;
1416import { getChildren , getParent , getTestType } from '../common/testUtils' ;
15- import { ITestCollectionStorageService , TestStatus , TestType } from '../common/types' ;
17+ import { ITestCollectionStorageService , Tests , TestStatus , TestType } from '../common/types' ;
1618import { ITestDataItemResource , ITestManagementService , ITestTreeViewProvider , TestDataItem , TestWorkspaceFolder , WorkspaceTestStatus } from '../types' ;
1719import { TestTreeItem } from './testTreeViewItem' ;
1820
@@ -30,6 +32,7 @@ export class TestTreeViewProvider implements ITestTreeViewProvider, ITestDataIte
3032 @inject ( ITestManagementService ) private testService : ITestManagementService ,
3133 @inject ( IWorkspaceService ) private readonly workspace : IWorkspaceService ,
3234 @inject ( ICommandManager ) private readonly commandManager : ICommandManager ,
35+ @inject ( IFileSystem ) private readonly fs : IFileSystem ,
3336 @inject ( IDisposableRegistry ) disposableRegistry : IDisposableRegistry
3437 ) {
3538 this . onDidChangeTreeData = this . _onDidChangeTreeData . event ;
@@ -92,7 +95,7 @@ export class TestTreeViewProvider implements ITestTreeViewProvider, ITestDataIte
9295 await this . commandManager . executeCommand ( Commands . Tests_Discover , element , CommandSource . testExplorer , undefined ) ;
9396 tests = this . testStore . getTests ( element . workspaceFolder . uri ) ;
9497 }
95- return tests ? tests . rootTestFolders : [ ] ;
98+ return this . getRootNodes ( tests ) ;
9699 }
97100 return getChildren ( element ! ) ;
98101 }
@@ -106,7 +109,7 @@ export class TestTreeViewProvider implements ITestTreeViewProvider, ITestDataIte
106109 // If we are in a single workspace
107110 if ( this . workspace . workspaceFolders . length === 1 ) {
108111 const tests = this . testStore . getTests ( this . workspace . workspaceFolders [ 0 ] . uri ) ;
109- return tests ? tests . rootTestFolders : [ ] ;
112+ return this . getRootNodes ( tests ) ;
110113 }
111114
112115 // If we are in a mult-root workspace, then nest the test data within a
@@ -131,7 +134,23 @@ export class TestTreeViewProvider implements ITestTreeViewProvider, ITestDataIte
131134 const tests = this . testStore . getTests ( element . resource ) ;
132135 return tests ? getParent ( tests , element ) : undefined ;
133136 }
134-
137+ /**
138+ * If we have test files directly in root directory, return those.
139+ * If we have test folders and no test files under the root directory, then just return the test directories.
140+ * The goal is not avoid returning an empty root node, when all it contains are child nodes for folders.
141+ *
142+ * @param {Tests } [tests]
143+ * @returns
144+ * @memberof TestTreeViewProvider
145+ */
146+ public getRootNodes ( tests ?: Tests ) {
147+ if ( tests && tests . rootTestFolders && tests . rootTestFolders . length === 1 ) {
148+ const rootFolder = tests . rootTestFolders [ 0 ] . name ;
149+ const testFiles = tests . testFiles . filter ( file => this . fs . arePathsSame ( path . dirname ( file . fullPath ) , rootFolder ) ) ;
150+ return [ ...testFiles , ...tests . rootTestFolders [ 0 ] . folders ] ;
151+ }
152+ return tests ? tests . rootTestFolders : [ ] ;
153+ }
135154 /**
136155 * Refresh the view by rebuilding the model and signaling the tree view to update itself.
137156 *
0 commit comments