@@ -10,13 +10,13 @@ import type { ProcessPool, WorkspaceSpec } from './pool'
10
10
import type { TestModule } from './reporters/reported-tasks'
11
11
import type { TestSpecification } from './spec'
12
12
import type { ResolvedConfig , TestProjectConfiguration , UserConfig , VitestRunMode } from './types/config'
13
- import type { CoverageProvider } from './types/coverage'
13
+ import type { CoverageProvider , ResolvedCoverageOptions } from './types/coverage'
14
14
import type { Reporter } from './types/reporter'
15
15
import type { TestRunResult } from './types/tests'
16
16
import os from 'node:os'
17
17
import { getTasks , hasFailed , limitConcurrency } from '@vitest/runner/utils'
18
18
import { SnapshotManager } from '@vitest/snapshot/manager'
19
- import { noop , toArray } from '@vitest/utils'
19
+ import { deepClone , deepMerge , noop , toArray } from '@vitest/utils'
20
20
import { normalize , relative } from 'pathe'
21
21
import { version } from '../../package.json' with { type : 'json' }
22
22
import { WebSocketReporter } from '../api/setup'
@@ -94,7 +94,6 @@ export class Vitest {
94
94
public readonly watcher : VitestWatcher
95
95
96
96
/** @internal */ configOverride : Partial < ResolvedConfig > = { }
97
- /** @internal */ coverageProvider : CoverageProvider | null | undefined
98
97
/** @internal */ filenamePattern ?: string [ ]
99
98
/** @internal */ runningPromise ?: Promise < TestRunResult >
100
99
/** @internal */ closingPromise ?: Promise < void >
@@ -117,6 +116,7 @@ export class Vitest {
117
116
private _state ?: StateManager
118
117
private _cache ?: VitestCache
119
118
private _snapshot ?: SnapshotManager
119
+ private _coverageProvider ?: CoverageProvider | null | undefined
120
120
121
121
constructor (
122
122
public readonly mode : VitestRunMode ,
@@ -209,10 +209,10 @@ export class Vitest {
209
209
this . pool = undefined
210
210
this . closingPromise = undefined
211
211
this . projects = [ ]
212
- this . coverageProvider = undefined
213
212
this . runningPromise = undefined
214
213
this . coreWorkspaceProject = undefined
215
214
this . specifications . clearCache ( )
215
+ this . _coverageProvider = undefined
216
216
this . _onUserTestsRerun = [ ]
217
217
218
218
this . _vite = server
@@ -312,6 +312,44 @@ export class Vitest {
312
312
await Promise . all ( this . _onSetServer . map ( fn => fn ( ) ) )
313
313
}
314
314
315
+ /** @internal */
316
+ get coverageProvider ( ) : CoverageProvider | null | undefined {
317
+ if ( this . configOverride . coverage ?. enabled === false ) {
318
+ return null
319
+ }
320
+ return this . _coverageProvider
321
+ }
322
+
323
+ public async enableCoverage ( ) : Promise < void > {
324
+ this . configOverride . coverage = { } as any
325
+ this . configOverride . coverage ! . enabled = true
326
+ await this . createCoverageProvider ( )
327
+ await this . coverageProvider ?. onEnabled ?.( )
328
+ }
329
+
330
+ public disableCoverage ( ) : void {
331
+ this . configOverride . coverage ??= { } as any
332
+ this . configOverride . coverage ! . enabled = false
333
+ }
334
+
335
+ private _coverageOverrideCache = new WeakMap < ResolvedCoverageOptions , ResolvedCoverageOptions > ( )
336
+
337
+ /** @internal */
338
+ get _coverageOptions ( ) : ResolvedCoverageOptions {
339
+ if ( ! this . configOverride . coverage ) {
340
+ return this . config . coverage
341
+ }
342
+ if ( ! this . _coverageOverrideCache . has ( this . configOverride . coverage ) ) {
343
+ const coverage = deepClone ( this . config . coverage )
344
+ const options = deepMerge ( coverage , this . configOverride . coverage )
345
+ this . _coverageOverrideCache . set (
346
+ this . configOverride . coverage ,
347
+ options ,
348
+ )
349
+ }
350
+ return this . _coverageOverrideCache . get ( this . configOverride . coverage ) !
351
+ }
352
+
315
353
/**
316
354
* Inject new test projects into the workspace.
317
355
* @param config Glob, config path or a custom config options.
@@ -399,12 +437,12 @@ export class Vitest {
399
437
* Creates a coverage provider if `coverage` is enabled in the config.
400
438
*/
401
439
public async createCoverageProvider ( ) : Promise < CoverageProvider | null > {
402
- if ( this . coverageProvider ) {
403
- return this . coverageProvider
440
+ if ( this . _coverageProvider ) {
441
+ return this . _coverageProvider
404
442
}
405
443
const coverageProvider = await this . initCoverageProvider ( )
406
444
if ( coverageProvider ) {
407
- await coverageProvider . clean ( this . config . coverage . clean )
445
+ await coverageProvider . clean ( this . _coverageOptions . clean )
408
446
}
409
447
return coverageProvider || null
410
448
}
@@ -444,18 +482,21 @@ export class Vitest {
444
482
}
445
483
446
484
private async initCoverageProvider ( ) : Promise < CoverageProvider | null | undefined > {
447
- if ( this . coverageProvider !== undefined ) {
485
+ if ( this . _coverageProvider != null ) {
448
486
return
449
487
}
450
- this . coverageProvider = await getCoverageProvider (
451
- this . config . coverage as unknown as SerializedCoverageConfig ,
488
+ const coverageConfig = ( this . configOverride . coverage
489
+ ? this . getRootProject ( ) . serializedConfig . coverage
490
+ : this . config . coverage ) as unknown as SerializedCoverageConfig
491
+ this . _coverageProvider = await getCoverageProvider (
492
+ coverageConfig ,
452
493
this . runner ,
453
494
)
454
- if ( this . coverageProvider ) {
455
- await this . coverageProvider . initialize ( this )
456
- this . config . coverage = this . coverageProvider . resolveOptions ( )
495
+ if ( this . _coverageProvider ) {
496
+ await this . _coverageProvider . initialize ( this )
497
+ this . config . coverage = this . _coverageProvider . resolveOptions ( )
457
498
}
458
- return this . coverageProvider
499
+ return this . _coverageProvider
459
500
}
460
501
461
502
/**
@@ -553,7 +594,7 @@ export class Vitest {
553
594
async start ( filters ?: string [ ] ) : Promise < TestRunResult > {
554
595
try {
555
596
await this . initCoverageProvider ( )
556
- await this . coverageProvider ?. clean ( this . config . coverage . clean )
597
+ await this . coverageProvider ?. clean ( this . _coverageOptions . clean )
557
598
}
558
599
finally {
559
600
await this . report ( 'onInit' , this )
@@ -602,7 +643,7 @@ export class Vitest {
602
643
async init ( ) : Promise < void > {
603
644
try {
604
645
await this . initCoverageProvider ( )
605
- await this . coverageProvider ?. clean ( this . config . coverage . clean )
646
+ await this . coverageProvider ?. clean ( this . _coverageOptions . clean )
606
647
}
607
648
finally {
608
649
await this . report ( 'onInit' , this )
@@ -677,7 +718,6 @@ export class Vitest {
677
718
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
678
719
*/
679
720
public async rerunTestSpecifications ( specifications : TestSpecification [ ] , allTestsRun = false ) : Promise < TestRunResult > {
680
- this . configOverride . testNamePattern = undefined
681
721
const files = specifications . map ( spec => spec . moduleId )
682
722
await Promise . all ( [
683
723
this . report ( 'onWatcherRerun' , files , 'rerun test' ) ,
@@ -709,7 +749,7 @@ export class Vitest {
709
749
this . snapshot . clear ( )
710
750
this . state . clearErrors ( )
711
751
712
- if ( ! this . isFirstRun && this . config . coverage . cleanOnRerun ) {
752
+ if ( ! this . isFirstRun && this . _coverageOptions . cleanOnRerun ) {
713
753
await this . coverageProvider ?. clean ( )
714
754
}
715
755
@@ -1111,7 +1151,7 @@ export class Vitest {
1111
1151
if ( this . state . getCountOfFailedTests ( ) > 0 ) {
1112
1152
await this . coverageProvider ?. onTestFailure ?.( )
1113
1153
1114
- if ( ! this . config . coverage . reportOnFailure ) {
1154
+ if ( ! this . _coverageOptions . reportOnFailure ) {
1115
1155
return
1116
1156
}
1117
1157
}
0 commit comments