Miniflare 2 ↗ 分别在 jest-environment-miniflare 和 vitest-environment-miniflare 包中为 Jest 和 Vitest 提供了自定义环境。
@cloudflare/vitest-pool-workers 包使用现代 Miniflare 版本和 workerd 运行时 ↗ 提供类似功能。workerd 是驱动 Cloudflare Workers 的同一 JavaScript/WebAssembly 运行时。使用 workerd 几乎消除了测试与已部署代码之间的行为差异。更多信息请参阅 Miniflare 3 公告 ↗。
首先,需要卸载旧环境并安装新的 pool。Vitest 环境只能自定义全局作用域,而 pool 可以使用完全不同的运行时运行测试。在此情况下,pool 在 workerd ↗ 内而非 Node.js 中运行测试。
npm uninstall vitest-environment-miniflare
npm install --save-dev vitest@^4.1.0
npm install --save-dev @cloudflare/vitest-pool-workers安装 Workers Vitest 集成后,更新 Vitest 配置文件以改用 cloudflareTest() Vite 插件。之前在 environmentOptions 中指定的大多数 Miniflare 配置可以移至 cloudflareTest() 中的 miniflare 选项。支持的选项请参阅 Miniflare 的 WorkerOptions 接口 ↗,更多信息请参阅 Miniflare 2 到 3 迁移指南。如果依赖存储在 Wrangler 文件中的配置,也请设置 wrangler.configPath。
+ import { cloudflareTest } from "@cloudflare/vitest-pool-workers";
+ import { defineConfig } from "vitest/config";
- export default defineWorkersConfig({
- test: {
- environment: "miniflare",
- environmentOptions: { ... },
- },
- });
+ export default defineConfig({
+ plugins: [
+ cloudflareTest({
+ miniflare: { ... },
+ wrangler: { configPath: "./wrangler.jsonc" },
+ }),
+ ],
+ });如果使用 TypeScript,请更新 tsconfig.json 以包含正确的环境 types:
{
"compilerOptions": {
...,
"types": [
...
- "vitest-environment-miniflare/globals"
+ "@cloudflare/vitest-pool-workers/types"
]
},
}要在测试中访问绑定,请使用 cloudflare:workers 模块中的 env 辅助函数。
import { it } from "vitest";
+ import { env } from "cloudflare:workers";
it("does something", () => {
- const env = getMiniflareBindings();
// ...
});如果使用 TypeScript,需要为测试定义 env 的类型。设置说明请参阅定义类型。
默认情况下,存储隔离按测试文件进行。不再需要在测试中包含 setupMiniflareIsolatedStorage()。
- const describe = setupMiniflareIsolatedStorage();
+ import { describe } from "vitest";new ExecutionContext() 构造函数和 getMiniflareWaitUntil() 函数现在分别对应 createExecutionContext() 和 waitOnExecutionContext()。注意 waitOnExecutionContext() 现在返回空的 Promise<void>,而不是解析为所有 waitUntil() 的 Promise 结果的 Promise。
+ import { createExecutionContext, waitOnExecutionContext } from "cloudflare:test";
it("does something", () => {
// ...
- const ctx = new ExecutionContext();
+ const ctx = createExecutionContext();
const response = worker.fetch(request, env, ctx);
- await getMiniflareWaitUntil(ctx);
+ await waitOnExecutionContext(ctx);
});getMiniflareFetchMock() 函数不再可用。要 mock 出站 fetch() 请求,请直接 mock globalThis.fetch,或使用 MSW ↗ 等生态库。完整示例请参阅请求 mock 示例 ↗。
getMiniflareDurableObjectStorage()、getMiniflareDurableObjectState()、getMiniflareDurableObjectInstance() 和 runWithMiniflareDurableObjectGates() 函数均已替换为 cloudflare:test 模块中的单个 runInDurableObject() 函数。runInDurableObject() 函数接受一个 DurableObjectStub 和回调,回调接受 Durable Object 及对应的 DurableObjectState 作为参数。将这些函数合并为单个函数简化了 API 表面,并确保实例在正确的请求上下文和门控行为 ↗下被访问。更多详情请参阅测试 API 页面。
+ import { env } from "cloudflare:workers";
+ import { runInDurableObject } from "cloudflare:test";
it("does something", async () => {
- const env = getMiniflareBindings();
const id = env.OBJECT.newUniqueId();
+ const stub = env.OBJECT.get(id);
- const storage = await getMiniflareDurableObjectStorage(id);
- doSomethingWith(storage);
+ await runInDurableObject(stub, async (instance, state) => {
+ doSomethingWith(state.storage);
+ });
- const state = await getMiniflareDurableObjectState(id);
- doSomethingWith(state);
+ await runInDurableObject(stub, async (instance, state) => {
+ doSomethingWith(state);
+ });
- const instance = await getMiniflareDurableObjectInstance(id);
- await runWithMiniflareDurableObjectGates(state, async () => {
- doSomethingWith(instance);
- });
+ await runInDurableObject(stub, async (instance) => {
+ doSomethingWith(instance);
+ });
});flushMiniflareDurableObjectAlarms() 函数已替换为 cloudflare:test 模块中的 runDurableObjectAlarm() 函数。runDurableObjectAlarm() 函数接受单个 DurableObjectStub,返回一个 Promise,如果 alarm 已调度且 alarm() 处理器已执行则解析为 true,否则为 false。要"刷新"多个实例的 alarm,请在循环中调用 runDurableObjectAlarm()。
+ import { env } from "cloudflare:workers";
+ import { runDurableObjectAlarm } from "cloudflare:test";
it("does something", async () => {
- const env = getMiniflareBindings();
const id = env.OBJECT.newUniqueId();
- await flushMiniflareDurableObjectAlarms([id]);
+ const stub = env.OBJECT.get(id);
+ const ran = await runDurableObjectAlarm(stub);
});最后,getMiniflareDurableObjectIds() 函数已替换为 cloudflare:test 模块中的 listDurableObjectIds() 函数。listDurableObjectIds() 函数现在接受 DurableObjectNamespace 实例而非命名空间 string,以提供更严格的类型。注意 listDurableObjectIds() 函数遵循存储隔离。在其他测试文件中创建的对象 ID 不会被返回。
+ import { env } from "cloudflare:workers";
+ import { listDurableObjectIds } from "cloudflare:test";
it("does something", async () => {
- const ids = await getMiniflareDurableObjectIds("OBJECT");
+ const ids = await listDurableObjectIds(env.OBJECT);
});