跳转到内容
搜索文档

从 Miniflare 2 的测试环境迁移

最后更新 查看 MarkdownAgent 设置

Miniflare 2 分别在 jest-environment-miniflarevitest-environment-miniflare 包中为 Jest 和 Vitest 提供了自定义环境。 @cloudflare/vitest-pool-workers 包使用现代 Miniflare 版本和 workerd 运行时 提供类似功能。workerd 是驱动 Cloudflare Workers 的同一 JavaScript/WebAssembly 运行时。使用 workerd 几乎消除了测试与已部署代码之间的行为差异。更多信息请参阅 Miniflare 3 公告

安装 Workers Vitest 集成

首先,需要卸载旧环境并安装新的 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

更新 Vitest 配置文件

安装 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 配置文件

如果使用 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";

使用 waitUntil()

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);
  });

Mock 出站请求

getMiniflareFetchMock() 函数不再可用。要 mock 出站 fetch() 请求,请直接 mock globalThis.fetch,或使用 MSW 等生态库。完整示例请参阅请求 mock 示例

使用 Durable Object 辅助函数

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);
  });

这篇文档对您有帮助吗?