Skip to content

Commit

Permalink
chore: copy jest's node env
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed May 11, 2023
1 parent 4fc7d80 commit 7c0ad50
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 21 deletions.
3 changes: 0 additions & 3 deletions packages/vitest/src/integrations/env/happy-dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ export default <Environment>({
})

return {
getGlobal() {
return win.globalThis
},
getVmContext() {
return win
},
Expand Down
103 changes: 97 additions & 6 deletions packages/vitest/src/integrations/env/node.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,108 @@
import { Console } from 'node:console'
import { importModule } from 'local-pkg'
import type { Environment } from '../../types'

// some globals we do not want, either because deprecated or we set it ourselves
const denyList = new Set([
'GLOBAL',
'root',
'global',
'Buffer',
'ArrayBuffer',
'Uint8Array',
])

const nodeGlobals = new Map(
Object.getOwnPropertyNames(globalThis)
.filter(global => !denyList.has(global))
.map((nodeGlobalsKey) => {
const descriptor = Object.getOwnPropertyDescriptor(
globalThis,
nodeGlobalsKey,
)

if (!descriptor) {
throw new Error(
`No property descriptor for ${nodeGlobalsKey}, this is a bug in Jest.`,
)
}

return [nodeGlobalsKey, descriptor]
}),
)

export default <Environment>({
name: 'node',
// this is largely copied from jest's node environment
async setupVM() {
const vm = await importModule('node:vm')
const global = {} // TODO: copy more globals
const vm = await import('node:vm')
const context = vm.createContext()
const global = vm.runInContext(
'this',
context,
)

const contextGlobals = new Set(Object.getOwnPropertyNames(global))
for (const [nodeGlobalsKey, descriptor] of nodeGlobals) {
if (!contextGlobals.has(nodeGlobalsKey)) {
if (descriptor.configurable) {
Object.defineProperty(global, nodeGlobalsKey, {
configurable: true,
enumerable: descriptor.enumerable,
get() {
// @ts-expect-error: no index signature
const val = globalThis[nodeGlobalsKey] as unknown

// override lazy getter
Object.defineProperty(global, nodeGlobalsKey, {
configurable: true,
enumerable: descriptor.enumerable,
value: val,
writable:
descriptor.writable === true
// Node 19 makes performance non-readable. This is probably not the correct solution.
|| nodeGlobalsKey === 'performance',
})
return val
},
set(val: unknown) {
// override lazy getter
Object.defineProperty(global, nodeGlobalsKey, {
configurable: true,
enumerable: descriptor.enumerable,
value: val,
writable: true,
})
},
})
}
else if ('value' in descriptor) {
Object.defineProperty(global, nodeGlobalsKey, {
configurable: false,
enumerable: descriptor.enumerable,
value: descriptor.value,
writable: descriptor.writable,
})
}
else {
Object.defineProperty(global, nodeGlobalsKey, {
configurable: false,
enumerable: descriptor.enumerable,
get: descriptor.get,
set: descriptor.set,
})
}
}
}

global.global = global
global.Buffer = Buffer
global.ArrayBuffer = ArrayBuffer
// TextEncoder (global or via 'util') references a Uint8Array constructor
// different than the global one used by users in tests. This makes sure the
// same constructor is referenced by both.
global.Uint8Array = Uint8Array

return {
getGlobal() {
return global
},
getVmContext() {
return context
},
Expand Down
15 changes: 4 additions & 11 deletions packages/vitest/src/runtime/vm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { URL, pathToFileURL } from 'node:url'
import { pathToFileURL } from 'node:url'
import { performance } from 'node:perf_hooks'
import { ModuleCacheMap } from 'vite-node/client'
import { workerId as poolId } from 'tinypool'
import { createBirpc } from 'birpc'
Expand Down Expand Up @@ -64,17 +65,9 @@ export async function run(ctx: WorkerContext) {
const context = vm.getVmContext()

context.__vitest_worker__ = state
// TODO: all globals for test/core to work
// TODO: copy more globals
// this is unfortunately needed for our own dependencies
// we need to find a way to not rely on this by default
context.process = process
context.URL ??= URL
context.performance ??= performance
context.setImmediate = setImmediate
context.clearImmediate = clearImmediate
context.setTimeout = setTimeout
context.clearTimeout = clearTimeout
context.setInterval = setInterval
context.clearInterval = clearInterval
context.global = context
context.console = createCustomConsole(state)

Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/types/general.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface ModuleCache {
}

export interface EnvironmentReturn {
teardown: (global: any) => Awaitable<void>
teardown(global: any): Awaitable<void>
}

export interface VmEnvironmentReturn {
Expand Down

0 comments on commit 7c0ad50

Please sign in to comment.