Workers Vitest pool 目前处于公开 Beta 阶段。以下是 Cloudflare 已知并正在修复的问题:
不支持通过 V8 ↗ 的原生代码覆盖率。必须使用 Istanbul ↗ 的插桩代码覆盖率。设置说明请参阅 Vitest 覆盖率文档 ↗。
Vitest 的假定时器 ↗不适用于 KV、R2 和 cache 模拟器。例如,无法通过推进假时间来使 KV 键过期。
在使用 exports.default.fetch() 编写集成测试时,在 export default { ... } 处理器内部,或在 Durable Object 事件处理器内部,动态 import() 语句无法正常工作。必须直接导入并调用处理器,或在全局作用域中使用静态 import 语句。
在按文件存储隔离的情况下,Durable Objects 不支持 WebSockets。解决方法是以共享存储方式运行测试,使用 --max-workers=1 --no-isolate。
存储隔离按测试文件进行。测试运行器会在每个测试文件结束时撤销对存储的所有写入,详见隔离与并发文档。Cloudflare 建议采取以下措施以避免常见问题:
始终 await 所有读取或写入存储服务的 Promise。
// Example: Seed data
beforeAll(async () => {
await env.KV.put("message", "test message");
await env.R2.put("file", "hello-world");
});调用 Service Worker 或 Durable Object 的 RPC 方法且返回非原始值(例如对象或扩展 RpcTarget 的类)时,使用 using 关键字显式标记资源何时可以释放。请参阅此示例测试 ↗以及显式资源管理了解更多详情。
using result = await stub.getCounter();通过 fetch 或 R2.get() 发起请求时,即使不断言其内容,也要消费完整的响应体。例如:
test("check if file exists", async () => {
await env.R2.put("file", "hello-world");
const response = await env.R2.get("file");
expect(response).not.toBe(null);
// Consume the response body even if you are not asserting it
await response.text();
});ctx.exports 属性提供对 main Worker 导出的访问。Workers Vitest 集成尝试通过 esbuild 静态分析 Worker 源代码来自动推断这些导出。然而,复杂的构建设置(例如使用 esbuild 无法跟踪的虚拟模块或通配符重新导出)可能导致 ctx.exports 对象上缺少属性。
例如,考虑一个 Worker 使用通配符导出从虚拟模块重新导出入口点:
// index.ts
export * from "@virtual-module";在这种情况下,来自 @virtual-module 的任何导出(例如 MyEntrypoint)都无法自动推断,将不会出现在 ctx.exports 中。
解决方法是在 Vitest 配置中添加 additionalExports 选项:
import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
import { defineConfig } from "vitest/config";
export default defineConfig({
plugins: [
cloudflareTest({
wrangler: { configPath: "./wrangler.jsonc" },
additionalExports: {
MyEntrypoint: "WorkerEntrypoint",
},
}),
],
});additionalExports 选项是一个映射,键为导出名称,值为导出类型("WorkerEntrypoint"、"DurableObject" 或 "WorkflowEntrypoint")。
如果遇到模块解析问题,例如:Error: Cannot use require() to import an ES Module 或 Error: No such module,可以使用 deps.optimizer ↗ 选项打包这些依赖:
import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
import { defineConfig } from "vitest/config";
export default defineConfig({
plugins: [
cloudflareTest({
// ...
}),
],
test: {
deps: {
optimizer: {
ssr: {
enabled: true,
include: ["your-package-name"],
},
},
},
},
});示例请参阅示例页面。
虽然 Vitest 已配置为在 workerd ↗ 运行时解析包,但 global setup 文件在 Node.js 环境中运行。导入 Postgres.js ↗ 等包时可能出现问题,该包为 workerd 导出了非 Node 版本。
解决方法是可以创建一个包装器,使用 Vite 的 SSR 模块加载器在正确条件下导入 global setup 文件。然后调整 Vitest 配置以指向该包装器。例如:
// File: global-setup-wrapper.ts
import { createServer } from "vite";
// Import the actual global setup file with the correct setup
const mod = await viteImport("./global-setup.ts");
export default mod.default;
// Helper to import the file with default node setup
async function viteImport(file: string) {
const server = await createServer({
root: import.meta.dirname,
configFile: false,
server: { middlewareMode: true, hmr: false, watch: null, ws: false },
optimizeDeps: { noDiscovery: true },
clearScreen: false,
});
const mod = await server.ssrLoadModule(file);
await server.close();
return mod;
}// File: vitest.config.ts
import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
import { defineConfig } from "vitest/config";
export default defineConfig({
plugins: [
cloudflareTest({
// ...
}),
],
test: {
// Replace the globalSetup with the wrapper file
globalSetup: ["./global-setup-wrapper.ts"],
},
});