mirror of
https://github.com/vitest-dev/vitest.git
synced 2025-12-08 18:26:03 +00:00
refactor: rework runner env
This commit is contained in:
parent
113a416dd6
commit
d07f5b3a91
25
src/env/happy-dom.ts
vendored
Normal file
25
src/env/happy-dom.ts
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
import { Environment } from '../types'
|
||||
import { KEYS } from './jsdom-keys'
|
||||
|
||||
export default <Environment>({
|
||||
name: 'happy-dom',
|
||||
async setup(global) {
|
||||
const { Window } = await import('happy-dom')
|
||||
const win = new Window()
|
||||
|
||||
const keys = KEYS.concat(Object.getOwnPropertyNames(win))
|
||||
.filter(k => !k.startsWith('_'))
|
||||
.filter(k => !(k in global))
|
||||
|
||||
for (const key of keys)
|
||||
// @ts-expect-error
|
||||
global[key] = win[key]
|
||||
|
||||
return {
|
||||
teardown(global) {
|
||||
win.happyDOM.cancelAsync()
|
||||
keys.forEach(key => delete global[key])
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
9
src/env/index.ts
vendored
Normal file
9
src/env/index.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
import node from './node'
|
||||
import jsdom from './jsdom'
|
||||
import happy from './happy-dom'
|
||||
|
||||
export const environments = {
|
||||
node,
|
||||
jsdom,
|
||||
'happy-dom': happy,
|
||||
}
|
||||
30
src/env/jsdom.ts
vendored
Normal file
30
src/env/jsdom.ts
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
import { Environment } from '../types'
|
||||
import { KEYS } from './jsdom-keys'
|
||||
|
||||
export default <Environment>({
|
||||
name: 'jsdom',
|
||||
async setup(global) {
|
||||
const { JSDOM } = await import('jsdom')
|
||||
const dom = new JSDOM('<!DOCTYPE html>',
|
||||
{
|
||||
pretendToBeVisual: true,
|
||||
runScripts: 'dangerously',
|
||||
// TODO: options
|
||||
url: 'http://localhost:3000',
|
||||
},
|
||||
)
|
||||
|
||||
const keys = KEYS.concat(Object.getOwnPropertyNames(dom.window))
|
||||
.filter(k => !k.startsWith('_'))
|
||||
.filter(k => !(k in global))
|
||||
|
||||
for (const key of keys)
|
||||
global[key] = dom.window[key]
|
||||
|
||||
return {
|
||||
teardown(global) {
|
||||
keys.forEach(key => delete global[key])
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
11
src/env/node.ts
vendored
Normal file
11
src/env/node.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import { Environment } from '../types'
|
||||
|
||||
export default <Environment>({
|
||||
name: 'node',
|
||||
async setup() {
|
||||
return {
|
||||
teardown() {
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
@ -1,22 +0,0 @@
|
||||
import { Window } from 'happy-dom'
|
||||
import { KEYS } from './keys'
|
||||
|
||||
export function setupHappyDOM(global: any) {
|
||||
const win = new Window()
|
||||
|
||||
const keys = KEYS.concat(Object.getOwnPropertyNames(win))
|
||||
.filter(k => !k.startsWith('_'))
|
||||
.filter(k => !(k in global))
|
||||
|
||||
for (const key of keys)
|
||||
// @ts-expect-error
|
||||
global[key] = win[key]
|
||||
|
||||
return {
|
||||
dom: win,
|
||||
restore() {
|
||||
win.happyDOM.cancelAsync()
|
||||
keys.forEach(key => delete global[key])
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
import { JSDOM } from 'jsdom'
|
||||
import { KEYS } from './keys'
|
||||
|
||||
export function setupJSDOM(global: any) {
|
||||
const dom = new JSDOM('<!DOCTYPE html>',
|
||||
{
|
||||
pretendToBeVisual: true,
|
||||
runScripts: 'dangerously',
|
||||
// TODO: options
|
||||
url: 'http://localhost:3000',
|
||||
},
|
||||
)
|
||||
|
||||
const keys = KEYS.concat(Object.getOwnPropertyNames(dom.window))
|
||||
.filter(k => !k.startsWith('_'))
|
||||
.filter(k => !(k in global))
|
||||
|
||||
for (const key of keys)
|
||||
global[key] = dom.window[key]
|
||||
|
||||
return {
|
||||
dom,
|
||||
restore() {
|
||||
keys.forEach(key => delete global[key])
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -18,13 +18,17 @@ sade('vitest [filter]', true)
|
||||
.option('-w, --watch', 'watch mode', false)
|
||||
.option('-u, --update', 'update snapshot', false)
|
||||
.option('--global', 'inject apis globally', false)
|
||||
.option('--dom', 'mock browser api using jsdom or happy-dom', '')
|
||||
.action(async(cliFilters, argv: CliOptions) => {
|
||||
.option('--dom', 'mock browser api happy-dom', false)
|
||||
.option('--environment', 'runner environment', '')
|
||||
.action(async(cliFilters, argv: CliOptions & { dom?: boolean }) => {
|
||||
process.env.VITEST = 'true'
|
||||
|
||||
console.log(c.magenta(c.bold('\nVitest is in closed beta exclusively for Sponsors')))
|
||||
console.log(c.yellow('Learn more at https://vitest.dev\n'))
|
||||
|
||||
if (argv.dom)
|
||||
argv.environment = 'happy-dom'
|
||||
|
||||
const { config, server } = await initViteServer({ ...argv, cliFilters })
|
||||
|
||||
const ctx = process.__vitest__ = {
|
||||
|
||||
@ -49,9 +49,10 @@ export async function initViteServer(options: CliOptions = {}) {
|
||||
|
||||
Object.assign(resolved, server.config.test)
|
||||
|
||||
resolved.depsInline = server.config.test?.deps?.inline || []
|
||||
resolved.depsExternal = server.config.test?.deps?.external || []
|
||||
resolved.depsInline = resolved.deps?.inline || []
|
||||
resolved.depsExternal = resolved.deps?.external || []
|
||||
|
||||
resolved.environment = resolved.environment || 'node'
|
||||
resolved.threads = resolved.threads ?? true
|
||||
resolved.interpretDefault = resolved.interpretDefault ?? true
|
||||
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
import { ResolvedConfig } from '../types'
|
||||
import { setupEnv } from './env'
|
||||
import { setupGlobalEnv, withEnv } from './env'
|
||||
import { startTests } from './run'
|
||||
|
||||
export async function run(files: string[], config: ResolvedConfig): Promise<void> {
|
||||
const restore = await setupEnv(config)
|
||||
await setupGlobalEnv(config)
|
||||
|
||||
await startTests(files)
|
||||
|
||||
restore?.()
|
||||
await withEnv(config.environment, () => startTests(files))
|
||||
}
|
||||
|
||||
@ -1,15 +1,20 @@
|
||||
import { environments } from '../env'
|
||||
import { setupChai } from '../integrations/chai/setup'
|
||||
import { ResolvedConfig } from '../types'
|
||||
|
||||
export async function setupEnv(config: ResolvedConfig) {
|
||||
export async function setupGlobalEnv(config: ResolvedConfig) {
|
||||
await setupChai()
|
||||
|
||||
if (config.global)
|
||||
(await import('../integrations/global')).registerApiGlobally()
|
||||
|
||||
// TODO: rework this
|
||||
if (config.dom === 'happy-dom')
|
||||
return (await import('../integrations/dom/happy-dom')).setupHappyDOM(globalThis).restore
|
||||
else if (config.dom)
|
||||
return (await import('../integrations/dom/jsdom')).setupJSDOM(globalThis).restore
|
||||
}
|
||||
|
||||
export async function withEnv(name: ResolvedConfig['environment'], fn: () => Promise<void>) {
|
||||
const env = await environments[name].setup(globalThis)
|
||||
try {
|
||||
await fn()
|
||||
}
|
||||
finally {
|
||||
await env.teardown(globalThis)
|
||||
}
|
||||
}
|
||||
|
||||
33
src/types.ts
33
src/types.ts
@ -50,11 +50,13 @@ export interface UserOptions {
|
||||
global?: boolean
|
||||
|
||||
/**
|
||||
* Use `jsdom` or `happy-dom` to mock browser APIs
|
||||
* Running environment
|
||||
*
|
||||
* @default false
|
||||
* Supports 'node', 'jsdom', 'happy-dom'
|
||||
*
|
||||
* @default 'node'
|
||||
*/
|
||||
dom?: boolean | 'jsdom' | 'happy-dom'
|
||||
environment?: 'node' | 'jsdom' | 'happy-dom'
|
||||
|
||||
/**
|
||||
* Update snapshot files
|
||||
@ -253,6 +255,15 @@ export interface ModuleCache {
|
||||
transformResult?: TransformResult
|
||||
}
|
||||
|
||||
export interface EnvironmentReturn {
|
||||
teardown: (global: any) => Awaitable<void>
|
||||
}
|
||||
|
||||
export interface Environment {
|
||||
name: string
|
||||
setup(global: any): Awaitable<EnvironmentReturn>
|
||||
}
|
||||
|
||||
export interface WorkerContext {
|
||||
port: MessagePort
|
||||
config: ResolvedConfig
|
||||
@ -260,6 +271,14 @@ export interface WorkerContext {
|
||||
invalidates?: string[]
|
||||
}
|
||||
|
||||
export interface VitestContext {
|
||||
config: ResolvedConfig
|
||||
server: ViteDevServer
|
||||
state: StateManager
|
||||
snapshot: SnapshotManager
|
||||
reporter: Reporter
|
||||
}
|
||||
|
||||
export interface RpcMap {
|
||||
workerReady: [[], void]
|
||||
fetch: [[id: string], TransformResult | null | undefined]
|
||||
@ -277,11 +296,3 @@ export type RpcCall = <T extends keyof RpcMap>(method: T, ...args: RpcMap[T][0])
|
||||
export type RpcSend = <T extends keyof RpcMap>(method: T, ...args: RpcMap[T][0]) => void
|
||||
|
||||
export type RpcPayload<T extends keyof RpcMap = keyof RpcMap> = { id: string; method: T; args: RpcMap[T][0] }
|
||||
|
||||
export interface VitestContext {
|
||||
config: ResolvedConfig
|
||||
server: ViteDevServer
|
||||
state: StateManager
|
||||
snapshot: SnapshotManager
|
||||
reporter: Reporter
|
||||
}
|
||||
|
||||
@ -6,6 +6,6 @@ import { defineConfig } from 'vite'
|
||||
export default defineConfig({
|
||||
test: {
|
||||
global: true,
|
||||
dom: 'happy-dom',
|
||||
environment: 'happy-dom',
|
||||
},
|
||||
})
|
||||
|
||||
@ -5,6 +5,6 @@ import { defineConfig } from 'vite'
|
||||
export default defineConfig({
|
||||
test: {
|
||||
global: true,
|
||||
dom: 'happy-dom',
|
||||
environment: 'happy-dom',
|
||||
},
|
||||
})
|
||||
|
||||
@ -7,6 +7,6 @@ export default defineConfig({
|
||||
],
|
||||
test: {
|
||||
global: true,
|
||||
dom: 'jsdom',
|
||||
environment: 'jsdom',
|
||||
},
|
||||
})
|
||||
|
||||
@ -9,6 +9,6 @@ export default defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
global: true,
|
||||
dom: 'happy-dom',
|
||||
environment: 'happy-dom',
|
||||
},
|
||||
})
|
||||
|
||||
@ -20,6 +20,6 @@ export default defineConfig({
|
||||
],
|
||||
test: {
|
||||
global: true,
|
||||
dom: 'happy-dom',
|
||||
environment: 'happy-dom',
|
||||
},
|
||||
})
|
||||
|
||||
@ -7,6 +7,6 @@ export default defineConfig({
|
||||
],
|
||||
test: {
|
||||
global: true,
|
||||
dom: 'jsdom',
|
||||
environment: 'happy-dom',
|
||||
},
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user