Skip to content

Commit 3e1429e

Browse files
authoredJan 19, 2023
feat: new environmentMatchGlobs option to auto infer env based on glob (#2714)
1 parent da7e8d5 commit 3e1429e

File tree

11 files changed

+107
-14
lines changed

11 files changed

+107
-14
lines changed
 

‎packages/vitest/src/node/config.ts

+2
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,8 @@ export function resolveConfig(
239239
...resolved.typecheck,
240240
}
241241

242+
resolved.environmentMatchGlobs = (resolved.environmentMatchGlobs || []).map(i => [resolve(resolved.root, i[0]), i[1]])
243+
242244
if (mode === 'typecheck') {
243245
resolved.include = resolved.typecheck.include
244246
resolved.exclude = resolved.typecheck.exclude

‎packages/vitest/src/runtime/entry.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { promises as fs } from 'node:fs'
2+
import mm from 'micromatch'
23
import type { EnvironmentOptions, ResolvedConfig, VitestEnvironment } from '../types'
34
import { getWorkerState, resetModules } from '../utils'
45
import { vi } from '../integrations/vi'
@@ -31,7 +32,21 @@ export async function run(files: string[], config: ResolvedConfig): Promise<void
3132
// if calling with no-threads, this will be the whole suite
3233
const filesWithEnv = await Promise.all(files.map(async (file) => {
3334
const code = await fs.readFile(file, 'utf-8')
34-
const env = code.match(/@(?:vitest|jest)-environment\s+?([\w-]+)\b/)?.[1] || config.environment || 'node'
35+
36+
// 1. Check for control comments in the file
37+
let env = code.match(/@(?:vitest|jest)-environment\s+?([\w-]+)\b/)?.[1]
38+
// 2. Check for globals
39+
if (!env) {
40+
for (const [glob, target] of config.environmentMatchGlobs || []) {
41+
if (mm.isMatch(file, glob)) {
42+
env = target
43+
break
44+
}
45+
}
46+
}
47+
// 3. Fallback to global env
48+
env ||= config.environment || 'node'
49+
3550
const envOptions = JSON.parse(code.match(/@(?:vitest|jest)-environment-options\s+?(.+)/)?.[1] || 'null')
3651
return {
3752
file,

‎packages/vitest/src/runtime/setup.ts

+6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { clearTimeout, getWorkerState, isNode, setTimeout, toArray } from '../ut
77
import * as VitestIndex from '../index'
88
import { resetRunOnceCounter } from '../integrations/run-once'
99
import { RealDate } from '../integrations/mock/date'
10+
import { expect } from '../integrations/chai'
1011
import { rpc } from './rpc'
1112

1213
let globalSetup = false
@@ -180,6 +181,11 @@ export async function withEnv(
180181
fn: () => Promise<void>,
181182
) {
182183
const config: Environment = (environments as any)[name] || await loadEnvironment(name)
184+
// @ts-expect-error untyped global
185+
globalThis.__vitest_environment__ = config.name || name
186+
expect.setState({
187+
environment: config.name || name || 'node',
188+
})
183189
const env = await config.setup(globalThis, options)
184190
try {
185191
await fn()

‎packages/vitest/src/types/config.ts

+16
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ export interface InlineConfig {
138138
*/
139139
environmentOptions?: EnvironmentOptions
140140

141+
/**
142+
* Automatically assign environment based on globs. The first match will be used.
143+
*
144+
* Format: [glob, environment-name]
145+
*
146+
* @default []
147+
* @example [
148+
* // all tests in tests/dom will run in jsdom
149+
* ['tests/dom/**', 'jsdom'],
150+
* // all tests in tests/ with .edge.test.ts will run in edge-runtime
151+
* ['**\/*.edge.test.ts', 'edge-runtime'],
152+
* // ...
153+
* ]
154+
*/
155+
environmentMatchGlobs?: [string, VitestEnvironment][]
156+
141157
/**
142158
* Update snapshot
143159
*

‎pnpm-lock.yaml

+19-13
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎test/env-glob/package.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "@vitest/test-env-glob",
3+
"private": true,
4+
"scripts": {
5+
"test": "vitest",
6+
"coverage": "vitest run --coverage"
7+
},
8+
"devDependencies": {
9+
"vitest": "workspace:*"
10+
}
11+
}

‎test/env-glob/test/base.dom.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('glob on extension', () => {
4+
expect(typeof window).not.toBe('undefined')
5+
expect(expect.getState().environment).toBe('happy-dom')
6+
})

‎test/env-glob/test/base.test.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('default', () => {
4+
expect(typeof window).toBe('undefined')
5+
expect(expect.getState().environment).toBe('node')
6+
})

‎test/env-glob/test/dom/base.spec.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { expect, test } from 'vitest'
2+
3+
test('glob on folder', () => {
4+
expect(typeof window).not.toBe('undefined')
5+
expect(expect.getState().environment).toBe('jsdom')
6+
})
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { expect, test } from 'vitest'
2+
3+
/**
4+
* @vitest-environment edge-runtime
5+
*/
6+
7+
test('glob on folder overrides', () => {
8+
expect(expect.getState().environment).toBe('edge-runtime')
9+
})

‎test/env-glob/vitest.config.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { defineConfig } from 'vitest/config'
2+
3+
export default defineConfig({
4+
test: {
5+
environmentMatchGlobs: [
6+
['**/*.dom.test.ts', 'happy-dom'],
7+
['test/dom/**', 'jsdom'],
8+
],
9+
},
10+
})

0 commit comments

Comments
 (0)
Please sign in to comment.