This guide will instruct you through installing and setting up the `@cloudflare/vitest-pool-workers` package. This will help you get started writing tests against your Workers using Vitest. The `@cloudflare/vitest-pool-workers` package works by running code inside a Cloudflare Worker that Vitest would usually run inside a [Node.js worker thread](https://nodejs.org/api/worker_threads.html). For examples of tests using `@cloudflare/vitest-pool-workers`, refer to [Recipes](https://developers.cloudflare.com/workers/testing/vitest-integration/recipes/).

## Prerequisites

* Open the root directory of your Worker or [create a new Worker](https://developers.cloudflare.com/workers/get-started/guide/#1-create-a-new-worker-project).

* Make sure that your Worker is developed using the ES modules format. To migrate from the service worker format to the ES modules format, refer to the [Migrate to the ES modules format](https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/) guide.

* In your project's [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/configuration/), define a [compatibility date](https://developers.cloudflare.com/workers/configuration/compatibility-dates/) of `2022-10-31` or higher, and include `nodejs_compat` in your [compatibility flags](https://developers.cloudflare.com/workers/configuration/compatibility-flags).

## Install Vitest and `@cloudflare/vitest-pool-workers`

Open a terminal window and make sure you are in your project's root directory. Once you have confirmed that, run:

```sh
npm install vitest@~3.0.0 --save-dev --save-exact
npm install @cloudflare/vitest-pool-workers --save-dev
```

The above commands will add the packages to your `package.json` file and install them as dev dependencies.

Note

Currently, the `@cloudflare/vitest-pool-workers` package *only* works with Vitest 2.0.x - 3.0.x.

## Define Vitest configuration

If you do not already have a `vitest.config.js` or `vitest.config.ts` file, you will need to create one and define the following configuration. You can reference a Wrangler file to leverage its `main` entry point, [compatibility settings](https://developers.cloudflare.com/workers/configuration/compatibility-dates/), and [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/).

```js
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";


export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        wrangler: { configPath: "./wrangler.toml" },
      },
    },
  },
});
```

Note

For a full list of available configuration options, refer to [Configuration](https://developers.cloudflare.com/workers/testing/vitest-integration/configuration/).

### Add configuration options via Miniflare

Under the hood, the Workers Vitest integration uses [Miniflare](https://miniflare.dev), the same simulator that powers [`wrangler dev`'s](https://developers.cloudflare.com/workers/wrangler/commands/#dev) local mode. Options can be passed directly to Miniflare for advanced configuration.

For example, to add bindings that will be used in tests, you can add `miniflare` to `defineWorkersConfig`:

```js
export default defineWorkersConfig({
  test: {
    poolOptions: {
      workers: {
        main: "./src/index.ts",
        miniflare: {
          kvNamespaces: ["TEST_NAMESPACE"],
        },
      },
    },
  },
});
```

This configuration would add a KV namespace `TEST_NAMESPACE` that was only accessible in tests. Using this method, you can add or override existing bindings like Durable Objects or service bindings.

Note

For a full list of available Miniflare options, refer to the [Miniflare `WorkersOptions` API documentation](https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare#interface-workeroptions).

## Define types

If you are using TypeScript, you will need to define types for Cloudflare Workers and `cloudflare:test` to make sure they are detected appropriately. Add a `tsconfig.json` in the same folder as your tests (that is, `test`) and add the following:

```js
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "moduleResolution": "bundler",
    "types": [
      "@cloudflare/workers-types/experimental",
      "@cloudflare/vitest-pool-workers"
    ]
  },
  "include": ["./**/*.ts", "../src/env.d.ts"]
}
```

Save this file, and you are ready to write your first test.

## Write tests

If you created a basic Worker via the guide listed above, you should have the following fetch handler in the `src` folder:

* JavaScript

  ```js
  export default {
    async fetch(request, env, ctx) {
      return new Response("Hello World!");
    },
  };
  ```

* TypeScript

  ```ts
  export default {
    async fetch(request, env, ctx): Promise<Response> {
      return new Response("Hello World!");
    },
  } satisfies ExportedHandler<Env>;
  ```

This Worker receives a request, and returns a response of `"Hello World!"`. In order to test this, create a `test` folder with the following test file:

* JavaScript

  ```js
  import {
    env,
    createExecutionContext,
    waitOnExecutionContext,
  } from "cloudflare:test";
  import { describe, it, expect } from "vitest";
  // Could import any other source file/function here
  import worker from "../src";


  describe("Hello World worker", () => {
    it("responds with Hello World!", async () => {
      const request = new Request("http://example.com");
      // Create an empty context to pass to `worker.fetch()`
      const ctx = createExecutionContext();
      const response = await worker.fetch(request, env, ctx);
      // Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
      await waitOnExecutionContext(ctx);
      expect(await response.text()).toBe("Hello World!");
    });
  });
  ```

* TypeScript

  ```ts
  import {
    env,
    createExecutionContext,
    waitOnExecutionContext,
  } from "cloudflare:test";
  import { describe, it, expect } from "vitest";
  // Could import any other source file/function here
  import worker from "../src";


  // For now, you'll need to do something like this to get a correctly-typed
  // `Request` to pass to `worker.fetch()`.
  const IncomingRequest = Request<unknown, IncomingRequestCfProperties>;


  describe("Hello World worker", () => {
    it("responds with Hello World!", async () => {
      const request = new IncomingRequest("http://example.com");
      // Create an empty context to pass to `worker.fetch()`
      const ctx = createExecutionContext();
      const response = await worker.fetch(request, env, ctx);
      // Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
      await waitOnExecutionContext(ctx);
      expect(await response.text()).toBe("Hello World!");
    });
  });
  ```

Add functionality to handle a `404` path on the Worker. This functionality will return the text `Not found` as well as the status code `404`.

* JavaScript

  ```js
  export default {
    async fetch(request, env, ctx) {
      const { pathname } = new URL(request.url);


      if (pathname === "/404") {
        return new Response("Not found", { status: 404 });
      }


      return new Response("Hello World!");
    },
  };
  ```

* TypeScript

  ```ts
  export default {
    async fetch(request, env, ctx): Promise<Response> {
      const { pathname } = new URL(request.url);


      if (pathname === "/404") {
        return new Response("Not found", { status: 404 });
      }


      return new Response("Hello World!");
    },
  } satisfies ExportedHandler<Env>;
  ```

To test this, add the following to your test file:

* JavaScript

  ```js
  it("responds with not found and proper status for /404", async () => {
    const request = new Request("http://example.com/404");
    // Create an empty context to pass to `worker.fetch()`
    const ctx = createExecutionContext();
    const response = await worker.fetch(request, env, ctx);
    // Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
    await waitOnExecutionContext(ctx);
    expect(await response.status).toBe(404);
    expect(await response.text()).toBe("Not found");
  });
  ```

* TypeScript

  ```ts
  it("responds with not found and proper status for /404", async () => {
    const request = new IncomingRequest("http://example.com/404");
    // Create an empty context to pass to `worker.fetch()`
    const ctx = createExecutionContext();
    const response = await worker.fetch(request, env, ctx);
    // Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
    await waitOnExecutionContext(ctx);
    expect(await response.status).toBe(404);
    expect(await response.text()).toBe("Not found");
  });
  ```

## Related resources

* [`@cloudflare/vitest-pool-workers` GitHub repository](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples) - Examples of tests using the `@cloudflare/vitest-pool-workers` package.
