1
- import { promises as fs } from 'node:fs'
2
- import mm from 'micromatch'
3
1
import type { VitestRunner , VitestRunnerConstructor } from '@vitest/runner'
4
2
import { startTests } from '@vitest/runner'
5
3
import { resolve } from 'pathe'
6
- import type { EnvironmentOptions , ResolvedConfig , VitestEnvironment } from '../types'
4
+ import type { ResolvedConfig , WorkerTestEnvironment } from '../types'
7
5
import { getWorkerState , resetModules } from '../utils'
8
6
import { vi } from '../integrations/vi'
9
- import { envs } from '../integrations/env'
10
7
import { distDir } from '../constants'
11
8
import { startCoverageInsideWorker , stopCoverageInsideWorker , takeCoverageInsideWorker } from '../integrations/coverage'
12
9
import { setupGlobalEnv , withEnv } from './setup.node'
@@ -15,15 +12,6 @@ import type { VitestExecutor } from './execute'
15
12
16
13
const runnersFile = resolve ( distDir , 'runners.js' )
17
14
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
-
27
15
async function getTestRunnerConstructor ( config : ResolvedConfig , executor : VitestExecutor ) : Promise < VitestRunnerConstructor > {
28
16
if ( ! config . runner ) {
29
17
const { VitestTestRunner, NodeBenchmarkRunner } = await executor . executeFile ( runnersFile )
@@ -77,89 +65,39 @@ async function getTestRunner(config: ResolvedConfig, executor: VitestExecutor):
77
65
}
78
66
79
67
// 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 > {
81
69
await setupGlobalEnv ( config )
82
70
await startCoverageInsideWorker ( config . coverage , executor )
83
71
84
72
const workerState = getWorkerState ( )
85
73
86
74
const runner = await getTestRunner ( config , executor )
87
75
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 )
102
87
}
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
127
88
128
- // @ts -expect-error untyped global
129
- globalThis . __vitest_environment__ = environment
89
+ workerState . filepath = file
130
90
131
- const filesByOptions = groupBy ( files , ( { envOptions } ) => JSON . stringify ( envOptions ) )
91
+ await startTests ( [ file ] , runner )
132
92
133
- for ( const options of Object . keys ( filesByOptions ) ) {
134
- const files = filesByOptions [ options ]
93
+ workerState . filepath = undefined
135
94
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 ( )
161
99
}
162
- }
163
100
164
- await stopCoverageInsideWorker ( config . coverage , executor )
101
+ await stopCoverageInsideWorker ( config . coverage , executor )
102
+ } )
165
103
}
0 commit comments