@@ -15,15 +15,17 @@ import type {
15
15
TaskUpdateEvent ,
16
16
Test ,
17
17
TestContext ,
18
+ WriteableTestContext ,
18
19
} from './types/tasks'
19
20
import { shuffle } from '@vitest/utils'
20
21
import { processError } from '@vitest/utils/error'
21
22
import { collectTests } from './collect'
22
- import { PendingError } from './errors'
23
+ import { abortContextSignal } from './context'
24
+ import { PendingError , TestRunAbortError } from './errors'
23
25
import { callFixtureCleanup } from './fixture'
24
26
import { getBeforeHookCleanupCallback } from './hooks'
25
27
import { getFn , getHooks } from './map'
26
- import { setCurrentTest } from './test-state'
28
+ import { addRunningTest , getRunningTests , setCurrentTest } from './test-state'
27
29
import { limitConcurrency } from './utils/limit-concurrency'
28
30
import { partitionSuiteChildren } from './utils/suite'
29
31
import { hasFailed , hasTests } from './utils/tasks'
@@ -87,12 +89,14 @@ async function callTestHooks(
87
89
return
88
90
}
89
91
92
+ const context = test . context as WriteableTestContext
93
+
90
94
const onTestFailed = test . context . onTestFailed
91
95
const onTestFinished = test . context . onTestFinished
92
- test . context . onTestFailed = ( ) => {
96
+ context . onTestFailed = ( ) => {
93
97
throw new Error ( `Cannot call "onTestFailed" inside a test hook.` )
94
98
}
95
- test . context . onTestFinished = ( ) => {
99
+ context . onTestFinished = ( ) => {
96
100
throw new Error ( `Cannot call "onTestFinished" inside a test hook.` )
97
101
}
98
102
@@ -115,8 +119,8 @@ async function callTestHooks(
115
119
}
116
120
}
117
121
118
- test . context . onTestFailed = onTestFailed
119
- test . context . onTestFinished = onTestFinished
122
+ context . onTestFailed = onTestFailed
123
+ context . onTestFinished = onTestFinished
120
124
}
121
125
122
126
export async function callSuiteHook < T extends keyof SuiteHooks > (
@@ -145,7 +149,11 @@ export async function callSuiteHook<T extends keyof SuiteHooks>(
145
149
}
146
150
147
151
async function runHook ( hook : Function ) {
148
- return getBeforeHookCleanupCallback ( hook , await hook ( ...args ) )
152
+ return getBeforeHookCleanupCallback (
153
+ hook ,
154
+ await hook ( ...args ) ,
155
+ name === 'beforeEach' ? args [ 0 ] : undefined ,
156
+ )
149
157
}
150
158
151
159
if ( sequence === 'parallel' ) {
@@ -274,6 +282,7 @@ export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
274
282
}
275
283
updateTask ( 'test-prepare' , test , runner )
276
284
285
+ const cleanupRunningTest = addRunningTest ( test )
277
286
setCurrentTest ( test )
278
287
279
288
const suite = test . suite || test . file
@@ -374,6 +383,7 @@ export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
374
383
}
375
384
updateTask ( 'test-finished' , test , runner )
376
385
setCurrentTest ( undefined )
386
+ cleanupRunningTest ( )
377
387
return
378
388
}
379
389
@@ -405,6 +415,7 @@ export async function runTest(test: Test, runner: VitestRunner): Promise<void> {
405
415
}
406
416
}
407
417
418
+ cleanupRunningTest ( )
408
419
setCurrentTest ( undefined )
409
420
410
421
test . result . duration = now ( ) - start
@@ -588,21 +599,38 @@ export async function runFiles(files: File[], runner: VitestRunner): Promise<voi
588
599
}
589
600
590
601
export async function startTests ( specs : string [ ] | FileSpecification [ ] , runner : VitestRunner ) : Promise < File [ ] > {
591
- const paths = specs . map ( f => typeof f === 'string' ? f : f . filepath )
592
- await runner . onBeforeCollect ?.( paths )
602
+ const cancel = runner . cancel ?. bind ( runner )
603
+ // Ideally, we need to have an event listener for this, but only have a runner here.
604
+ // Adding another onCancel felt wrong (maybe it needs to be refactored)
605
+ runner . cancel = ( reason ) => {
606
+ // We intentionally create only one error since there is only one test run that can be cancelled
607
+ const error = new TestRunAbortError ( 'The test run was aborted by the user.' , reason )
608
+ getRunningTests ( ) . forEach ( test =>
609
+ abortContextSignal ( test . context , error ) ,
610
+ )
611
+ return cancel ?.( reason )
612
+ }
593
613
594
- const files = await collectTests ( specs , runner )
614
+ try {
615
+ const paths = specs . map ( f => typeof f === 'string' ? f : f . filepath )
616
+ await runner . onBeforeCollect ?.( paths )
595
617
596
- await runner . onCollected ?.( files )
597
- await runner . onBeforeRunFiles ?.( files )
618
+ const files = await collectTests ( specs , runner )
598
619
599
- await runFiles ( files , runner )
620
+ await runner . onCollected ?.( files )
621
+ await runner . onBeforeRunFiles ?.( files )
600
622
601
- await runner . onAfterRunFiles ?. ( files )
623
+ await runFiles ( files , runner )
602
624
603
- await finishSendTasksUpdate ( runner )
625
+ await runner . onAfterRunFiles ?. ( files )
604
626
605
- return files
627
+ await finishSendTasksUpdate ( runner )
628
+
629
+ return files
630
+ }
631
+ finally {
632
+ runner . cancel = cancel
633
+ }
606
634
}
607
635
608
636
async function publicCollect ( specs : string [ ] | FileSpecification [ ] , runner : VitestRunner ) : Promise < File [ ] > {
0 commit comments