测试环境
Vitest 提供了 environment
选项,用于在特定环境下运行测试代码。你还可以使用 environmentOptions
选项来配置环境的行为。
默认情况下,Vitest 支持以下内置环境:
node
:默认环境。jsdom
:通过jsdom
包模拟浏览器环境,提供浏览器 API。happy-dom
:通过happy-dom
包模拟浏览器环境。它通常比jsdom
更快,但可能缺少部分 API。edge-runtime
:通过@edge-runtime/vm
包模拟 Vercel 的 Edge Runtime 环境。
INFO
当使用 jsdom
或 happy-dom
环境时,Vitest 遵循 Vite 导入 CSS 和 静态资源 的相同规则。如果导入外部依赖时遇到 unknown extension .css
错误,你需要手动内联整个导入链,将所有相关包添加到 server.deps.external
。例如,如果错误发生在导入链 source code -> package-1 -> package-2 -> package-3
中的 package-3
,则需要将 package-1
、package-2
和 package-3
都添加到 server.deps.external
。
自 Vitest 2.0.4 版本起,外部依赖中的 CSS 和静态资源的 require
引用将自动解析。
特定文件的环境
在 Vitest 配置中设置 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';
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;