new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Cloudflare Workers · all subjects

testing

300 notes in this subject, read out of this brain and free to use. This is page 2 of 5.

Miniflare Queue producers configuration

To add queue producers to a Miniflare environment, use the queueProducers option. You can specify producers as an object mapping binding names to queue names: const mf = new Miniflare({ queueProducers: { MY_QUEUE: "my-queue" } }). If the binding name and queue name are identical, you can use an array: queueProducers: ["MY_QUEUE"].

Miniflare queue testing with multiple workers example

Example showing how to test queue interactions between two Workers in Miniflare: Worker 'a' produces messages to MY_QUEUE using env.QUEUE.send(), and worker 'b' consumes them via the queue handler. Use getQueueProducer("QUEUE", "a") to send messages from outside and verify consumer behavior. const mf = new Miniflare({ workers: [ { name: "a", modules: true, script: ` export default { async fetch(request, env, ctx) { await env.QUEUE.send(await request.text()); } } `, queueProducers: { QUEUE: "my-queue" }, }, { name: "b", modules: true, script: ` export default { async queue(batch, env, ctx) { console.log(batch); } } `, queueConsumers: { "my-queue": { maxBatchTimeout: 1 } }, }, ], }); const queue = await mf.getQueueProducer("QUEUE", "a"); await queue.send("message");

Scheduled events Miniflare crons configuration

Scheduled events are automatically dispatched according to cron triggers specified in the Miniflare configuration. Pass an array of cron expressions to the crons property when creating a Miniflare instance.

Scheduled event testing example with cron and scheduledTime

Example showing how to test scheduled events using Miniflare's getWorker API. The code creates a Miniflare instance with an inline worker script that exports a scheduled handler checking the cron expression and calling controller.noRetry(). It then dispatches two scheduled events with different cron and scheduledTime parameters and logs the results showing outcome and noRetry status.

Miniflare getWorker scheduled events dispatching

The getWorker function in Miniflare's API allows dispatching scheduled events to a Worker for testing. The scheduled method accepts optional scheduledTime and cron parameters (defaulting to current time and empty string respectively) and returns a promise resolving to an array containing data from all awaited promises.

Scheduled events HTTP trigger endpoint

Make HTTP requests to /cdn-cgi/mf/scheduled to trigger scheduled events in Miniflare without waiting for cron triggers. Use the time query parameter to simulate different scheduledTime values and the cron query parameter to simulate different cron expressions.

Miniflare does not support subrequest limiting

Miniflare does not support limiting the amount of subrequests. If you make a large amount of subrequests from your Worker during testing with Miniflare, this limitation should be kept in mind.

Miniflare fetch mock example with intercept

