@@ -323,8 +323,17 @@ export class LogtalkTestsExplorerProvider implements Disposable {
323323 ) ;
324324 this . logger . debug ( 'Created test run' ) ;
325325
326+ // Open the Testing pane if configured to do so
327+ const testingSettings = workspace . getConfiguration ( 'testing' ) ;
328+ const autoOpenSetting = testingSettings . get < string > ( 'automaticallyOpenTestResults' , 'neverOpen' ) ;
329+ if ( autoOpenSetting === 'openOnTestStart' || autoOpenSetting === 'openExplorerOnTestStart' ) {
330+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
331+ }
332+
326333 // Track directories where tests were run for Allure report generation
327334 const testDirectories = new Set < string > ( ) ;
335+ // Track whether any tests failed for openOnTestFailure setting
336+ let hasFailures = false ;
328337
329338 try {
330339 // If no specific tests are selected, run all tests via the tester file
@@ -348,13 +357,18 @@ export class LogtalkTestsExplorerProvider implements Disposable {
348357 const resultsFilePath = path . join ( testerDir , '.vscode_test_results' ) ;
349358 if ( fs . existsSync ( resultsFilePath ) ) {
350359 this . logger . debug ( `Parsing results from: ${ resultsFilePath } ` ) ;
351- await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) ;
360+ hasFailures = await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) || hasFailures ;
352361 } else {
353362 this . logger . warn ( `Results file not found: ${ resultsFilePath } ` ) ;
354363 }
355364
356365 this . runAllureReportIfEnabled ( testDirectories ) ;
357366 testRun . end ( ) ;
367+
368+ // Open the Testing pane if there were failures and setting is configured to do so
369+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
370+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
371+ }
358372 return ;
359373 }
360374
@@ -379,14 +393,19 @@ export class LogtalkTestsExplorerProvider implements Disposable {
379393 const resultsFilePath = path . join ( testerDir , '.vscode_test_results' ) ;
380394 if ( fs . existsSync ( resultsFilePath ) ) {
381395 this . logger . debug ( `Parsing results from: ${ resultsFilePath } ` ) ;
382- await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) ;
396+ hasFailures = await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) || hasFailures ;
383397 } else {
384398 this . logger . warn ( `Results file not found: ${ resultsFilePath } ` ) ;
385399 }
386400 }
387401 }
388402 this . runAllureReportIfEnabled ( testDirectories ) ;
389403 testRun . end ( ) ;
404+
405+ // Open the Testing pane if there were failures and setting is configured to do so
406+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
407+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
408+ }
390409 return ;
391410 }
392411
@@ -412,7 +431,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
412431 const dirResultsFilePath = path . join ( testerDir , '.vscode_test_results' ) ;
413432 if ( fs . existsSync ( dirResultsFilePath ) ) {
414433 this . logger . debug ( `Parsing results from: ${ dirResultsFilePath } ` ) ;
415- await this . parseTestResultFile ( Uri . file ( dirResultsFilePath ) , testRun , withCoverage ) ;
434+ hasFailures = await this . parseTestResultFile ( Uri . file ( dirResultsFilePath ) , testRun , withCoverage ) || hasFailures ;
416435 } else {
417436 this . logger . warn ( `Results file not found: ${ dirResultsFilePath } ` ) ;
418437 }
@@ -433,7 +452,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
433452 const dirResultsFilePath = path . join ( testerDir , '.vscode_test_results' ) ;
434453 if ( fs . existsSync ( dirResultsFilePath ) ) {
435454 this . logger . debug ( `Parsing results from: ${ dirResultsFilePath } ` ) ;
436- await this . parseTestResultFile ( Uri . file ( dirResultsFilePath ) , testRun , withCoverage ) ;
455+ hasFailures = await this . parseTestResultFile ( Uri . file ( dirResultsFilePath ) , testRun , withCoverage ) || hasFailures ;
437456 } else {
438457 this . logger . warn ( `Results file not found: ${ dirResultsFilePath } ` ) ;
439458 }
@@ -443,6 +462,11 @@ export class LogtalkTestsExplorerProvider implements Disposable {
443462
444463 this . runAllureReportIfEnabled ( testDirectories ) ;
445464 testRun . end ( ) ;
465+
466+ // Open the Testing pane if there were failures and setting is configured to do so
467+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
468+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
469+ }
446470 return ;
447471 }
448472
@@ -486,7 +510,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
486510 this . logger . debug ( `Looking for results file: ${ dirResultsFilePath } ` ) ;
487511 if ( fs . existsSync ( dirResultsFilePath ) ) {
488512 this . logger . debug ( `Parsing results from: ${ dirResultsFilePath } ` ) ;
489- await this . parseTestResultFile ( Uri . file ( dirResultsFilePath ) , testRun , withCoverage ) ;
513+ hasFailures = await this . parseTestResultFile ( Uri . file ( dirResultsFilePath ) , testRun , withCoverage ) || hasFailures ;
490514 } else {
491515 this . logger . warn ( `Results file not found: ${ dirResultsFilePath } ` ) ;
492516 }
@@ -500,7 +524,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
500524 // Parse results
501525 if ( fs . existsSync ( resultsFilePath ) ) {
502526 this . logger . debug ( `Parsing results from: ${ resultsFilePath } ` ) ;
503- await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) ;
527+ hasFailures = await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) || hasFailures ;
504528 }
505529 break ;
506530
@@ -512,7 +536,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
512536 // Parse results
513537 if ( fs . existsSync ( resultsFilePath ) ) {
514538 this . logger . debug ( `Parsing results from: ${ resultsFilePath } ` ) ;
515- await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) ;
539+ hasFailures = await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) || hasFailures ;
516540 }
517541 break ;
518542
@@ -524,7 +548,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
524548 // Parse results
525549 if ( fs . existsSync ( resultsFilePath ) ) {
526550 this . logger . debug ( `Parsing results from: ${ resultsFilePath } ` ) ;
527- await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) ;
551+ hasFailures = await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , withCoverage ) || hasFailures ;
528552 }
529553 break ;
530554 }
@@ -535,8 +559,17 @@ export class LogtalkTestsExplorerProvider implements Disposable {
535559
536560 this . runAllureReportIfEnabled ( testDirectories ) ;
537561 testRun . end ( ) ;
562+
563+ // Open the Testing pane if there were failures and setting is configured to do so
564+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
565+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
566+ }
538567 } catch ( error ) {
539568 this . logger . error ( 'Error in runTests:' , error ) ;
569+ // Open the Testing pane if there were failures and setting is configured to do so
570+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
571+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
572+ }
540573 this . runAllureReportIfEnabled ( testDirectories ) ;
541574 testRun . end ( ) ;
542575 }
@@ -560,6 +593,16 @@ export class LogtalkTestsExplorerProvider implements Disposable {
560593 ) ;
561594 this . logger . debug ( 'Created test run for testers' ) ;
562595
596+ // Open the Testing pane if configured to do so
597+ const testingSettings = workspace . getConfiguration ( 'testing' ) ;
598+ const autoOpenSetting = testingSettings . get < string > ( 'automaticallyOpenTestResults' , 'neverOpen' ) ;
599+ if ( autoOpenSetting === 'openOnTestStart' || autoOpenSetting === 'openExplorerOnTestStart' ) {
600+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
601+ }
602+
603+ // Track whether any tests failed for openOnTestFailure setting
604+ let hasFailures = false ;
605+
563606 try {
564607 // Get the workspace folder to run testers in
565608 let workspaceDir : string | undefined ;
@@ -580,13 +623,25 @@ export class LogtalkTestsExplorerProvider implements Disposable {
580623 this . testsReporter ,
581624 async ( dir : string ) => {
582625 // After testers complete, parse xUnit XML files and update test explorer
583- await this . parseXUnitReportsInDirectory ( dir , testRun ) ;
626+ const failures = await this . parseXUnitReportsInDirectory ( dir , testRun ) ;
627+ if ( failures ) {
628+ hasFailures = true ;
629+ }
584630 }
585631 ) ;
586632
587633 testRun . end ( ) ;
634+
635+ // Open the Testing pane if there were failures and setting is configured to do so
636+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
637+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
638+ }
588639 } catch ( error ) {
589640 this . logger . error ( 'Error in runTestsWithTesters:' , error ) ;
641+ // Open the Testing pane if there were failures and setting is configured to do so
642+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
643+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
644+ }
590645 testRun . end ( ) ;
591646 }
592647 }
@@ -608,9 +663,21 @@ export class LogtalkTestsExplorerProvider implements Disposable {
608663 true // persist = true for "Rerun Last Run" functionality
609664 ) ;
610665
666+ // Open the Testing pane if configured to do so
667+ const testingSettings = workspace . getConfiguration ( 'testing' ) ;
668+ const autoOpenSetting = testingSettings . get < string > ( 'automaticallyOpenTestResults' , 'neverOpen' ) ;
669+ if ( autoOpenSetting === 'openOnTestStart' || autoOpenSetting === 'openExplorerOnTestStart' ) {
670+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
671+ }
672+
611673 try {
612- await this . parseXUnitReportsInDirectory ( dir , testRun ) ;
674+ const hasFailures = await this . parseXUnitReportsInDirectory ( dir , testRun ) ;
613675 testRun . end ( ) ;
676+
677+ // Open the Testing pane if there were failures and setting is configured to do so
678+ if ( hasFailures && autoOpenSetting === 'openOnTestFailure' ) {
679+ await commands . executeCommand ( 'workbench.view.extension.test' ) ;
680+ }
614681 } catch ( error ) {
615682 this . logger . error ( 'Error updating from project testers:' , error ) ;
616683 testRun . end ( ) ;
@@ -622,7 +689,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
622689 * @param dir - The directory to search for xunit_report.xml files
623690 * @param testRun - Optional test run to update with results
624691 */
625- private async parseXUnitReportsInDirectory ( dir : string , testRun ?: TestRun ) : Promise < void > {
692+ private async parseXUnitReportsInDirectory ( dir : string , testRun ?: TestRun ) : Promise < boolean > {
626693 this . logger . debug ( `Parsing xUnit reports in directory: ${ dir } ` ) ;
627694
628695 // Find all xunit_report.xml files recursively in the directory
@@ -631,19 +698,22 @@ export class LogtalkTestsExplorerProvider implements Disposable {
631698
632699 this . logger . debug ( `Found ${ files . length } xUnit report files` ) ;
633700
701+ let hasFailures = false ;
634702 for ( const file of files ) {
635- await this . parseXUnitReportFile ( file , testRun ) ;
703+ hasFailures = await this . parseXUnitReportFile ( file , testRun ) || hasFailures ;
636704 }
705+ return hasFailures ;
637706 }
638707
639708 /**
640709 * Parse a single xUnit XML report file and create/update test items
641710 * @param uri - URI of the xunit_report.xml file
642711 * @param testRun - Optional test run to update with results
712+ * @returns true if there were any failed tests, false otherwise
643713 */
644- private async parseXUnitReportFile ( uri : Uri , testRun ?: TestRun ) : Promise < void > {
714+ private async parseXUnitReportFile ( uri : Uri , testRun ?: TestRun ) : Promise < boolean > {
645715 if ( ! fs . existsSync ( uri . fsPath ) ) {
646- return ;
716+ return false ;
647717 }
648718
649719 try {
@@ -655,7 +725,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
655725
656726 if ( testResults . length === 0 ) {
657727 this . logger . debug ( 'No test results found in xUnit report' ) ;
658- return ;
728+ return false ;
659729 }
660730
661731 // Get the directory containing the xunit_report.xml file
@@ -675,9 +745,11 @@ export class LogtalkTestsExplorerProvider implements Disposable {
675745 this . logger . debug ( `Wrote test results to: ${ resultsFilePath } ` ) ;
676746
677747 // Now parse the results file to update the test explorer
678- await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , false ) ;
748+ const failures = await this . parseTestResultFile ( Uri . file ( resultsFilePath ) , testRun , false ) ;
749+ return failures ;
679750 } catch ( error ) {
680751 this . logger . error ( `Error parsing xUnit report ${ uri . fsPath } :` , error ) ;
752+ return false ;
681753 }
682754 }
683755
@@ -833,7 +905,7 @@ export class LogtalkTestsExplorerProvider implements Disposable {
833905 * @param testRun - Optional test run to update with results. If not provided, a new test run will be created.
834906 * @param withCoverage - Whether to process and report coverage data (default: false)
835907 */
836- private async parseTestResultFile ( uri : Uri , testRun ?: TestRun , withCoverage : boolean = false ) : Promise < void > {
908+ private async parseTestResultFile ( uri : Uri , testRun ?: TestRun , withCoverage : boolean = false ) : Promise < boolean > {
837909 if ( ! fs . existsSync ( uri . fsPath ) ) {
838910 return ;
839911 }
@@ -942,8 +1014,13 @@ export class LogtalkTestsExplorerProvider implements Disposable {
9421014 await this . updateTestRunFromResults ( testResults , testRun ) ;
9431015 }
9441016 }
1017+
1018+ // Check if there were any failures
1019+ const hasFailures = testResults . some ( result => result . status . toLowerCase ( ) . startsWith ( 'failed' ) ) ;
1020+ return hasFailures ;
9451021 } catch ( error ) {
9461022 this . logger . error ( `Error parsing test results file ${ uri . fsPath } :` , error ) ;
1023+ return false ;
9471024 }
9481025 }
9491026
0 commit comments