# Write Vitest Tests for a Cloudflare Worker

Yes. An agent writes Vitest tests that run your Worker inside workerd with a local D1 database and its migrations applied, then opens a pull request.

[Run this on Rush](https://cloud.getrush.ai/run/write-workers-vitest-tests/cloudflare-workers/), in a Project that has your repository.

## What the agent does

The agent reads the Worker and its bindings first. In cloudflare/templates' `d1-template`, `wrangler.json` sets `main` to `src/index.ts`, `compatibility_date` 2025-10-08, and one D1 binding named `DB`. `package.json` pins `wrangler` 4.136.1 and TypeScript 5.9.3, and its scripts apply migrations with `wrangler d1 migrations apply DB --local` before `wrangler dev`. There is one migration, `migrations/0001_create_comments_table.sql`, which creates `comments` (`id`, `author`, `content`) and inserts three rows. There is no test runner and no test file.

Then it reads what the Worker does. `src/index.ts` has a single `fetch` handler: whatever the path or method, it runs `SELECT * FROM comments LIMIT 3` and returns `renderHtml(JSON.stringify(results, null, 2))` as `text/html`. So "each route" here is one handler that answers every path the same way, and the agent tests that explicitly: `/`, an unknown path and a `POST` all return the same page, which is worth knowing before someone assumes there is routing.

For the setup it uses Cloudflare's own pool: `@cloudflare/vitest-pool-workers` with a `vitest.config.ts` built on `defineWorkersConfig`, pointing `wrangler.configPath` at `./wrangler.json` so the tests get the same `DB` binding. It reads the migrations with `readD1Migrations` in the config, passes them as a test binding, and applies them in a setup file with `applyD1Migrations`, so every test file starts from the real schema and seed rows. Tests call the Worker through `SELF.fetch` from `cloudflare:test`, inside workerd, and read the database through `env.DB`.

The tests check the migration (the table, its columns and the three seed rows), that the page lists at most three comments, and that a comment inserted in a test shows up and one beyond the limit does not. They also check escaping, and find a real defect: `renderHtml` interpolates the JSON straight into the HTML, and `JSON.stringify` does not escape `<`, so a comment whose content is `<script>` reaches the page as markup. The agent keeps that test, marks it as expected to fail, and explains it in the pull request.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "In d1-template, write tests with @cloudflare/vitest-pool-workers that run the Worker against a real local D1 database, covering each route and the migration. Run them and open a pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-workers"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a pull request that adds `vitest.config.ts`, a setup file that applies the D1 migrations, `test/index.spec.ts`, a `tsconfig` entry for the `cloudflare:test` types, and Vitest with `@cloudflare/vitest-pool-workers` in `package.json` and `package-lock.json` at versions the pool supports together. `src/` and `migrations/` are unchanged.

The description lists each test with what it proves, explains that the Worker has one handler for every path, and names the expected failure: comment content rendered as raw HTML in `renderHtml.ts`. The session's trajectory keeps each `npx vitest run` with its output from inside workerd.

Before merging, a reviewer checks the pinned Vitest and pool versions match what the team runs, decides whether the escaping defect is fixed now (escape `<`, `>` and `&` before interpolation) or tracked, and adds `vitest run` to CI. A follow-up on the same session can fix `renderHtml` and turn that test green.

## Run it on every new D1 migration

When a pull request adds a file under `migrations/`, a GitHub webhook can send this request with that pull request in `resources`, asking the agent to extend the tests for the new schema and run them. Because the setup file applies every migration in order, a migration that breaks an earlier one fails in the sandbox before `wrangler d1 migrations apply --remote` ever runs.

Set a webhook URL on the API key and Rush POSTs `run.completed` or `run.failed` when the turn finishes, so your server can post the result on the pull request before the deploy step's `predeploy` script applies it remotely.

## Why run it on Rush?

Workers tests are only meaningful inside workerd with real bindings, and getting `@cloudflare/vitest-pool-workers`, a compatible Vitest, D1 migrations and the `cloudflare:test` types to agree is where most attempts stop. In its own sandbox the agent installs them, runs the suite, and reads each error until it passes, with no Cloudflare account and nothing deployed.

The proof is in the run: every `vitest run` and its output is in the trajectory, and the defect the tests found is named with its file. Because runs are isolated, the same request can add tests to every Worker in a repository of templates at once, each in its own pull request.

## Frequently asked questions

### Does it need my Cloudflare account?

No. The pool runs the Worker in workerd locally with a local D1 database, so nothing is deployed and no API token is used. The `database_id` in `wrangler.json` is never contacted by the tests.

### Is the D1 database real or mocked?

Real: it is a local D1 database inside the test runtime, with your SQL migrations applied by `applyD1Migrations`. Queries in the tests run the same SQL engine the Worker uses in development.

### My Worker has routes and KV or Durable Objects. Does this still work?

Yes. The pool reads every binding from your Wrangler config, so KV namespaces, R2 buckets and Durable Objects are available on `env` in tests the same way D1 is. With a router, the agent writes a test per route and method instead of the single-handler checks this template needs.

### Which Vitest version does it use?

The one `@cloudflare/vitest-pool-workers` declares as its peer dependency, since the pool supports specific Vitest releases. The agent installs both together and the lockfile records the exact pair.
