@@ -688,24 +688,35 @@ export class TestRunner {
688
688
}
689
689
}
690
690
691
+ const compositeToken = new CompositeCancellationToken ( token ) ;
692
+
691
693
// Create a cancellation token source for this test run
692
- const compositeToken = new CompositeCancellationTokenSource ( token ) ;
694
+ const compositeTokenSource = new CompositeCancellationTokenSource ( token ) ;
693
695
694
696
// Create and run the test runner
695
697
const runner = new TestRunner (
696
698
testKind ,
697
699
request ,
698
700
folderContext ,
699
701
controller ,
700
- compositeToken . token
702
+ compositeTokenSource . token
701
703
) ;
702
704
703
705
// If the user terminates a debugging session for swift-testing
704
706
// 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
+ ) ;
706
717
707
718
// Register the test run with the manager
708
- folderContext . registerTestRun ( runner . testRun , compositeToken ) ;
719
+ folderContext . registerTestRun ( runner . testRun , compositeTokenSource ) ;
709
720
710
721
// Fire the event to notify that a test run was created
711
722
onCreateTestRun . fire ( runner . testRun ) ;
@@ -714,6 +725,7 @@ export class TestRunner {
714
725
await runner . runHandler ( ) ;
715
726
716
727
terminationListener . dispose ( ) ;
728
+ cancellationListener . dispose ( ) ;
717
729
718
730
// Run the post-run handler if provided
719
731
if ( postRunHandler ) {
@@ -749,13 +761,18 @@ export class TestRunner {
749
761
750
762
const runState = new TestRunnerTestRunState ( this . testRun ) ;
751
763
752
- const cancellationDisposable = this . testRun . token . onCancellationRequested ( ( ) => {
753
- this . testRun . appendOutput ( "\r\nTest run cancelled." ) ;
754
- } ) ;
755
-
756
764
try {
757
765
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
+
758
773
await this . debugSession ( runState ) ;
774
+
775
+ cancellationDisposable . dispose ( ) ;
759
776
} else {
760
777
await this . runSession ( runState ) ;
761
778
}
@@ -769,7 +786,6 @@ export class TestRunner {
769
786
await this . testRun . computeCoverage ( ) ;
770
787
}
771
788
772
- cancellationDisposable . dispose ( ) ;
773
789
await this . testRun . end ( ) ;
774
790
775
791
this . workspaceContext . testsFinished ( this . folderContext , this . testKind , testTargets ) ;
0 commit comments