测试环境
Vitest 提供了 environment
选项,用于在特定环境中运行测试代码。你可以通过 environmentOptions
选项来修改环境的行为。
默认情况下,Vitest 支持以下内置环境:
node
:默认的 Node.js 环境。jsdom
:通过jsdom
包模拟浏览器环境,提供浏览器 API。happy-dom
:通过happy-dom
包模拟浏览器环境。相较于jsdom
,它通常性能更优,但可能缺少部分 API。edge-runtime
:模拟 Vercel 的 edge-runtime,使用@edge-runtime/vm
包。
INFO
当使用 jsdom
或 happy-dom
环境时,Vitest 遵循 Vite 导入 CSS 和 静态资源 的相同规则。如果导入外部依赖项时出现 unknown extension .css
错误,你需要将所有相关包添加到 server.deps.external
。这是因为 Vitest 需要手动处理整个导入链。例如,如果 source code -> package-1 -> package-2 -> package-3
这条导入链中 package-3
发生错误,你需要将 package-1
、package-2
和 package-3
都添加到 server.deps.external
。
外部依赖项中对 CSS 和静态资源的 require
引用会自动解析。
特定文件的环境
在配置中设置 environment
选项时,它将应用于项目中的所有测试文件。为了实现更精细的控制,你可以使用控制注释来为特定文件指定环境。控制注释以 @vitest-environment
开头,后跟环境名称:
// @vitest-environment jsdom
import { expect, test } from 'vitest';
test('test', () => {
expect(typeof window).not.toBe('undefined');
});
或者,你也可以通过设置 environmentMatchGlobs
选项,根据 glob 模式来指定环境。
自定义环境
你可以创建自己的包来扩展 Vitest 环境。为此,请创建一个名为 vitest-environment-${name}
的包,或者指定一个有效的 JS/TS 文件路径。该包应导出一个符合 Environment
接口的对象:
import type { Environment } from 'vitest/environments';
export default <Environment>{
name: 'custom',
transformMode: 'ssr',
// 可选 - 仅当你支持 "experimental-vm" 模式时
async setupVM() {
const vm = await import('node:vm');
const context = vm.createContext();
return {
getVmContext() {
return context;
},
teardown() {
// 在所有使用该环境的测试运行完毕后调用
},
};
},
setup() {
// 自定义设置
return {
teardown() {
// 在所有使用该环境的测试运行完毕后调用
},
};
},
};
WARNING
Vitest 要求环境对象必须包含 transformMode
选项。其值应为 ssr
或 web
。此值决定了插件转换源代码的方式。如果设置为 ssr
,插件钩子在转换或解析文件时将获得 ssr: true
参数。否则,ssr
将被设置为 false
。
你还可以通过 vitest/environments
入口来访问默认的 Vitest 环境:
import { builtinEnvironments, populateGlobal } from 'vitest/environments';
console.log(builtinEnvironments); // { jsdom, happy-dom, node, edge-runtime }
Vitest 还提供了 populateGlobal
工具函数,可用于将对象的属性注入到全局命名空间:
interface PopulateOptions {
// 非类函数是否应绑定到全局对象
bindFunctions?: boolean;
}
interface PopulateResult {
// 已复制的所有键的列表,即使原始对象上不存在对应的值
keys: Set<string>;
// 存储原始对象中可能已被新键覆盖的属性的映射
// 你可以在 `teardown` 函数中恢复这些原始值
originals: Map<string | symbol, any>;
}
export function populateGlobal(
global: any,
original: any,
options: PopulateOptions
): PopulateResult;