@@ -69,6 +69,81 @@ async function findTestEnvironment(
6969 }
7070}
7171
72+ function determineCoverageProvider (
73+ browser : BrowserConfigOptions | undefined ,
74+ testConfig : InlineConfig | undefined ,
75+ optionsCoverageEnabled : boolean | undefined ,
76+ projectSourceRoot : string ,
77+ ) : 'istanbul' | 'v8' | 'custom' | undefined {
78+ let determinedProvider = testConfig ?. coverage ?. provider ;
79+ if ( ! determinedProvider && ( optionsCoverageEnabled || testConfig ?. coverage ?. enabled ) ) {
80+ const browsersToCheck = getBrowsersToCheck ( browser , testConfig ?. browser ) ;
81+
82+ const hasNonChromium = browsersToCheck . some (
83+ ( b ) => ! [ 'chrome' , 'chromium' , 'edge' ] . includes ( normalizeBrowserName ( b ) . browser ) ,
84+ ) ;
85+
86+ if ( hasNonChromium ) {
87+ determinedProvider = 'istanbul' ;
88+ } else {
89+ const projectRequire = createRequire ( projectSourceRoot + '/' ) ;
90+ const checkInstalled = ( pkg : string ) => {
91+ try {
92+ projectRequire . resolve ( pkg ) ;
93+
94+ return true ;
95+ } catch {
96+ return false ;
97+ }
98+ } ;
99+ const hasIstanbul = checkInstalled ( '@vitest/coverage-istanbul' ) ;
100+ const hasV8 = checkInstalled ( '@vitest/coverage-v8' ) ;
101+
102+ if ( hasIstanbul && ! hasV8 ) {
103+ determinedProvider = 'istanbul' ;
104+ } else {
105+ determinedProvider = 'v8' ;
106+ }
107+ }
108+ }
109+
110+ return determinedProvider ;
111+ }
112+
113+ function getBrowsersToCheck (
114+ browser : BrowserConfigOptions | undefined ,
115+ testConfigBrowser : BrowserConfigOptions | undefined ,
116+ ) : string [ ] {
117+ const browsersToCheck : string [ ] = [ ] ;
118+
119+ const cliBrowser = browser as CustomBrowserConfigOptions | undefined ;
120+ const userBrowser = testConfigBrowser as CustomBrowserConfigOptions | undefined ;
121+
122+ // 1. CLI options override the Vitest configuration completely.
123+ if ( cliBrowser ) {
124+ if ( cliBrowser . instances ) {
125+ browsersToCheck . push ( ...cliBrowser . instances . map ( ( i ) => i . browser ) ) ;
126+ }
127+ if ( cliBrowser . name ) {
128+ browsersToCheck . push ( cliBrowser . name ) ;
129+ }
130+
131+ return browsersToCheck ;
132+ }
133+
134+ // 2. Fall back to Vitest configuration ONLY if browser testing is enabled.
135+ if ( userBrowser && userBrowser . enabled !== false ) {
136+ if ( userBrowser . instances ) {
137+ browsersToCheck . push ( ...userBrowser . instances . map ( ( i ) => i . browser ) ) ;
138+ }
139+ if ( userBrowser . name ) {
140+ browsersToCheck . push ( userBrowser . name ) ;
141+ }
142+ }
143+
144+ return browsersToCheck ;
145+ }
146+
72147export async function createVitestConfigPlugin (
73148 options : VitestConfigPluginOptions ,
74149) : Promise < VitestPlugins [ 0 ] > {
@@ -89,6 +164,13 @@ export async function createVitestConfigPlugin(
89164 async config ( config ) {
90165 const testConfig = config . test ;
91166
167+ const determinedProvider = determineCoverageProvider (
168+ browser ,
169+ testConfig ,
170+ options . coverage . enabled ,
171+ projectSourceRoot ,
172+ ) ;
173+
92174 if ( reporters !== undefined ) {
93175 delete testConfig ?. reporters ;
94176 }
@@ -155,8 +237,8 @@ export async function createVitestConfigPlugin(
155237 ( browser || testConfig ?. browser ?. enabled ) &&
156238 ( options . coverage . enabled || testConfig ?. coverage ?. enabled )
157239 ) {
158- // Validate that enabled browsers support V8 coverage
159- validateBrowserCoverage ( browser , testConfig ?. browser ) ;
240+ // Validate that enabled browsers support the selected coverage provider
241+ validateBrowserCoverage ( browser , testConfig ?. browser , determinedProvider ) ;
160242
161243 projectPlugins . unshift ( createSourcemapSupportPlugin ( ) ) ;
162244 setupFiles . unshift ( 'virtual:source-map-support' ) ;
@@ -208,6 +290,7 @@ export async function createVitestConfigPlugin(
208290 options . coverage ,
209291 testConfig ?. coverage ,
210292 projectName ,
293+ determinedProvider ,
211294 ) ,
212295 // eslint-disable-next-line @typescript-eslint/no-explicit-any
213296 ...( reporters ? ( { reporters } as any ) : { } ) ,
@@ -423,6 +506,7 @@ function createSourcemapSupportPlugin(): VitestPlugins[0] {
423506}
424507
425508interface CustomBrowserConfigOptions {
509+ enabled ?: boolean ;
426510 instances ?: { browser : string } [ ] ;
427511 name ?: string ;
428512}
@@ -434,25 +518,12 @@ interface CustomBrowserConfigOptions {
434518function validateBrowserCoverage (
435519 browser : BrowserConfigOptions | undefined ,
436520 testConfigBrowser : BrowserConfigOptions | undefined ,
521+ provider ?: string ,
437522) : void {
438- const browsersToCheck : string [ ] = [ ] ;
439-
440- // 1. Check browsers passed by the Angular CLI options
441- const cliBrowser = browser as CustomBrowserConfigOptions | undefined ;
442- if ( cliBrowser ?. instances ) {
443- browsersToCheck . push ( ...cliBrowser . instances . map ( ( i ) => i . browser ) ) ;
444- }
445-
446- // 2. Check browsers defined in the user's vitest.config.ts
447- const userBrowser = testConfigBrowser as CustomBrowserConfigOptions | undefined ;
448- if ( userBrowser ) {
449- if ( userBrowser . instances ) {
450- browsersToCheck . push ( ...userBrowser . instances . map ( ( i ) => i . browser ) ) ;
451- }
452- if ( userBrowser . name ) {
453- browsersToCheck . push ( userBrowser . name ) ;
454- }
523+ if ( provider === 'istanbul' ) {
524+ return ;
455525 }
526+ const browsersToCheck = getBrowsersToCheck ( browser , testConfigBrowser ) ;
456527
457528 // Normalize and filter unsupported browsers
458529 const unsupportedBrowsers = browsersToCheck
@@ -473,6 +544,7 @@ async function generateCoverageOption(
473544 optionsCoverage : NormalizedUnitTestBuilderOptions [ 'coverage' ] ,
474545 configCoverage : VitestCoverageOption | undefined ,
475546 projectName : string ,
547+ provider ?: 'istanbul' | 'v8' | 'custom' ,
476548) : Promise < VitestCoverageOption > {
477549 let defaultExcludes : string [ ] = [ ] ;
478550 // When a coverage exclude option is provided, Vitest's default coverage excludes
@@ -486,6 +558,7 @@ async function generateCoverageOption(
486558 }
487559
488560 return {
561+ provider,
489562 excludeAfterRemap : true ,
490563 reportsDirectory :
491564 configCoverage ?. reportsDirectory ?? toPosixPath ( path . join ( 'coverage' , projectName ) ) ,
0 commit comments