@@ -18,7 +18,12 @@ import * as stream from "stream";
18
18
import * as os from "os" ;
19
19
import * as asyncfs from "fs/promises" ;
20
20
import { 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" ;
22
27
import { createSwiftTask } from "../tasks/SwiftTaskProvider" ;
23
28
import configuration from "../configuration" ;
24
29
import { WorkspaceContext } from "../WorkspaceContext" ;
@@ -67,6 +72,7 @@ export interface TestRunState {
67
72
passed : vscode . TestItem [ ] ;
68
73
skipped : vscode . TestItem [ ] ;
69
74
errored : vscode . TestItem [ ] ;
75
+ enqueued : vscode . TestItem [ ] ;
70
76
unknown : number ;
71
77
output : string [ ] ;
72
78
}
@@ -95,6 +101,7 @@ export class TestRunProxy {
95
101
passed : [ ] ,
96
102
skipped : [ ] ,
97
103
errored : [ ] ,
104
+ enqueued : [ ] ,
98
105
unknown : 0 ,
99
106
output : [ ] ,
100
107
} ;
@@ -181,10 +188,9 @@ export class TestRunProxy {
181
188
for ( const outputLine of this . queuedOutput ) {
182
189
this . performAppendOutput ( this . testRun , outputLine ) ;
183
190
}
184
- this . queuedOutput = [ ] ;
185
191
186
192
for ( const test of this . testItems ) {
187
- this . testRun . enqueued ( test ) ;
193
+ this . enqueued ( test ) ;
188
194
}
189
195
} ;
190
196
@@ -218,11 +224,17 @@ export class TestRunProxy {
218
224
}
219
225
}
220
226
227
+ private enqueued ( test : vscode . TestItem ) {
228
+ this . testRun ?. enqueued ( test ) ;
229
+ this . runState . enqueued . push ( test ) ;
230
+ }
231
+
221
232
public unknownTestRan ( ) {
222
233
this . runState . unknown ++ ;
223
234
}
224
235
225
236
public started ( test : vscode . TestItem ) {
237
+ this . clearEnqueuedTest ( test ) ;
226
238
this . runState . pending . push ( test ) ;
227
239
this . testRun ?. started ( test ) ;
228
240
}
@@ -231,7 +243,29 @@ export class TestRunProxy {
231
243
this . runState . pending = this . runState . pending . filter ( t => t !== test ) ;
232
244
}
233
245
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
+
234
267
public skipped ( test : vscode . TestItem ) {
268
+ this . clearEnqueuedTest ( test ) ;
235
269
test . tags = [ ...test . tags , new vscode . TestTag ( TestRunProxy . Tags . SKIPPED ) ] ;
236
270
237
271
this . runState . skipped . push ( test ) ;
@@ -240,6 +274,7 @@ export class TestRunProxy {
240
274
}
241
275
242
276
public passed ( test : vscode . TestItem , duration ?: number ) {
277
+ this . clearEnqueuedTest ( test ) ;
243
278
this . runState . passed . push ( test ) ;
244
279
this . clearPendingTest ( test ) ;
245
280
this . testRun ?. passed ( test , duration ) ;
@@ -250,6 +285,7 @@ export class TestRunProxy {
250
285
message : vscode . TestMessage | readonly vscode . TestMessage [ ] ,
251
286
duration ?: number
252
287
) {
288
+ this . clearEnqueuedTest ( test ) ;
253
289
this . runState . failed . push ( { test, message } ) ;
254
290
this . clearPendingTest ( test ) ;
255
291
this . testRun ?. failed ( test , message , duration ) ;
@@ -260,6 +296,7 @@ export class TestRunProxy {
260
296
message : vscode . TestMessage | readonly vscode . TestMessage [ ] ,
261
297
duration ?: number
262
298
) {
299
+ this . clearEnqueuedTest ( test ) ;
263
300
this . runState . errored . push ( test ) ;
264
301
this . clearPendingTest ( test ) ;
265
302
this . testRun ?. errored ( test , message , duration ) ;
@@ -278,6 +315,21 @@ export class TestRunProxy {
278
315
this . failed ( test , new vscode . TestMessage ( "Test did not complete." ) ) ;
279
316
} ) ;
280
317
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
+
281
333
this . reportAttachments ( ) ;
282
334
this . testRun ?. end ( ) ;
283
335
this . testRunCompleteEmitter . fire ( ) ;
0 commit comments