@@ -22,6 +22,7 @@ import { sendTelemetryEvent } from '../../telemetry';
2222import { EventName } from '../../telemetry/constants' ;
2323import { TestProvider } from '../types' ;
2424import {
25+ clearAllChildren ,
2526 createErrorTestItem ,
2627 DebugTestTag ,
2728 ErrorTestItemOptions ,
@@ -135,8 +136,11 @@ export class WorkspaceTestAdapter {
135136 }
136137
137138 if ( rawTestExecData !== undefined && rawTestExecData . result !== undefined ) {
139+ // Map which holds the subtest information for each test item.
140+ const subTestStats : Map < string , { passed : number ; failed : number } > = new Map ( ) ;
141+
142+ // iterate through payload and update the UI accordingly.
138143 for ( const keyTemp of Object . keys ( rawTestExecData . result ) ) {
139- // check for result and update the UI accordingly.
140144 const testCases : TestItem [ ] = [ ] ;
141145
142146 // grab leaf level test items
@@ -147,7 +151,6 @@ export class WorkspaceTestAdapter {
147151
148152 if (
149153 rawTestExecData . result [ keyTemp ] . outcome === 'failure' ||
150- rawTestExecData . result [ keyTemp ] . outcome === 'subtest-failure' ||
151154 rawTestExecData . result [ keyTemp ] . outcome === 'passed-unexpected'
152155 ) {
153156 const rawTraceback = rawTestExecData . result [ keyTemp ] . traceback ?? '' ;
@@ -175,8 +178,7 @@ export class WorkspaceTestAdapter {
175178 } ) ;
176179 } else if (
177180 rawTestExecData . result [ keyTemp ] . outcome === 'success' ||
178- rawTestExecData . result [ keyTemp ] . outcome === 'expected-failure' ||
179- rawTestExecData . result [ keyTemp ] . outcome === 'subtest-passed'
181+ rawTestExecData . result [ keyTemp ] . outcome === 'expected-failure'
180182 ) {
181183 const grabTestItem = this . runIdToTestItem . get ( keyTemp ) ;
182184 const grabVSid = this . runIdToVSid . get ( keyTemp ) ;
@@ -203,6 +205,73 @@ export class WorkspaceTestAdapter {
203205 }
204206 } ) ;
205207 }
208+ } else if ( rawTestExecData . result [ keyTemp ] . outcome === 'subtest-failure' ) {
209+ // split on " " since the subtest ID has the parent test ID in the first part of the ID.
210+ const parentTestCaseId = keyTemp . split ( ' ' ) [ 0 ] ;
211+ const parentTestItem = this . runIdToTestItem . get ( parentTestCaseId ) ;
212+ const data = rawTestExecData . result [ keyTemp ] ;
213+ // find the subtest's parent test item
214+ if ( parentTestItem ) {
215+ const subtestStats = subTestStats . get ( parentTestCaseId ) ;
216+ if ( subtestStats ) {
217+ subtestStats . failed += 1 ;
218+ } else {
219+ subTestStats . set ( parentTestCaseId , { failed : 1 , passed : 0 } ) ;
220+ runInstance . appendOutput ( fixLogLines ( `${ parentTestCaseId } [subtests]:\r\n` ) ) ;
221+ // clear since subtest items don't persist between runs
222+ clearAllChildren ( parentTestItem ) ;
223+ }
224+ const subtestId = keyTemp ;
225+ const subTestItem = testController ?. createTestItem ( subtestId , subtestId ) ;
226+ runInstance . appendOutput ( fixLogLines ( `${ subtestId } Failed\r\n` ) ) ;
227+ // create a new test item for the subtest
228+ if ( subTestItem ) {
229+ const traceback = data . traceback ?? '' ;
230+ const text = `${ data . subtest } Failed: ${ data . message ?? data . outcome } \r\n${ traceback } \r\n` ;
231+ runInstance . appendOutput ( fixLogLines ( text ) ) ;
232+ parentTestItem . children . add ( subTestItem ) ;
233+ runInstance . started ( subTestItem ) ;
234+ const message = new TestMessage ( rawTestExecData ?. result [ keyTemp ] . message ?? '' ) ;
235+ if ( parentTestItem . uri && parentTestItem . range ) {
236+ message . location = new Location ( parentTestItem . uri , parentTestItem . range ) ;
237+ }
238+ runInstance . failed ( subTestItem , message ) ;
239+ } else {
240+ throw new Error ( 'Unable to create new child node for subtest' ) ;
241+ }
242+ } else {
243+ throw new Error ( 'Parent test item not found' ) ;
244+ }
245+ } else if ( rawTestExecData . result [ keyTemp ] . outcome === 'subtest-success' ) {
246+ // split on " " since the subtest ID has the parent test ID in the first part of the ID.
247+ const parentTestCaseId = keyTemp . split ( ' ' ) [ 0 ] ;
248+ const parentTestItem = this . runIdToTestItem . get ( parentTestCaseId ) ;
249+
250+ // find the subtest's parent test item
251+ if ( parentTestItem ) {
252+ const subtestStats = subTestStats . get ( parentTestCaseId ) ;
253+ if ( subtestStats ) {
254+ subtestStats . passed += 1 ;
255+ } else {
256+ subTestStats . set ( parentTestCaseId , { failed : 0 , passed : 1 } ) ;
257+ runInstance . appendOutput ( fixLogLines ( `${ parentTestCaseId } [subtests]:\r\n` ) ) ;
258+ // clear since subtest items don't persist between runs
259+ clearAllChildren ( parentTestItem ) ;
260+ }
261+ const subtestId = keyTemp ;
262+ const subTestItem = testController ?. createTestItem ( subtestId , subtestId ) ;
263+ // create a new test item for the subtest
264+ if ( subTestItem ) {
265+ parentTestItem . children . add ( subTestItem ) ;
266+ runInstance . started ( subTestItem ) ;
267+ runInstance . passed ( subTestItem ) ;
268+ runInstance . appendOutput ( fixLogLines ( `${ subtestId } Passed\r\n` ) ) ;
269+ } else {
270+ throw new Error ( 'Unable to create new child node for subtest' ) ;
271+ }
272+ } else {
273+ throw new Error ( 'Parent test item not found' ) ;
274+ }
206275 }
207276 }
208277 }
0 commit comments