1- import { promises as fs } from 'node:fs'
2- import mm from 'micromatch'
31import type { VitestRunner , VitestRunnerConstructor } from '@vitest/runner'
42import { startTests } from '@vitest/runner'
53import { resolve } from 'pathe'
6- import type { EnvironmentOptions , ResolvedConfig , VitestEnvironment } from '../types'
4+ import type { ResolvedConfig , WorkerTestEnvironment } from '../types'
75import { getWorkerState , resetModules } from '../utils'
86import { vi } from '../integrations/vi'
9- import { envs } from '../integrations/env'
107import { distDir } from '../constants'
118import { startCoverageInsideWorker , stopCoverageInsideWorker , takeCoverageInsideWorker } from '../integrations/coverage'
129import { setupGlobalEnv , withEnv } from './setup.node'
@@ -15,15 +12,6 @@ import type { VitestExecutor } from './execute'
1512
1613const runnersFile = resolve ( distDir , 'runners.js' )
1714
18- function groupBy < T , K extends string | number | symbol > ( collection : T [ ] , iteratee : ( item : T ) => K ) {
19- return collection . reduce ( ( acc , item ) => {
20- const key = iteratee ( item )
21- acc [ key ] ||= [ ]
22- acc [ key ] . push ( item )
23- return acc
24- } , { } as Record < K , T [ ] > )
25- }
26-
2715async function getTestRunnerConstructor ( config : ResolvedConfig , executor : VitestExecutor ) : Promise < VitestRunnerConstructor > {
2816 if ( ! config . runner ) {
2917 const { VitestTestRunner, NodeBenchmarkRunner } = await executor . executeFile ( runnersFile )
@@ -77,89 +65,39 @@ async function getTestRunner(config: ResolvedConfig, executor: VitestExecutor):
7765}
7866
7967// browser shouldn't call this!
80- export async function run ( files : string [ ] , config : ResolvedConfig , executor : VitestExecutor ) : Promise < void > {
68+ export async function run ( files : string [ ] , config : ResolvedConfig , environment : WorkerTestEnvironment , executor : VitestExecutor ) : Promise < void > {
8169 await setupGlobalEnv ( config )
8270 await startCoverageInsideWorker ( config . coverage , executor )
8371
8472 const workerState = getWorkerState ( )
8573
8674 const runner = await getTestRunner ( config , executor )
8775
88- // if calling from a worker, there will always be one file
89- // if calling with no-threads, this will be the whole suite
90- const filesWithEnv = await Promise . all ( files . map ( async ( file ) => {
91- const code = await fs . readFile ( file , 'utf-8' )
92-
93- // 1. Check for control comments in the file
94- let env = code . match ( / @ (?: v i t e s t | j e s t ) - e n v i r o n m e n t \s + ?( [ \w - ] + ) \b / ) ?. [ 1 ]
95- // 2. Check for globals
96- if ( ! env ) {
97- for ( const [ glob , target ] of config . environmentMatchGlobs || [ ] ) {
98- if ( mm . isMatch ( file , glob ) ) {
99- env = target
100- break
101- }
76+ // @ts -expect-error untyped global
77+ globalThis . __vitest_environment__ = environment
78+
79+ await withEnv ( environment . name , environment . options || config . environmentOptions || { } , executor , async ( ) => {
80+ for ( const file of files ) {
81+ // it doesn't matter if running with --threads
82+ // if running with --no-threads, we usually want to reset everything before running a test
83+ // but we have --isolate option to disable this
84+ if ( config . isolate ) {
85+ workerState . mockMap . clear ( )
86+ resetModules ( workerState . moduleCache , true )
10287 }
103- }
104- // 3. Fallback to global env
105- env ||= config . environment || 'node'
106-
107- const envOptions = JSON . parse ( code . match ( / @ (?: v i t e s t | j e s t ) - e n v i r o n m e n t - o p t i o n s \s + ?( .+ ) / ) ?. [ 1 ] || 'null' )
108- return {
109- file,
110- env : env as VitestEnvironment ,
111- envOptions : envOptions ? { [ env ] : envOptions } as EnvironmentOptions : null ,
112- }
113- } ) )
114-
115- const filesByEnv = groupBy ( filesWithEnv , ( { env } ) => env )
116-
117- const orderedEnvs = envs . concat (
118- Object . keys ( filesByEnv ) . filter ( env => ! envs . includes ( env ) ) ,
119- )
120-
121- for ( const env of orderedEnvs ) {
122- const environment = env as VitestEnvironment
123- const files = filesByEnv [ environment ]
124-
125- if ( ! files || ! files . length )
126- continue
12788
128- // @ts -expect-error untyped global
129- globalThis . __vitest_environment__ = environment
89+ workerState . filepath = file
13090
131- const filesByOptions = groupBy ( files , ( { envOptions } ) => JSON . stringify ( envOptions ) )
91+ await startTests ( [ file ] , runner )
13292
133- for ( const options of Object . keys ( filesByOptions ) ) {
134- const files = filesByOptions [ options ]
93+ workerState . filepath = undefined
13594
136- if ( ! files || ! files . length )
137- continue
138-
139- await withEnv ( environment , files [ 0 ] . envOptions || config . environmentOptions || { } , executor , async ( ) => {
140- for ( const { file } of files ) {
141- // it doesn't matter if running with --threads
142- // if running with --no-threads, we usually want to reset everything before running a test
143- // but we have --isolate option to disable this
144- if ( config . isolate ) {
145- workerState . mockMap . clear ( )
146- resetModules ( workerState . moduleCache , true )
147- }
148-
149- workerState . filepath = file
150-
151- await startTests ( [ file ] , runner )
152-
153- workerState . filepath = undefined
154-
155- // reset after tests, because user might call `vi.setConfig` in setupFile
156- vi . resetConfig ( )
157- // mocks should not affect different files
158- vi . restoreAllMocks ( )
159- }
160- } )
95+ // reset after tests, because user might call `vi.setConfig` in setupFile
96+ vi . resetConfig ( )
97+ // mocks should not affect different files
98+ vi . restoreAllMocks ( )
16199 }
162- }
163100
164- await stopCoverageInsideWorker ( config . coverage , executor )
101+ await stopCoverageInsideWorker ( config . coverage , executor )
102+ } )
165103}
0 commit comments