@@ -18,7 +18,12 @@ import * as stream from "stream";
1818import * as os from "os" ;
1919import * as asyncfs from "fs/promises" ;
2020import { FolderContext } from "../FolderContext" ;
21- import { compactMap , execFile , getErrorDescription } from "../utilities/utilities" ;
21+ import {
22+ compactMap ,
23+ execFile ,
24+ getErrorDescription ,
25+ IS_PRODUCTION_BUILD ,
26+ } from "../utilities/utilities" ;
2227import { createSwiftTask } from "../tasks/SwiftTaskProvider" ;
2328import configuration from "../configuration" ;
2429import { WorkspaceContext } from "../WorkspaceContext" ;
@@ -67,6 +72,7 @@ export interface TestRunState {
6772 passed : vscode . TestItem [ ] ;
6873 skipped : vscode . TestItem [ ] ;
6974 errored : vscode . TestItem [ ] ;
75+ enqueued : vscode . TestItem [ ] ;
7076 unknown : number ;
7177 output : string [ ] ;
7278}
@@ -95,6 +101,7 @@ export class TestRunProxy {
95101 passed : [ ] ,
96102 skipped : [ ] ,
97103 errored : [ ] ,
104+ enqueued : [ ] ,
98105 unknown : 0 ,
99106 output : [ ] ,
100107 } ;
@@ -181,10 +188,9 @@ export class TestRunProxy {
181188 for ( const outputLine of this . queuedOutput ) {
182189 this . performAppendOutput ( this . testRun , outputLine ) ;
183190 }
184- this . queuedOutput = [ ] ;
185191
186192 for ( const test of this . testItems ) {
187- this . testRun . enqueued ( test ) ;
193+ this . enqueued ( test ) ;
188194 }
189195 } ;
190196
@@ -218,11 +224,17 @@ export class TestRunProxy {
218224 }
219225 }
220226
227+ private enqueued ( test : vscode . TestItem ) {
228+ this . testRun ?. enqueued ( test ) ;
229+ this . runState . enqueued . push ( test ) ;
230+ }
231+
221232 public unknownTestRan ( ) {
222233 this . runState . unknown ++ ;
223234 }
224235
225236 public started ( test : vscode . TestItem ) {
237+ this . clearEnqueuedTest ( test ) ;
226238 this . runState . pending . push ( test ) ;
227239 this . testRun ?. started ( test ) ;
228240 }
@@ -231,7 +243,29 @@ export class TestRunProxy {
231243 this . runState . pending = this . runState . pending . filter ( t => t !== test ) ;
232244 }
233245
246+ private clearEnqueuedTest ( test : vscode . TestItem ) {
247+ if ( IS_PRODUCTION_BUILD ) {
248+ // `runState.enqueued` exists only for test validation purposes.
249+ return ;
250+ }
251+
252+ this . runState . enqueued = this . runState . enqueued . filter ( t => t !== test ) ;
253+
254+ if ( ! test . parent ) {
255+ return ;
256+ }
257+
258+ const parentHasEnqueuedChildren = Array . from ( test . parent . children ) . some ( ( [ _ , child ] ) =>
259+ this . runState . enqueued . includes ( child )
260+ ) ;
261+
262+ if ( ! parentHasEnqueuedChildren ) {
263+ this . clearEnqueuedTest ( test . parent ) ;
264+ }
265+ }
266+
234267 public skipped ( test : vscode . TestItem ) {
268+ this . clearEnqueuedTest ( test ) ;
235269 test . tags = [ ...test . tags , new vscode . TestTag ( TestRunProxy . Tags . SKIPPED ) ] ;
236270
237271 this . runState . skipped . push ( test ) ;
@@ -240,6 +274,7 @@ export class TestRunProxy {
240274 }
241275
242276 public passed ( test : vscode . TestItem , duration ?: number ) {
277+ this . clearEnqueuedTest ( test ) ;
243278 this . runState . passed . push ( test ) ;
244279 this . clearPendingTest ( test ) ;
245280 this . testRun ?. passed ( test , duration ) ;
@@ -250,6 +285,7 @@ export class TestRunProxy {
250285 message : vscode . TestMessage | readonly vscode . TestMessage [ ] ,
251286 duration ?: number
252287 ) {
288+ this . clearEnqueuedTest ( test ) ;
253289 this . runState . failed . push ( { test, message } ) ;
254290 this . clearPendingTest ( test ) ;
255291 this . testRun ?. failed ( test , message , duration ) ;
@@ -260,6 +296,7 @@ export class TestRunProxy {
260296 message : vscode . TestMessage | readonly vscode . TestMessage [ ] ,
261297 duration ?: number
262298 ) {
299+ this . clearEnqueuedTest ( test ) ;
263300 this . runState . errored . push ( test ) ;
264301 this . clearPendingTest ( test ) ;
265302 this . testRun ?. errored ( test , message , duration ) ;
@@ -278,6 +315,21 @@ export class TestRunProxy {
278315 this . failed ( test , new vscode . TestMessage ( "Test did not complete." ) ) ;
279316 } ) ;
280317
318+ // If there are tests that never started, mark them as skipped.
319+ // This can happen if there is a build error preventing tests from running.
320+ this . runState . enqueued . forEach ( test => {
321+ // Omit adding the root test item as a skipped test to keep just the suites/tests
322+ // in the test run output, just like a regular pass/fail test run.
323+ if ( test . parent ) {
324+ for ( const output of this . queuedOutput ) {
325+ this . appendOutputToTest ( output , test ) ;
326+ }
327+ this . skipped ( test ) ;
328+ }
329+ } ) ;
330+
331+ this . queuedOutput = [ ] ;
332+
281333 this . reportAttachments ( ) ;
282334 this . testRun ?. end ( ) ;
283335 this . testRunCompleteEmitter . fire ( ) ;
0 commit comments