11import * as path from "path" ;
22import * as vs from "vscode" ;
3- import { DART_TEST_CONTAINER_NODE_WITH_FAILURES_CONTEXT , DART_TEST_CONTAINER_NODE_WITH_SKIPS_CONTEXT , DART_TEST_GROUP_NODE_CONTEXT , DART_TEST_SUITE_NODE_CONTEXT , DART_TEST_TEST_NODE_CONTEXT , IS_IN_DART_TEST_SUITE_CONTEXT , IS_IN_FLUTTER_TEST_SUITE_CONTEXT } from "../../shared/constants" ;
3+ import { FlutterCapabilities } from "../../shared/capabilities/flutter" ;
4+ import { DART_TEST_CAN_RUN_SKIPPED_CONTEXT , DART_TEST_CONTAINER_NODE_WITH_FAILURES_CONTEXT , DART_TEST_CONTAINER_NODE_WITH_SKIPS_CONTEXT , DART_TEST_GROUP_NODE_CONTEXT , DART_TEST_SUITE_NODE_CONTEXT , DART_TEST_TEST_NODE_CONTEXT } from "../../shared/constants" ;
45import { TestStatus } from "../../shared/enums" ;
56import { TestSessionCoordinator } from "../../shared/test/coordinator" ;
67import { GroupNode , SuiteNode , TestContainerNode , TestNode , TestTreeModel , TreeNode } from "../../shared/test/test_model" ;
@@ -21,8 +22,10 @@ export class TestResultsProvider implements vs.Disposable, vs.TreeDataProvider<T
2122 private onDidChangeTreeDataEmitter : vs . EventEmitter < TreeNode | undefined > = new vs . EventEmitter < TreeNode | undefined > ( ) ;
2223 public readonly onDidChangeTreeData : vs . Event < TreeNode | undefined > = this . onDidChangeTreeDataEmitter . event ;
2324 private currentTestTerminal : [ vs . Terminal , vs . EventEmitter < string > ] | undefined ;
25+ private readonly treeItemBuilder : TreeItemBuilder ;
2426
25- constructor ( private readonly data : TestTreeModel , private readonly coordinator : TestSessionCoordinator ) {
27+ constructor ( private readonly data : TestTreeModel , private readonly coordinator : TestSessionCoordinator , private readonly flutterCapabilities : FlutterCapabilities ) {
28+ this . treeItemBuilder = new TreeItemBuilder ( flutterCapabilities ) ;
2629 this . disposables . push ( data . onDidChangeTreeData . listen ( ( node ) => this . onDidChangeTreeDataEmitter . fire ( node ) ) ) ;
2730 this . disposables . push ( vs . workspace . onDidChangeConfiguration ( ( e ) => this . handleConfigChange ( e ) ) ) ;
2831
@@ -34,8 +37,8 @@ export class TestResultsProvider implements vs.Disposable, vs.TreeDataProvider<T
3437 this . disposables . push ( vs . commands . registerCommand ( "dart.startWithoutDebuggingTest" , ( treeNode : SuiteNode | GroupNode | TestNode ) => this . runTests ( treeNode , this . getTestNames ( treeNode ) , false , false , treeNode instanceof TestNode ) ) ) ;
3538 this . disposables . push ( vs . commands . registerCommand ( "dart.startDebuggingSkippedTests" , ( treeNode : SuiteNode | GroupNode | TestNode ) => this . runTests ( treeNode , this . getTestNames ( treeNode , TestStatus . Skipped ) , true , false , true ) ) ) ;
3639 this . disposables . push ( vs . commands . registerCommand ( "dart.startWithoutDebuggingSkippedTests" , ( treeNode : SuiteNode | GroupNode | TestNode ) => this . runTests ( treeNode , this . getTestNames ( treeNode , TestStatus . Skipped ) , false , false , true ) ) ) ;
37- this . disposables . push ( vs . commands . registerCommand ( "dart.startDebuggingFailedTests" , ( treeNode : SuiteNode | GroupNode | TestNode ) => this . runTests ( treeNode , this . getTestNames ( treeNode , TestStatus . Failed ) , true , false ) ) ) ;
38- this . disposables . push ( vs . commands . registerCommand ( "dart.startWithoutDebuggingFailedTests" , ( treeNode : SuiteNode | GroupNode | TestNode ) => this . runTests ( treeNode , this . getTestNames ( treeNode , TestStatus . Failed ) , false , false ) ) ) ;
40+ this . disposables . push ( vs . commands . registerCommand ( "dart.startDebuggingFailedTests" , ( treeNode : SuiteNode | GroupNode | TestNode ) => this . runTests ( treeNode , this . getTestNames ( treeNode , TestStatus . Failed ) , true , false , false ) ) ) ;
41+ this . disposables . push ( vs . commands . registerCommand ( "dart.startWithoutDebuggingFailedTests" , ( treeNode : SuiteNode | GroupNode | TestNode ) => this . runTests ( treeNode , this . getTestNames ( treeNode , TestStatus . Failed ) , false , false , false ) ) ) ;
3942 this . disposables . push ( vs . commands . registerCommand ( "dart.runAllSkippedTestsWithoutDebugging" , ( ) => this . runAllSkippedTests ( ) ) ) ;
4043 this . disposables . push ( vs . commands . registerCommand ( "dart.runAllFailedTestsWithoutDebugging" , ( ) => this . runAllFailedTests ( ) ) ) ;
4144
@@ -123,7 +126,7 @@ export class TestResultsProvider implements vs.Disposable, vs.TreeDataProvider<T
123126 ) ;
124127 }
125128
126- private async runTests ( treeNode : GroupNode | SuiteNode | TestNode , testNames : string [ ] | undefined , debug : boolean , suppressPromptOnErrors : boolean , runSkippedTests ? : boolean , token ?: vs . CancellationToken ) {
129+ private async runTests ( treeNode : GroupNode | SuiteNode | TestNode , testNames : string [ ] | undefined , debug : boolean , suppressPromptOnErrors : boolean , runSkippedTests : boolean , token ?: vs . CancellationToken ) {
127130 const subs : vs . Disposable [ ] = [ ] ;
128131 return new Promise < void > ( async ( resolve , reject ) => {
129132 // Construct a unique ID for this session so we can track when it completes.
@@ -139,7 +142,8 @@ export class TestResultsProvider implements vs.Disposable, vs.TreeDataProvider<T
139142 resolve ( ) ;
140143 } ) ) ;
141144 const programPath = fsPath ( treeNode . suiteData . path ) ;
142- const shouldRunSkippedTests = runSkippedTests && ! isInsideFlutterProject ( vs . Uri . file ( treeNode . suiteData . path ) ) ;
145+ const canRunSkippedTest = this . flutterCapabilities . supportsRunSkippedTests || ! isInsideFlutterProject ( vs . Uri . file ( treeNode . suiteData . path ) ) ;
146+ const shouldRunSkippedTests = runSkippedTests && canRunSkippedTest ;
143147 const didStart = await vs . debug . startDebugging (
144148 vs . workspace . getWorkspaceFolder ( vs . Uri . file ( treeNode . suiteData . path ) ) ,
145149 {
@@ -221,11 +225,11 @@ export class TestResultsProvider implements vs.Disposable, vs.TreeDataProvider<T
221225
222226 public getTreeItem ( element : TreeNode ) : vs . TreeItem {
223227 if ( element instanceof SuiteNode ) {
224- return treeItemBuilder . createSuiteNode ( element ) ;
228+ return this . treeItemBuilder . createSuiteNode ( element ) ;
225229 } else if ( element instanceof GroupNode ) {
226- return treeItemBuilder . createGroupNode ( element ) ;
230+ return this . treeItemBuilder . createGroupNode ( element ) ;
227231 } else if ( element instanceof TestNode ) {
228- return treeItemBuilder . createTestNode ( element ) ;
232+ return this . treeItemBuilder . createTestNode ( element ) ;
229233 } else {
230234 throw new Error ( `Unrecognised tree node type: ${ element } ` ) ;
231235 }
@@ -317,6 +321,8 @@ function getIconPath(status: TestStatus, isStale: boolean): vs.Uri | undefined {
317321}
318322
319323class TreeItemBuilder {
324+ constructor ( private readonly flutterCapabilities : FlutterCapabilities ) { }
325+
320326 public createSuiteNode ( node : SuiteNode ) : vs . TreeItem {
321327 // TODO: children is quite expensive, we should add a faster way.
322328 const collapseState = node . children ?. length || 0 > 0 ? vs . TreeItemCollapsibleState . Collapsed : vs . TreeItemCollapsibleState . None ;
@@ -371,13 +377,11 @@ class TreeItemBuilder {
371377 contexts += `${ DART_TEST_CONTAINER_NODE_WITH_SKIPS_CONTEXT } ` ;
372378 }
373379
374- if ( node . suiteData . isFlutterSuite )
375- contexts += ` ${ IS_IN_FLUTTER_TEST_SUITE_CONTEXT } ` ;
376- else
377- contexts += `${ IS_IN_DART_TEST_SUITE_CONTEXT } ` ;
380+ // Don't mark a node as skipable unless it's non-Flutter or the current Flutter version
381+ // supports run-skipped.
382+ if ( ! node . suiteData . isFlutterSuite || this . flutterCapabilities . supportsRunSkippedTests )
383+ contexts += `${ DART_TEST_CAN_RUN_SKIPPED_CONTEXT } ` ;
378384
379385 return contexts . trimEnd ( ) ;
380386 }
381387}
382-
383- const treeItemBuilder = new TreeItemBuilder ( ) ;
0 commit comments