Migrate from Miniflare 2's test environments
Miniflare 2 ↗ provided custom environments for Jest and Vitest in the jest-environment-miniflare and vitest-environment-miniflare packages respectively.
The @cloudflare/vitest-pool-workers package provides similar functionality using modern Miniflare versions and the workerd runtime ↗. workerd is the same JavaScript/WebAssembly runtime that powers Cloudflare Workers. Using workerd practically eliminates behavior mismatches between your tests and deployed code. Refer to the Miniflare 3 announcement ↗ for more information.
First, you will need to uninstall the old environment and install the new pool. Vitest environments can only customize the global scope, whereas pools can run tests using a completely different runtime. In this case, the pool runs your tests inside workerd ↗ instead of Node.js.
npm uninstall vitest-environment-miniflarenpm install --save-dev vitest@^4.1.0npm install --save-dev @cloudflare/vitest-pool-workersAfter installing the Workers Vitest integration, update your Vitest configuration file to use the cloudflareTest() Vite plugin instead. Most Miniflare configuration previously specified in environmentOptions can be moved to the miniflare option in cloudflareTest(). Refer to Miniflare's WorkerOptions interface ↗ for supported options and the Miniflare version 2 to 3 migration guide for more information. If you relied on configuration stored in a Wrangler file, set wrangler.configPath too.
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" }, }), ],});If you are using TypeScript, update your tsconfig.json to include the correct ambient types:
{ "compilerOptions": { ..., "types": [ ... "vitest-environment-miniflare/globals" "@cloudflare/vitest-pool-workers" ] },}To access bindings in your tests, use the env helper from the cloudflare:workers module.
import { it } from "vitest";import { env } from "cloudflare:workers";
it("does something", () => { const env = getMiniflareBindings(); // ...});If you are using TypeScript, you need to define the type of env for your tests. Refer to Define types for setup instructions.
Storage isolation is per test file by default. You no longer need to include setupMiniflareIsolatedStorage() in your tests.
const describe = setupMiniflareIsolatedStorage();import { describe } from "vitest";The new ExecutionContext() constructor and getMiniflareWaitUntil() function are now createExecutionContext() and waitOnExecutionContext() respectively. Note waitOnExecutionContext() now returns an empty Promise<void> instead of a Promise resolving to the results of all waitUntil()ed Promises.
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);});The getMiniflareFetchMock() function is no longer available. To mock outbound fetch() requests, mock globalThis.fetch directly or use ecosystem libraries such as MSW ↗. Refer to the request mocking example ↗ for a complete example.
The getMiniflareDurableObjectStorage(), getMiniflareDurableObjectState(), getMiniflareDurableObjectInstance(), and runWithMiniflareDurableObjectGates() functions have all been replaced with a single runInDurableObject() function from the cloudflare:test module. The runInDurableObject() function accepts a DurableObjectStub with a callback accepting the Durable Object and corresponding DurableObjectState as arguments. Consolidating these functions into a single function simplifies the API surface, and ensures instances are accessed with the correct request context and gating behavior ↗. Refer to the Test APIs page for more details.
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); });});The flushMiniflareDurableObjectAlarms() function has been replaced with the runDurableObjectAlarm() function from the cloudflare:test module. The runDurableObjectAlarm() function accepts a single DurableObjectStub and returns a Promise that resolves to true if an alarm was scheduled and the alarm() handler was executed, or false otherwise. To "flush" multiple instances' alarms, call runDurableObjectAlarm() in a loop.
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);});Finally, the getMiniflareDurableObjectIds() function has been replaced with the listDurableObjectIds() function from the cloudflare:test module. The listDurableObjectIds() function now accepts a DurableObjectNamespace instance instead of a namespace string to provide stricter typing. Note the listDurableObjectIds() function respects storage isolation. IDs of objects created in other test files will not be returned.
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);});