Skip to main content
app.fetch(req, env, ctx) is your single test seam. Pass a synthetic Request, a plain mock env object, and a mock ExecutionContext — no Worker runtime, no wrangler dev, no live Cloudflare account needed. Because Blaze enriches the standard Request internally, your tests stay clean and fast.

Unit testing with Vitest

Vitest runs in a standard Node.js environment. Build up a mockEnv with vi.fn() stubs for each binding your handler touches, then call app.fetch() and assert on the Response.
Use mockCtx.waitUntil as a vi.fn() to assert on background tasks. After calling app.fetch(), inspect mockCtx.waitUntil.mock.calls to verify that analytics writes, cache warming, or other fire-and-forget work was scheduled — without actually running the deferred work.

Integration testing with @cloudflare/vitest-pool-workers

For tests that need real Cloudflare APIs — Workers KV, D1, R2 — use the @cloudflare/vitest-pool-workers pool. It runs your tests inside an actual Workers runtime via Miniflare, so bindings behave exactly as they do in production.

Mocking Cloudflare bindings

Different bindings need different mock shapes. Here are the patterns for the most common ones:

Testing middleware

Test auth middleware by controlling the Authorization header. Pass the header to simulate an authenticated request; omit it (or supply an invalid token) to test the rejection path.
test/auth.test.ts

Testing error handlers

Assert on the status code and response body to verify your error handler shapes the response correctly, including custom metadata from BlazeError.
test/errors.test.ts
To test that background tasks are scheduled correctly, assert on mockCtx.waitUntil.mock.calls after await app.fetch(...). For example, if your analytics handler writes a data point after every GET /products/:id, you can verify expect(mockCtx.waitUntil).toHaveBeenCalledOnce() without waiting for the deferred promise to settle.