77 */
88
99import { createRequire } from 'node:module' ;
10- import type { BrowserBuiltinProvider , BrowserConfigOptions } from 'vitest/node' ;
10+ import type {
11+ BrowserBuiltinProvider ,
12+ BrowserConfigOptions ,
13+ BrowserProviderOption ,
14+ } from 'vitest/node' ;
1115import { assertIsError } from '../../../../utils/error' ;
1216
1317export interface BrowserConfiguration {
@@ -40,7 +44,7 @@ function findBrowserProvider(
4044export interface BrowserInstanceConfiguration {
4145 browser : string ;
4246 headless : boolean ;
43- provider ?: import ( 'vitest/node' ) . BrowserProviderOption ;
47+ provider ?: BrowserProviderOption ;
4448}
4549
4650function normalizeBrowserName ( browserName : string ) : BrowserInstanceConfiguration {
@@ -56,6 +60,67 @@ function normalizeBrowserName(browserName: string): BrowserInstanceConfiguration
5660 } ;
5761}
5862
63+ /**
64+ * Mutates the provided browser instances to apply standard headless execution
65+ * constraints based on the chosen provider, user options, and CI environment presence.
66+ *
67+ * @param instances The normalized browser instances to mutate.
68+ * @param providerName The identifier for the chosen Vitest browser provider.
69+ * @param headless The user-provided headless configuration option.
70+ * @param isCI Whether the current environment is running in CI.
71+ * @returns An array of informational messages generated during evaluation.
72+ */
73+ export function applyHeadlessConfiguration (
74+ instances : BrowserInstanceConfiguration [ ] ,
75+ providerName : BrowserBuiltinProvider | undefined ,
76+ headless : boolean | undefined ,
77+ isCI : boolean ,
78+ ) : string [ ] {
79+ const messages : string [ ] = [ ] ;
80+
81+ if ( providerName === 'preview' ) {
82+ instances . forEach ( ( instance ) => {
83+ // Preview mode only supports headed execution
84+ instance . headless = false ;
85+ } ) ;
86+
87+ if ( headless ) {
88+ messages . push ( 'The "headless" option is ignored when using the "preview" provider.' ) ;
89+ }
90+ } else if ( headless !== undefined ) {
91+ if ( headless ) {
92+ const allHeadlessByDefault = isCI || instances . every ( ( i ) => i . headless ) ;
93+ if ( allHeadlessByDefault ) {
94+ messages . push (
95+ 'The "headless" option is unnecessary as all browsers are already configured to run in headless mode.' ,
96+ ) ;
97+ }
98+ }
99+
100+ instances . forEach ( ( instance ) => {
101+ instance . headless = headless ;
102+ } ) ;
103+ } else if ( isCI ) {
104+ instances . forEach ( ( instance ) => {
105+ instance . headless = true ;
106+ } ) ;
107+ }
108+
109+ return messages ;
110+ }
111+
112+ /**
113+ * Resolves and configures the Vitest browser provider for the unit test builder.
114+ * Dynamically discovers and imports the necessary provider (Playwright, WebdriverIO, or Preview),
115+ * maps the requested browser instances, and applies environment-specific execution logic.
116+ *
117+ * @param browsers An array of requested browser names (e.g., 'chrome', 'firefox').
118+ * @param headless User-provided configuration for headless execution.
119+ * @param debug Whether the builder is running in watch or debug mode.
120+ * @param projectSourceRoot The root directory of the project being tested for resolving installed packages.
121+ * @param viewport Optional viewport dimensions to apply to the launched browser instances.
122+ * @returns A fully resolved Vitest browser configuration object alongside any generated warning or error messages.
123+ */
59124export async function setupBrowserConfiguration (
60125 browsers : string [ ] | undefined ,
61126 headless : boolean | undefined ,
@@ -149,35 +214,7 @@ export async function setupBrowserConfiguration(
149214 }
150215
151216 const isCI = ! ! process . env [ 'CI' ] ;
152- const messages : string [ ] = [ ] ;
153-
154- if ( providerName === 'preview' ) {
155- instances . forEach ( ( instance ) => {
156- // Preview mode only supports headed execution
157- instance . headless = false ;
158- } ) ;
159-
160- if ( headless ) {
161- messages . push ( 'The "headless" option is ignored when using the "preview" provider.' ) ;
162- }
163- } else if ( headless !== undefined ) {
164- if ( headless ) {
165- const allHeadlessByDefault = isCI || instances . every ( ( i ) => i . headless ) ;
166- if ( allHeadlessByDefault ) {
167- messages . push (
168- 'The "headless" option is unnecessary as all browsers are already configured to run in headless mode.' ,
169- ) ;
170- }
171- }
172-
173- instances . forEach ( ( instance ) => {
174- instance . headless = headless ;
175- } ) ;
176- } else if ( isCI ) {
177- instances . forEach ( ( instance ) => {
178- instance . headless = true ;
179- } ) ;
180- }
217+ const messages = applyHeadlessConfiguration ( instances , providerName , headless , isCI ) ;
181218
182219 const browser = {
183220 enabled : true ,
0 commit comments