---
title: Test APIs · Cloudflare Workers docs
description: Runtime helpers for writing tests, exported from the `cloudflare:test` module.
lastUpdated: 2025-02-18T12:14:51.000Z
source_url:
  html: https://a74404c8.preview.developers.cloudflare.com/workers/testing/vitest-integration/test-apis/index.md
  md: https://a74404c8.preview.developers.cloudflare.com/workers/testing/vitest-integration/test-apis/
---

The Workers Vitest integration provides runtime helpers for writing tests in the `cloudflare:test` module. The `cloudflare:test` module is provided by the `@cloudflare/vitest-pool-workers` package, but can only be imported from test files that execute in the Workers runtime.

## `cloudflare:test` module definition

* `env`: import("cloudflare:test").ProvidedEnv

  * Exposes the [`env` object](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#parameters) for use as the second argument passed to ES modules format exported handlers. This provides access to [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/) that you have defined in your [Vitest configuration file](https://developers.cloudflare.com/workers/testing/vitest-integration/configuration/).



    ```js
    import { env } from "cloudflare:test";


    it("uses binding", async () => {
      await env.KV_NAMESPACE.put("key", "value");
      expect(await env.KV_NAMESPACE.get("key")).toBe("value");
    });
    ```

    To configure the type of this value, use an ambient module type:

    ```ts
    declare module "cloudflare:test" {
      interface ProvidedEnv {
        KV_NAMESPACE: KVNamespace;
      }
      // ...or if you have an existing `Env` type...
      interface ProvidedEnv extends Env {}
    }
    ```

* `SELF`: Fetcher

  * [Service binding](https://developers.cloudflare.com/workers/runtime-apis/bindings/service-bindings/) to the default export defined in the `main` Worker. Use this to write integration tests against your Worker. The `main` Worker runs in the same isolate/context as tests so any global mocks will apply to it too.



    ```js
    import { SELF } from "cloudflare:test";


    it("dispatches fetch event", async () => {
      const response = await SELF.fetch("https://example.com");
      expect(await response.text()).toMatchInlineSnapshot(...);
    });
    ```

* `fetchMock`: import("undici").MockAgent

  * Declarative interface for mocking outbound `fetch()` requests. Deactivated by default and reset before running each test file. Refer to [`undici`'s `MockAgent` documentation](https://undici.nodejs.org/#/docs/api/MockAgent) for more information. Note this only mocks `fetch()` requests for the current test runner Worker. Auxiliary Workers should mock `fetch()`es using the Miniflare `fetchMock`/`outboundService` options. Refer to [Configuration](https://developers.cloudflare.com/workers/testing/vitest-integration/configuration/#workerspooloptions) for more information.



    ```js
    import { fetchMock } from "cloudflare:test";
    import { beforeAll, afterEach, it, expect } from "vitest";


    beforeAll(() => {
      // Enable outbound request mocking...
      fetchMock.activate();
      // ...and throw errors if an outbound request isn't mocked
      fetchMock.disableNetConnect();
    });
    // Ensure we matched every mock we defined
    afterEach(() => fetchMock.assertNoPendingInterceptors());


    it("mocks requests", async () => {
      // Mock the first request to `https://example.com`
      fetchMock
        .get("https://example.com")
        .intercept({ path: "/" })
        .reply(200, "body");


      const response = await fetch("https://example.com/");
      expect(await response.text()).toBe("body");
    });
    ```

### Events

* `createExecutionContext()`: ExecutionContext

  * Creates an instance of the [`context` object](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#parameters) for use as the third argument to ES modules format exported handlers.

* `waitOnExecutionContext(ctx:ExecutionContext)`: Promise\<void>

  * Use this to wait for all Promises passed to `ctx.waitUntil()` to settle, before running test assertions on any side effects. Only accepts instances of `ExecutionContext` returned by `createExecutionContext()`.



    ```ts
    import { env, createExecutionContext, waitOnExecutionContext } from "cloudflare:test";
    import { it, expect } from "vitest";
    import worker from "./index.mjs";


    it("calls fetch handler", async () => {
      const request = new Request("https://example.com");
      const ctx = createExecutionContext();
      const response = await worker.fetch(request, env, ctx);
      await waitOnExecutionContext(ctx);
      expect(await response.text()).toMatchInlineSnapshot(...);
    });
    ```

* `createScheduledController(options?:FetcherScheduledOptions)`: ScheduledController

  * Creates an instance of `ScheduledController` for use as the first argument to modules-format [`scheduled()`](https://developers.cloudflare.com/workers/runtime-apis/handlers/scheduled/) exported handlers.



    ```ts
    import { env, createScheduledController, createExecutionContext, waitOnExecutionContext } from "cloudflare:test";
    import { it, expect } from "vitest";
    import worker from "./index.mjs";


    it("calls scheduled handler", async () => {
      const ctrl = createScheduledController({
        scheduledTime: new Date(1000),
        cron: "30 * * * *"
      });
      const ctx = createExecutionContext();
      await worker.scheduled(ctrl, env, ctx);
      await waitOnExecutionContext(ctx);
    });
    ```

* `createMessageBatch(queueName:string, messages:ServiceBindingQueueMessage[])`: MessageBatch

  * Creates an instance of `MessageBatch` for use as the first argument to modules-format [`queue()`](https://developers.cloudflare.com/queues/configuration/javascript-apis/#consumer) exported handlers.

* `getQueueResult(batch:MessageBatch, ctx:ExecutionContext)`: Promise\<FetcherQueueResult>

  * Gets the acknowledged/retry state of messages in the `MessageBatch`, and waits for all `ExecutionContext#waitUntil()`ed `Promise`s to settle. Only accepts instances of `MessageBatch` returned by `createMessageBatch()`, and instances of `ExecutionContext` returned by `createExecutionContext()`.



    ```ts
    import { env, createMessageBatch, createExecutionContext, getQueueResult } from "cloudflare:test";
    import { it, expect } from "vitest";
    import worker from "./index.mjs";


    it("calls queue handler", async () => {
      const batch = createMessageBatch("my-queue", [
        {
          id: "message-1",
          timestamp: new Date(1000),
          body: "body-1"
        }
      ]);
      const ctx = createExecutionContext();
      await worker.queue(batch, env, ctx);
      const result = await getQueueResult(batch, ctx);
      expect(result.ackAll).toBe(false);
      expect(result.retryBatch).toMatchObject({ retry: false });
      expect(result.explicitAcks).toStrictEqual(["message-1"]);
      expect(result.retryMessages).toStrictEqual([]);
    });
    ```

### Durable Objects

* `runInDurableObject<O extends DurableObject, R>(stub:DurableObjectStub, callback:(instance: O, state: DurableObjectState) => R | Promise<R>)`: Promise\<R>

  * Runs the provided `callback` inside the Durable Object that corresponds to the provided `stub`.



    This temporarily replaces your Durable Object's `fetch()` handler with `callback`, then sends a request to it, returning the result. This can be used to call/spy-on Durable Object methods or seed/get persisted data. Note this can only be used with `stub`s pointing to Durable Objects defined in the `main` Worker.



    ```ts
    export class Counter {
      constructor(readonly state: DurableObjectState) {}


      async fetch(request: Request): Promise<Response> {
        let count = (await this.state.storage.get<number>("count")) ?? 0;
        void this.state.storage.put("count", ++count);
        return new Response(count.toString());
      }
    }
    ```

    ```ts
    import { env, runInDurableObject } from "cloudflare:test";
    import { it, expect } from "vitest";
    import { Counter } from "./index.ts";


    it("increments count", async () => {
      const id = env.COUNTER.newUniqueId();
      const stub = env.COUNTER.get(id);
      let response = await stub.fetch("https://example.com");
      expect(await response.text()).toBe("1");


      response = await runInDurableObject(stub, async (instance: Counter, state) => {
        expect(instance).toBeInstanceOf(Counter);
        expect(await state.storage.get<number>("count")).toBe(1);


        const request = new Request("https://example.com");
        return instance.fetch(request);
      });
      expect(await response.text()).toBe("2");
    });
    ```

* `runDurableObjectAlarm(stub:DurableObjectStub)`: Promise\<boolean>

  * Immediately runs and removes the Durable Object pointed to by `stub`'s alarm if one is scheduled. Returns `true` if an alarm ran, and `false` otherwise. Note this can only be used with `stub`s pointing to Durable Objects defined in the `main` Worker.

* `listDurableObjectIds(namespace:DurableObjectNamespace)`: Promise\<DurableObjectId\[]>

  * Gets the IDs of all objects that have been created in the `namespace`. Respects `isolatedStorage` if enabled, meaning objects created in a different test will not be returned.



    ```ts
    import { env, listDurableObjectIds } from "cloudflare:test";
    import { it, expect } from "vitest";


    it("increments count", async () => {
      const id = env.COUNTER.newUniqueId();
      const stub = env.COUNTER.get(id);
      const response = await stub.fetch("https://example.com");
      expect(await response.text()).toBe("1");


      const ids = await listDurableObjectIds(env.COUNTER);
      expect(ids.length).toBe(1);
      expect(ids[0].equals(id)).toBe(true);
    });
    ```

### D1

* `applyD1Migrations(db:D1Database, migrations:D1Migration[], migrationTableName?:string)`: Promise\<void>

  * Applies all un-applied [D1 migrations](https://developers.cloudflare.com/d1/reference/migrations/) stored in the `migrations` array to database `db`, recording migrations state in the `migrationsTableName` table. `migrationsTableName` defaults to `d1_migrations`. Call the [`readD1Migrations()`](https://developers.cloudflare.com/workers/testing/vitest-integration/configuration/#readd1migrationsmigrationspath) function from the `@cloudflare/vitest-pool-workers/config` package inside Node.js to get the `migrations` array. Refer to the [D1 recipe](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/d1) for an example project using migrations.
