@@ -688,24 +688,35 @@ export class TestRunner {
688688 }
689689 }
690690
691+ const compositeToken = new CompositeCancellationToken ( token ) ;
692+
691693 // Create a cancellation token source for this test run
692- const compositeToken = new CompositeCancellationTokenSource ( token ) ;
694+ const compositeTokenSource = new CompositeCancellationTokenSource ( token ) ;
693695
694696 // Create and run the test runner
695697 const runner = new TestRunner (
696698 testKind ,
697699 request ,
698700 folderContext ,
699701 controller ,
700- compositeToken . token
702+ compositeTokenSource . token
701703 ) ;
702704
703705 // If the user terminates a debugging session for swift-testing
704706 // we want to prevent XCTest from starting.
705- const terminationListener = runner . onDebugSessionTerminated ( ( ) => compositeToken . cancel ( ) ) ;
707+ const terminationListener = runner . onDebugSessionTerminated ( ( ) =>
708+ compositeTokenSource . cancel ( )
709+ ) ;
710+
711+ // If the user cancels the test run via the VS Code UI, skip the pending tests
712+ // so they don't appear as failed. Any pending tests left over at the end of a run
713+ // are assumed to have crashed.
714+ const cancellationListener = compositeToken . onCancellationRequested ( ( ) =>
715+ runner . testRun . skipPendingTests ( )
716+ ) ;
706717
707718 // Register the test run with the manager
708- folderContext . registerTestRun ( runner . testRun , compositeToken ) ;
719+ folderContext . registerTestRun ( runner . testRun , compositeTokenSource ) ;
709720
710721 // Fire the event to notify that a test run was created
711722 onCreateTestRun . fire ( runner . testRun ) ;
@@ -714,6 +725,7 @@ export class TestRunner {
714725 await runner . runHandler ( ) ;
715726
716727 terminationListener . dispose ( ) ;
728+ cancellationListener . dispose ( ) ;
717729
718730 // Run the post-run handler if provided
719731 if ( postRunHandler ) {
@@ -749,13 +761,18 @@ export class TestRunner {
749761
750762 const runState = new TestRunnerTestRunState ( this . testRun ) ;
751763
752- const cancellationDisposable = this . testRun . token . onCancellationRequested ( ( ) => {
753- this . testRun . appendOutput ( "\r\nTest run cancelled." ) ;
754- } ) ;
755-
756764 try {
757765 if ( isDebugging ( this . testKind ) ) {
766+ // A cancellation error propagates up and is logged during a regular runSession,
767+ // however when the debugSession is cancelled no error is thrown, so we must log
768+ // the cancellation message here.
769+ const cancellationDisposable = this . testRun . token . onCancellationRequested ( ( ) => {
770+ this . testRun . appendOutput ( "\r\nTest run cancelled." ) ;
771+ } ) ;
772+
758773 await this . debugSession ( runState ) ;
774+
775+ cancellationDisposable . dispose ( ) ;
759776 } else {
760777 await this . runSession ( runState ) ;
761778 }
@@ -769,7 +786,6 @@ export class TestRunner {
769786 await this . testRun . computeCoverage ( ) ;
770787 }
771788
772- cancellationDisposable . dispose ( ) ;
773789 await this . testRun . end ( ) ;
774790
775791 this . workspaceContext . testsFinished ( this . folderContext , this . testKind , testTargets ) ;
0 commit comments