mirror of
https://github.com/vitest-dev/vitest.git
synced 2026-02-01 17:36:51 +00:00
feat: support edge runtime (#1574)
* feat: add edge-runtime environment https://github.com/vercel/edge-runtime * chore: apply code review * chore: ci * chore: ci * chore: add @edge-runtime/vm to peerDependencies * chore: lint Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com> Co-authored-by: Vladimir Sheremet <sheremet.va@icloud.com>
This commit is contained in:
parent
4a95177356
commit
b947be48c3
@ -153,13 +153,14 @@ export default defineConfig({
|
||||
|
||||
### environment
|
||||
|
||||
- **Type:** `'node' | 'jsdom' | 'happy-dom'`
|
||||
- **Type:** `'node' | 'jsdom' | 'happy-dom' | 'edge-runtime'`
|
||||
- **Default:** `'node'`
|
||||
|
||||
The environment that will be used for testing. The default environment in Vitest
|
||||
is a Node.js environment. If you are building a web application, you can use
|
||||
browser-like environment through either [`jsdom`](https://github.com/jsdom/jsdom)
|
||||
or [`happy-dom`](https://github.com/capricorn86/happy-dom) instead.
|
||||
If you are building edge functions, you can use [`edge-runtime`](https://edge-runtime.vercel.app/packages/vm) environment
|
||||
|
||||
By adding a `@vitest-environment` docblock or comment at the top of the file,
|
||||
you can specify another environment to be used for all tests in that file:
|
||||
|
||||
@ -465,6 +465,13 @@ Repository: git://github.com/kpdecker/jsdiff.git
|
||||
|
||||
---------------------------------------
|
||||
|
||||
## eastasianwidth
|
||||
License: MIT
|
||||
By: Masaki Komagata
|
||||
Repository: git://github.com/komagata/eastasianwidth.git
|
||||
|
||||
---------------------------------------
|
||||
|
||||
## emoji-regex
|
||||
License: MIT
|
||||
By: Mathias Bynens
|
||||
|
||||
@ -62,6 +62,7 @@
|
||||
"prepublishOnly": "nr build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@edge-runtime/vm": "*",
|
||||
"@vitest/ui": "*",
|
||||
"c8": "*",
|
||||
"happy-dom": "*",
|
||||
@ -79,6 +80,9 @@
|
||||
},
|
||||
"jsdom": {
|
||||
"optional": true
|
||||
},
|
||||
"@edge-runtime/vm": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -94,6 +98,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@antfu/install-pkg": "^0.1.0",
|
||||
"@edge-runtime/vm": "1.1.0-beta.10",
|
||||
"@sinonjs/fake-timers": "^9.1.2",
|
||||
"@types/diff": "^5.0.2",
|
||||
"@types/jsdom": "^16.2.14",
|
||||
|
||||
24
packages/vitest/src/integrations/env/edge-runtime.ts
vendored
Normal file
24
packages/vitest/src/integrations/env/edge-runtime.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
import { importModule } from 'local-pkg'
|
||||
import type { Environment } from '../../types'
|
||||
import { populateGlobal } from './utils'
|
||||
|
||||
export default <Environment>({
|
||||
name: 'edge-runtime',
|
||||
async setup(global) {
|
||||
const { EdgeVM } = await importModule('@edge-runtime/vm') as typeof import('@edge-runtime/vm')
|
||||
const vm = new EdgeVM({
|
||||
extend: (context) => {
|
||||
context.global = context
|
||||
context.Buffer = Buffer
|
||||
return context
|
||||
},
|
||||
})
|
||||
const { keys, originals } = populateGlobal(global, vm.context, { bindFunctions: true })
|
||||
return {
|
||||
teardown(global) {
|
||||
keys.forEach(key => delete global[key])
|
||||
originals.forEach((v, k) => global[k] = v)
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
10
packages/vitest/src/integrations/env/index.ts
vendored
10
packages/vitest/src/integrations/env/index.ts
vendored
@ -1,9 +1,19 @@
|
||||
import node from './node'
|
||||
import jsdom from './jsdom'
|
||||
import happy from './happy-dom'
|
||||
import edge from './edge-runtime'
|
||||
|
||||
export const environments = {
|
||||
node,
|
||||
jsdom,
|
||||
'happy-dom': happy,
|
||||
'edge-runtime': edge,
|
||||
}
|
||||
|
||||
export const envs = Object.keys(environments)
|
||||
|
||||
export const envPackageNames: Record<Exclude<keyof typeof environments, 'node'>, string> = {
|
||||
'jsdom': 'jsdom',
|
||||
'happy-dom': 'happy-dom',
|
||||
'edge-runtime': '@edge-runtime/vm',
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import type { UserConfig as ViteUserConfig } from 'vite'
|
||||
import { envPackageNames } from '../integrations/env'
|
||||
import type { UserConfig } from '../types'
|
||||
import { ensurePackageInstalled } from '../utils'
|
||||
import { createVitest } from './create'
|
||||
@ -37,7 +38,8 @@ export async function startVitest(cliFilters: string[], options: CliOptions, vit
|
||||
}
|
||||
|
||||
if (ctx.config.environment && ctx.config.environment !== 'node') {
|
||||
if (!await ensurePackageInstalled(ctx.config.environment)) {
|
||||
const packageName = envPackageNames[ctx.config.environment]
|
||||
if (!await ensurePackageInstalled(packageName)) {
|
||||
process.exitCode = 1
|
||||
return false
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import type { BuiltinEnvironment, ResolvedConfig } from '../types'
|
||||
import { getWorkerState, resetModules } from '../utils'
|
||||
import { envs } from '../integrations/env'
|
||||
import { setupGlobalEnv, withEnv } from './setup'
|
||||
import { startTests } from './run'
|
||||
|
||||
@ -9,8 +10,6 @@ export async function run(files: string[], config: ResolvedConfig): Promise<void
|
||||
|
||||
const workerState = getWorkerState()
|
||||
|
||||
const envs = ['node', 'jsdom', 'happy-dom']
|
||||
|
||||
// if calling from a worker, there will always be one file
|
||||
// if calling with no-threads, this will be the whole suite
|
||||
const filesWithEnv = await Promise.all(files.map(async (file) => {
|
||||
|
||||
@ -8,7 +8,7 @@ import type { Reporter } from './reporter'
|
||||
import type { SnapshotStateOptions } from './snapshot'
|
||||
import type { Arrayable } from './general'
|
||||
|
||||
export type BuiltinEnvironment = 'node' | 'jsdom' | 'happy-dom'
|
||||
export type BuiltinEnvironment = 'node' | 'jsdom' | 'happy-dom' | 'edge-runtime'
|
||||
|
||||
export type ApiConfig = Pick<CommonServerOptions, 'port' | 'strictPort' | 'host'>
|
||||
|
||||
@ -98,7 +98,7 @@ export interface InlineConfig {
|
||||
/**
|
||||
* Running environment
|
||||
*
|
||||
* Supports 'node', 'jsdom', 'happy-dom'
|
||||
* Supports 'node', 'jsdom', 'happy-dom', 'edge-runtime'
|
||||
*
|
||||
* @default 'node'
|
||||
*/
|
||||
|
||||
24
pnpm-lock.yaml
generated
24
pnpm-lock.yaml
generated
@ -648,6 +648,7 @@ importers:
|
||||
packages/vitest:
|
||||
specifiers:
|
||||
'@antfu/install-pkg': ^0.1.0
|
||||
'@edge-runtime/vm': 1.1.0-beta.10
|
||||
'@sinonjs/fake-timers': ^9.1.2
|
||||
'@types/chai': ^4.3.1
|
||||
'@types/chai-subset': ^1.3.3
|
||||
@ -706,6 +707,7 @@ importers:
|
||||
vite: 3.0.0-beta.4
|
||||
devDependencies:
|
||||
'@antfu/install-pkg': 0.1.0
|
||||
'@edge-runtime/vm': 1.1.0-beta.10
|
||||
'@sinonjs/fake-timers': 9.1.2
|
||||
'@types/diff': 5.0.2
|
||||
'@types/jsdom': 16.2.14
|
||||
@ -880,6 +882,16 @@ importers:
|
||||
pathe: 0.2.0
|
||||
vitest: link:../../packages/vitest
|
||||
|
||||
test/vite-edge:
|
||||
specifiers:
|
||||
'@edge-runtime/vm': 1.1.0-beta.10
|
||||
'@vitest/web-worker': workspace:*
|
||||
vitest: workspace:*
|
||||
devDependencies:
|
||||
'@edge-runtime/vm': 1.1.0-beta.10
|
||||
'@vitest/web-worker': link:../../packages/web-worker
|
||||
vitest: link:../../packages/vitest
|
||||
|
||||
test/vite-node:
|
||||
specifiers:
|
||||
vite-node: workspace:*
|
||||
@ -3057,6 +3069,16 @@ packages:
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
dev: true
|
||||
|
||||
/@edge-runtime/primitives/1.1.0-beta.10:
|
||||
resolution: {integrity: sha512-hv0i2ce35yspqlnmcSKV/GEKfk8WyB9aTSOk0ZMK6gOR6ZvBDCzDpdacIcGuktaTuDinwon2DLxXRhiAS2PjUg==}
|
||||
dev: true
|
||||
|
||||
/@edge-runtime/vm/1.1.0-beta.10:
|
||||
resolution: {integrity: sha512-AHeIdWp1OUf4kvA4to56shXZzM66bR84LMNTbYGY7G3+BBr+VkUcvU+hWr8JYCOj/iAHi/fuE9r1TyrMm2pQaw==}
|
||||
dependencies:
|
||||
'@edge-runtime/primitives': 1.1.0-beta.10
|
||||
dev: true
|
||||
|
||||
/@emotion/babel-plugin/11.9.2_@babel+core@7.18.2:
|
||||
resolution: {integrity: sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==}
|
||||
peerDependencies:
|
||||
@ -6301,7 +6323,7 @@ packages:
|
||||
dev: true
|
||||
|
||||
/@types/form-data/0.0.33:
|
||||
resolution: {integrity: sha1-yayFsqX9GENbjIXZ7LUObWyJP/g=}
|
||||
resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==}
|
||||
dependencies:
|
||||
'@types/node': 17.0.40
|
||||
dev: true
|
||||
|
||||
14
test/vite-edge/package.json
Normal file
14
test/vite-edge/package.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "@vitest/test-edge-runtime",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"coverage": "vitest run --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@edge-runtime/vm": "1.1.0-beta.10",
|
||||
"@vitest/web-worker": "workspace:*",
|
||||
"vitest": "workspace:*"
|
||||
}
|
||||
}
|
||||
19
test/vite-edge/test/edge.test.ts
Normal file
19
test/vite-edge/test/edge.test.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @vitest-environment edge-runtime
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest'
|
||||
describe('edge runtime api', () => {
|
||||
it('TextEncoder references the same global Uint8Array constructor', () => {
|
||||
expect(new TextEncoder().encode('abc')).toBeInstanceOf(Uint8Array)
|
||||
})
|
||||
|
||||
it('allows to run fetch', async () => {
|
||||
const response = await fetch('https://vitest.dev')
|
||||
expect(response.status).toEqual(200)
|
||||
})
|
||||
|
||||
it('allows to run crypto', async () => {
|
||||
const array = new Uint32Array(10)
|
||||
expect(crypto.getRandomValues(array)).toHaveLength(array.length)
|
||||
})
|
||||
})
|
||||
5
test/vite-edge/test/node.test.ts
Normal file
5
test/vite-edge/test/node.test.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { expect, test } from 'vitest'
|
||||
|
||||
test('node env should not have crypto', () => {
|
||||
expect(global).not.toHaveProperty('crypto')
|
||||
})
|
||||
7
test/vite-edge/vitest.config.ts
Normal file
7
test/vite-edge/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
environment: 'node',
|
||||
},
|
||||
})
|
||||
Loading…
x
Reference in New Issue
Block a user