Example showing how to mock fetch requests in Miniflare: ```js import { Miniflare, createFetchMock } from "miniflare"; // Create `MockAgent` and connect it to the `Miniflare` instance const fetchMock = createFetchMock(); const mf = new Miniflare({ modules: true, script: ` export default { async fetch(request, env, ctx) { const res = await fetch("https://example.com/thing"); const text = await res.text(); return new Response(\`response:\${text}\`); } } `, fetchMock, }); // Throw when no matching mocked request is found fetchMock.disableNetConnect(); // Mock request to https://example.com/thing const origin = fetchMock.get("https://example.com"); origin .intercept({ method: "GET", path: "/thing" }) .reply(200, "Mocked response!"); const res = await mf.dispatchFetch("http://localhost:8787/"); console.log(await res.text()); // "response:Mocked response!" ``` This example demonstrates creating a MockAgent, configuring it to intercept a specific GET request, and returning a mocked response.

Miniflare fetch mocking with MockAgent

Miniflare allows you to substitute custom Responses for fetch() calls using undici's MockAgent API. To enable fetch mocking, create a MockAgent using the createFetchMock() function, then set this using the fetchMock option when instantiating Miniflare. This is useful for testing Workers that make HTTP requests to other services.

Miniflare data blob bindings from files

Data blob bindings in Miniflare can be loaded from files using the dataBlobBindings configuration. File contents are read and bound as ArrayBuffers. The configuration takes an object with binding names as keys and file paths as values.

Arbitrary globals not supported in Miniflare and workerd

Injecting arbitrary globals is not supported by workerd. When using a service Worker with Miniflare, bindings will be injected as globals, but these bindings must be JSON-serializable.

Miniflare bindings configuration for variables and secrets

In Miniflare, variables and secrets are bound using the bindings object in the Miniflare constructor. Pass an object with key-value pairs where keys are the binding names and values are the variable values.

Miniflare debugging is for advanced use cases

Breakpoint debugging when using Miniflare directly is only relevant for advanced use cases. Most users should use Wrangler with the Workers Observability documentation for setting up breakpoints and debugging.

Node.js debugging with Miniflare

You can use regular Node.js tools to debug Workers. Miniflare supports setting breakpoints, watching values, and inspecting the call stack. Breakpoints can be added via the Workers DevTools or through IDEs like VSCode and WebStorm that attach to Miniflare's debugging port.

Miniflare debugger: WebStorm configuration

To debug a Worker in WebStorm using Miniflare, create a new Node.js/Chrome debug configuration by clicking Add Configuration in the top right, then clicking the plus button in the popup. Set the Host field to localhost and the Port field to 9229, then click OK. With the new configuration selected, click the green debug button to start debugging.

Miniflare debugger: VSCode configuration

To debug a Worker in VSCode using Miniflare, create a .vscode/launch.json file with a Node.js attach configuration. Set the type to 'node', request to 'attach', port to 9229, cwd to '/', resolveSourceMapLocations to null, attachExistingChildren to false, and autoAttachChildProcesses to false. Open the Run and Debug menu, select the Miniflare configuration, and click the green play button to start debugging.

Miniflare automatically upgrades WebSocket connections

Miniflare will automatically upgrade any WebSocket connection attempts without requiring additional configuration.

Testing WebSocket with Miniflare example

This example shows how to test a WebSocket server using Miniflare's dispatchFetch: import { Miniflare } from "miniflare"; const mf = new Miniflare({ modules: true, scriptPath: "echo.mjs", }); const res = await mf.dispatchFetch("https://example.com", { headers: { Upgrade: "websocket", }, }); const webSocket = res.webSocket; webSocket.accept(); webSocket.addEventListener("message", (event) => { console.log(event.data); }); webSocket.send("Hello!"); // Above listener logs "Hello!"

Miniflare dispatchFetch with WebSocket upgrade

When using Miniflare's dispatchFetch() method to test WebSocket connections, send an Upgrade: websocket header in the request. The returned Response object will have a webSocket property that can be used to interact with the server side of the connection.

Miniflare purpose for testing and advanced use cases

Miniflare allows you to dispatch events to workers without making actual HTTP requests, simulate connections between Workers, and interact with local emulations of storage products like KV, R2, and Durable Objects. This makes it ideal for writing tests and advanced use cases requiring finer-grained control.

D1 query execution in Miniflare tests

To execute D1 queries in Miniflare tests, call prepare() with your SQL query string on the database object, then await the run() method. The run() method returns a result object with a results property containing the query results. Example: const stmt = await db.prepare("<Query>"); const returnValue = await stmt.run(); return Response.json(returnValue.results);

getD1Database method for testing

Use the getD1Database method in Miniflare to retrieve a D1 database bound to a Worker for testing. The method is async and takes a binding name as a string argument. Example: const db = await mf.getD1Database("DB"); You can then use standard D1 methods like prepare() and run() on the returned database object.

D1 database binding in Miniflare configuration

To specify D1 databases in Miniflare, pass a d1Databases object to the Miniflare constructor where keys are binding names and values are database UUIDs. Example: const mf = new Miniflare({ d1Databases: { DB: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" } });

Get caches object outside Worker in Miniflare

Use the getCaches() method on a Miniflare instance to access the global caches object outside of a Worker. This allows you to put and match cache data for testing purposes.

Miniflare cache with named cache example

Example of accessing and manipulating cache outside a Worker with Miniflare: ```js import { Miniflare, Response } from "miniflare"; const mf = new Miniflare({ modules: true, script: ` export default { async fetch(request) { const url = new URL(request.url); const cache = caches.default; if(url.pathname === "/put") { await cache.put("https://miniflare.dev/", new Response("1", { headers: { "Cache-Control": "max-age=3600" }, })); } return cache.match("https://miniflare.dev/"); } } `, }); let res = await mf.dispatchFetch("http://localhost:8787/put"); console.log(await res.text()); // 1 const caches = await mf.getCaches(); const cachedRes = await caches.default.match("https://miniflare.dev/"); console.log(await cachedRes.text()); // 1 await caches.default.put( "https://miniflare.dev", new Response("2", { headers: { "Cache-Control": "max-age=3600" }, }), ); res = await mf.dispatchFetch("http://localhost:8787"); console.log(await res.text()); // 2 ```

Miniflare R2 bucket testing example

Example showing how to test R2 operations in Miniflare: create a Miniflare instance with r2Buckets: ["BUCKET"], use getR2Bucket to access the bucket outside the worker, call bucket.put to store data, dispatch a fetch request to the worker, and verify the results by reading from the bucket. The worker receives env.BUCKET for R2 operations, can call env.BUCKET.get(key) to retrieve objects, and env.BUCKET.put(key, value) to store data.

Configure R2 buckets in Miniflare

To specify R2 buckets in a Miniflare environment, pass an array of bucket names to the r2Buckets property of the Miniflare constructor. Example: const mf = new Miniflare({ r2Buckets: ["BUCKET1", "BUCKET2"] });

Access R2 bucket outside worker in Miniflare tests

Use the getR2Bucket method on the Miniflare instance to retrieve and manipulate R2 bucket data outside of a worker for testing purposes. Example: const bucket = await mf.getR2Bucket("BUCKET"); followed by await bucket.put("count", "1"); or await bucket.get("count");

Miniflare KV namespace setup

To set up KV namespaces in Miniflare for testing, pass an array of namespace names to the kvNamespaces property when creating a new Miniflare instance. Example: const mf = new Miniflare({ kvNamespaces: ["TEST_NAMESPACE1", "TEST_NAMESPACE2"] });

Manipulate KV data outside workers in Miniflare

To put or get data from KV outside of a worker for testing purposes, use the getKVNamespace method on a Miniflare instance. This returns a namespace object that supports KV operations like put and get, allowing you to set up test data before running worker code.

Miniflare supports all KV operations and data types

Miniflare supports all KV operations and data types, providing full KV API compatibility for testing purposes.

Access KV namespaces in Miniflare workers

KV namespaces configured in Miniflare are accessible via the env object in worker handlers. Access them by the namespace name as a property. Example: export default { async fetch(request, env) { return new Response(await env.TEST_NAMESPACE1.get("key")); } };

Miniflare getKVNamespace method example

The following example demonstrates setting up test data in KV and then dispatching a fetch request to verify the worker processes it correctly: import { Miniflare } from "miniflare"; const mf = new Miniflare({ modules: true, script: ` export default { async fetch(request, env, ctx) { const value = parseInt(await env.TEST_NAMESPACE.get("count")) + 1; await env.TEST_NAMESPACE.put("count", value.toString()); return new Response(value.toString()); }, } `, kvNamespaces: ["TEST_NAMESPACE"], }); const ns = await mf.getKVNamespace("TEST_NAMESPACE"); await ns.put("count", "1"); const res = await mf.dispatchFetch("http://localhost:8787/"); console.log(await res.text()); // 2 console.log(await ns.get("count")); // 2

Testing frameworks supported by Miniflare

While the Miniflare documentation demonstrates concepts using node:test, any testing framework can be used with Miniflare.

Test runtime differences between Miniflare and Vitest

When using Miniflare with node:test, only the Worker itself runs in workerd, while test files run in Node.js. By contrast, the Vitest integration runs your entire test suite in workerd. This means importing functions from your Worker into test files might exhibit different behavior than at runtime if the functions rely on workerd-specific behavior. With Miniflare, you cannot unit test individual functions—all access to your Worker must be through dispatchFetch().

Testing TypeScript and bundled Workers with Miniflare

When testing Workers written in TypeScript or consisting of bundled code, run your build tool before tests execute. This can be done in a before() hook by spawning the build command, for example: spawnSync("npx wrangler build -c wrangler-build.json", { shell: true, stdio: "pipe" })

Testing multiple module Workers with Miniflare

For Workers consisting of multiple JavaScript files, provide all modules in the modules array when creating a Miniflare instance, with each module specifying type: "ESModule" and path. Alternatively, use scriptPath with modules: true and modulesRules to have Miniflare automatically crawl the module graph: new Miniflare({ scriptPath: "src/index.js", modules: true, modulesRules: [{ type: "ESModule", include: ["**/*.js"] }] })

Miniflare does not read wrangler.toml

Miniflare does not read Wrangler's config file (wrangler.toml). All bindings that your Worker uses must be specified directly in the Miniflare API options.

Testing KV with Miniflare

To test KV namespace bindings with Miniflare, add kvNamespaces to the Miniflare configuration: new Miniflare({ kvNamespaces: ["KV"] }). Then interact with it via getBindings(): const bindings = await worker.getBindings(); await bindings.KV.put("key", "value"); await bindings.KV.get("key");

Testing environment variables with Miniflare

To test environment variable bindings with Miniflare, add them to the bindings configuration option when creating the Miniflare instance: new Miniflare({ bindings: { FOO: "Hello Bindings" } }). Then access them via getBindings(): const bindings = await worker.getBindings(); bindings.FOO

Miniflare getBindings API

Use the getBindings() API to interact directly with bindings in tests, such as environment variables, KV namespaces, R2 buckets, and other bindings. Call: const bindings = await worker.getBindings();

Miniflare basic test example

Example of setting up Miniflare and writing a test using node:test framework: ```js import assert from "node:assert"; import test, { after, before, describe } from "node:test"; import { Miniflare } from "miniflare"; describe("worker", () => { let worker; before(async () => { worker = new Miniflare({ modules: [ { type: "ESModule", path: "src/index.js", }, ], }); await worker.ready; }); test("hello world", async () => { assert.strictEqual( await (await worker.dispatchFetch("http://example.com")).text(), "Hello World", ); }); after(async () => { await worker.dispose(); }); }); ```

Miniflare basic setup with dispatchFetch

To set up Miniflare for testing a Worker, create a new Miniflare instance with modules configuration pointing to your Worker file, await worker.ready, then use worker.dispatchFetch() to send requests to the Worker and assert against responses. All access to your Worker must be through the dispatchFetch() API.

Installing Miniflare

Install the latest version of Miniflare v3 using npm or your package manager with the command: npm install --save-dev miniflare@latest

Miniflare testing overview and recommendations

For most users, Cloudflare recommends using the Workers Vitest integration for unit tests and createTestHarness() for integration tests. Use Miniflare directly only when you need low-level simulator control that is not exposed by those higher-level testing APIs. Miniflare is a low-level API that allows you to fully control how your Workers are run and tested.

Example: Multiple Workers in test harness

const server = createTestHarness({ workers: [ // Wrangler project { configPath: "./workers/api/wrangler.jsonc" }, // Vite project (built output from the Cloudflare Vite plugin) { configPath: "./dist/web_worker/wrangler.json" }, ], });

Print debug output with server.debug()

server.debug() prints the server timeline and captured Workers runtime logs. Call it when a test throws an exception or fails and you need more information to debug it.

createTestHarness() runs Workers in a local server

createTestHarness() runs one or more Workers in a single local server. Each Worker can come from a Wrangler project or a Vite project that uses the Cloudflare Vite plugin.

Specify types for Worker handles with server.getWorker()

server.getWorker() accepts types for the Worker environment and module exports. Pass the generated environment interface as the first type parameter and use typeof import() to derive the Worker exports from its source module as the second type parameter.

Example: Basic createTestHarness configuration

const server = createTestHarness({ workers: [{ configPath: "./wrangler.jsonc" }], });

Example: Select Wrangler environment in test harness

const server = createTestHarness({ workers: [{ configPath: "./wrangler.jsonc", env: "test" }], });

Configure test harness after setup with server.update()

If part of the Worker configuration depends on the test setup, you can call createTestHarness() without options and configure the harness with server.update() before starting the server with server.listen().

Override vars and secrets in test harness

You can override vars and secrets for each Worker in the harness if you want to avoid creating a separate Wrangler environment for testing.

Select Wrangler environment in test harness

By default, the test harness loads the top-level Wrangler configuration. Set the env property to load a specific environment from the configuration.

Build Vite projects before using in test harness

For Workers built by the Cloudflare Vite plugin, run vite build first so tests use the production build output. The generated Wrangler configuration works like any other configPath.

Configure Worker projects with configPath in createTestHarness

Point each entry in the workers array to the Wrangler configuration file for a project using the configPath property.

Example: Override variables and secrets in test harness

const server = createTestHarness({ workers: [ { configPath: "./wrangler.jsonc", vars: { API_HOST: "http://identity.example.com" }, secrets: { API_TOKEN: "test-token" }, }, ], });

Reset test harness between tests with server.reset()

When reusing a server across tests, call server.reset() after each test. It recreates local storage and restores Workers to the options used when the current session started. After a reset, apply any required schema migrations and seed data again.

Generate Worker environment types with wrangler types

Generate the env type from the Wrangler configuration using the wrangler types command. Give each Worker a distinct environment interface so the generated declarations can be used together. Specify the output file, config path, and env-interface name as arguments.

Example: Configure test harness after setup

const server = createTestHarness(); let upstream: { url: string; close(): Promise<void> }; beforeAll(async () => { upstream = await startLocalApi(); await server.update({ workers: [ { configPath: "./wrangler.jsonc", vars: { API_HOST: upstream.url }, }, ], }); await server.listen(); }); afterAll(async () => { await server.close(); await upstream.close(); });

Give your agent this brain