diff --git a/src/content/docs/agents/getting-started/testing-your-agent.mdx b/src/content/docs/agents/getting-started/testing-your-agent.mdx index e8f0e7fad05b8de..1bb97c45d6348fd 100644 --- a/src/content/docs/agents/getting-started/testing-your-agent.mdx +++ b/src/content/docs/agents/getting-started/testing-your-agent.mdx @@ -22,46 +22,21 @@ The `agents-starter` template and new Cloudflare Workers projects already includ Before you write your first test, install the necessary packages: ```sh -npm install vitest@~3.0.0 --save-dev --save-exact -npm install @cloudflare/vitest-pool-workers --save-dev +npm install vitest@^4.1.0 @cloudflare/vitest-pool-workers --save-dev ``` -Ensure that your `vitest.config.js` file is identical to the following: +Ensure that your `vitest.config.js` has the `cloudflareTest` plugin configured: ```js -import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; - -export default defineWorkersConfig({ - test: { - poolOptions: { - workers: { - wrangler: { configPath: "./wrangler.jsonc" }, - }, - }, - }, -}); -``` - -### Add the Agent configuration - -Add a `durableObjects` configuration to `vitest.config.js` with the name of your Agent class: - -```js -import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; - -export default defineWorkersConfig({ - test: { - poolOptions: { - workers: { - main: "./src/index.ts", - miniflare: { - durableObjects: { - NAME: "MyAgent", - }, - }, - }, - }, - }, +import { cloudflareTest } from "@cloudflare/vitest-pool-workers"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + plugins: [ + cloudflareTest({ + wrangler: { configPath: "./wrangler.jsonc" }, + }), + ], }); ``` @@ -76,11 +51,10 @@ Review the [Vitest documentation](https://vitest.dev/) for more information on t Tests use the `vitest` framework. A basic test suite for your Agent can validate how your Agent responds to requests, but can also unit test your Agent's methods and state. ```ts +import { env, exports } from "cloudflare:workers"; import { - env, createExecutionContext, waitOnExecutionContext, - SELF, } from "cloudflare:test"; import { describe, it, expect } from "vitest"; import worker from "../src"; @@ -104,7 +78,7 @@ describe("make a request to my Agent", () => { it("also responds with state", async () => { const request = new Request("http://example.com/agent/my-agent/agent-123"); - const response = await SELF.fetch(request); + const response = await exports.default.fetch(request); expect(await response.text()).toMatchObject({ hello: "from your agent" }); }); }); diff --git a/src/content/docs/durable-objects/best-practices/rules-of-durable-objects.mdx b/src/content/docs/durable-objects/best-practices/rules-of-durable-objects.mdx index 84a75ff040d60b5..970a60460bfc87b 100644 --- a/src/content/docs/durable-objects/best-practices/rules-of-durable-objects.mdx +++ b/src/content/docs/durable-objects/best-practices/rules-of-durable-objects.mdx @@ -1496,7 +1496,7 @@ This pattern does not scale. As traffic increases, the single Durable Object bec ### Test with Vitest and plan for class migrations -Use `@cloudflare/vitest-pool-workers` for testing Durable Objects. The integration provides isolated storage per test and utilities for direct instance access. +Use `@cloudflare/vitest-pool-workers` for testing Durable Objects. The integration provides utilities for direct instance access. ```ts @@ -1508,7 +1508,7 @@ import { import { describe, it, expect } from "vitest"; describe("ChatRoom", () => { -// Each test gets isolated storage automatically + it("should send and retrieve messages", async () => { const id = env.CHAT_ROOM.idFromName("test-room"); const stub = env.CHAT_ROOM.get(id); @@ -1530,7 +1530,7 @@ const stub = env.CHAT_ROOM.get(id); const count = state.storage.sql .exec<{ count: number }>("SELECT COUNT(*) as count FROM messages") .one(); - expect(count.count).toBe(0); // Fresh instance due to test isolation + expect(count.count).toBe(2); }); // Trigger alarms immediately without waiting diff --git a/src/content/docs/durable-objects/examples/testing-with-durable-objects.mdx b/src/content/docs/durable-objects/examples/testing-with-durable-objects.mdx index 30795e9c3ac010d..979b289081fc3c5 100644 --- a/src/content/docs/durable-objects/examples/testing-with-durable-objects.mdx +++ b/src/content/docs/durable-objects/examples/testing-with-durable-objects.mdx @@ -176,7 +176,6 @@ import { env } from "cloudflare:workers"; import { describe, it, expect, beforeEach } from "vitest"; describe("Counter Durable Object", () => { - // Each test gets isolated storage automatically it("should increment the counter", async () => { const id = env.COUNTER.idFromName("test-counter"); const stub = env.COUNTER.get(id); @@ -192,17 +191,11 @@ describe("Counter Durable Object", () => { expect(count3).toBe(3); }); - it("should track separate counters independently", async () => { + it("should persist storage within a test file", async () => { const id = env.COUNTER.idFromName("test-counter"); const stub = env.COUNTER.get(id); - await stub.increment("counter-a"); - await stub.increment("counter-a"); - await stub.increment("counter-b"); - - expect(await stub.getCount("counter-a")).toBe(2); - expect(await stub.getCount("counter-b")).toBe(1); - expect(await stub.getCount("counter-c")).toBe(0); + expect(await stub.getCount()).toBe(3); }); it("should reset a counter", async () => { @@ -342,40 +335,6 @@ describe("Direct Durable Object access", () => { ``` -### Test isolation - -Each test automatically gets isolated storage. Durable Objects created in one test do not affect other tests: - - -```ts -import { env } from "cloudflare:workers"; -import { listDurableObjectIds } from "cloudflare:test"; -import { describe, it, expect } from "vitest"; - -describe("Test isolation", () => { - it("first test: creates a Durable Object", async () => { - const id = env.COUNTER.idFromName("isolated-counter"); - const stub = env.COUNTER.get(id); - - await stub.increment(); - await stub.increment(); - expect(await stub.getCount()).toBe(2); - }); - - it("second test: previous Durable Object does not exist", async () => { - // The Durable Object from the previous test is automatically cleaned up - const ids = await listDurableObjectIds(env.COUNTER); - expect(ids.length).toBe(0); - - // Creating the same ID gives a fresh instance - const id = env.COUNTER.idFromName("isolated-counter"); - const stub = env.COUNTER.get(id); - expect(await stub.getCount()).toBe(0); - }); -}); -``` - - ### Testing SQLite storage SQLite-backed Durable Objects work seamlessly in tests. The SQL API is available when your Durable Object class is configured with `new_sqlite_classes` in your Wrangler configuration: diff --git a/src/content/docs/workers/testing/vitest-integration/known-issues.mdx b/src/content/docs/workers/testing/vitest-integration/known-issues.mdx index df3ea817044df9d..d83fc179637f121 100644 --- a/src/content/docs/workers/testing/vitest-integration/known-issues.mdx +++ b/src/content/docs/workers/testing/vitest-integration/known-issues.mdx @@ -21,10 +21,6 @@ Vitest's [fake timers](https://vitest.dev/guide/mocking.html#timers) do not appl Dynamic `import()` statements do not work inside `export default { ... }` handlers when writing integration tests with `exports.default.fetch()`, or inside Durable Object event handlers. You must import and call your handlers directly, or use static `import` statements in the global scope. -### Durable Object alarms - -Durable Object alarms are not reset between test runs and do not respect isolated storage. Ensure you delete or run all alarms with [`runDurableObjectAlarm()`](/workers/testing/vitest-integration/test-apis/#durable-objects) scheduled in each test before finishing the test. - ### WebSockets Using WebSockets with Durable Objects is not supported with per-file storage isolation. To work around this, run your tests with shared storage using `--max-workers=1 --no-isolate`. diff --git a/src/content/docs/workers/testing/vitest-integration/recipes.mdx b/src/content/docs/workers/testing/vitest-integration/recipes.mdx index 7d14e7a85776d56..fc7b1393472efd4 100644 --- a/src/content/docs/workers/testing/vitest-integration/recipes.mdx +++ b/src/content/docs/workers/testing/vitest-integration/recipes.mdx @@ -10,21 +10,22 @@ description: Examples that demonstrate how to write unit and integration Recipes are examples that help demonstrate how to write unit tests and integration tests for Workers projects using the [`@cloudflare/vitest-pool-workers`](https://www.npmjs.com/package/@cloudflare/vitest-pool-workers) package. -- [Basic unit and integration tests for Workers using `SELF`](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/basics-unit-integration-self) -- [Basic unit and integration tests for Pages Functions using `SELF`](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/pages-functions-unit-integration-self) +- [Basic unit and integration tests for Workers using `exports.default`](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/basics-unit-integration-self) +- [Basic unit and integration tests for Pages Functions using `exports.default`](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/pages-functions-unit-integration-self) - [Basic integration tests using an auxiliary Worker](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/basics-integration-auxiliary) -- [Basic integration test for Workers with static assets](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/workers-assets) -- [Isolated tests using KV, R2 and the Cache API](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/kv-r2-caches) -- [Isolated tests using D1 with migrations](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/d1) -- [Isolated tests using Durable Objects with direct access](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/durable-objects) -- [Isolated tests using Workflows](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/workflows) +- [Tests using KV, R2 and the Cache API](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/kv-r2-caches) +- [Tests using D1 with migrations](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/d1) +- [Tests using Durable Objects with direct access](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/durable-objects) +- [Tests using Workflows](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/workflows) - [Tests using Queue producers and consumers](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/queues) +- [Tests using Pipelines](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/pipelines) - [Tests using Hyperdrive with a Vitest managed TCP server](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/hyperdrive) -- [Tests using declarative/imperative outbound request mocks](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/request-mocking) +- [Tests using declarative (MSW) / imperative outbound request mocks](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/request-mocking) - [Tests using multiple auxiliary Workers and request mocks](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/multiple-workers) - [Tests importing WebAssembly modules](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/web-assembly) - [Tests using JSRPC with entrypoints and Durable Objects](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/rpc) - [Tests using `ctx.exports` to access Worker exports](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/context-exports) -- [Integration test with static assets and Puppeteer](https://github.com/GregBrimble/puppeteer-vitest-workers-assets) - [Resolving modules with Vite Dependency Pre-Bundling](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/module-resolution) - [Mocking Workers AI and Vectorize bindings in unit tests](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/ai-vectorize) +- [Tests using the Images binding](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/images) +- [Tests mocking Workers Assets](https://github.com/cloudflare/workers-sdk/tree/main/fixtures/vitest-pool-workers-examples/workers-assets) \ No newline at end of file diff --git a/src/content/docs/workers/testing/vitest-integration/write-your-first-test.mdx b/src/content/docs/workers/testing/vitest-integration/write-your-first-test.mdx index c135ce09566b8fd..63358a036289ffe 100644 --- a/src/content/docs/workers/testing/vitest-integration/write-your-first-test.mdx +++ b/src/content/docs/workers/testing/vitest-integration/write-your-first-test.mdx @@ -103,16 +103,6 @@ You should also add the output of `wrangler types` to the `include` array so tha ``` -You also need to define the type of the `env` object that is provided to your tests. Create an `env.d.ts` file in your tests folder, and declare the `ProvidedEnv` interface by extending the `Env` interface that is generated by `wrangler types`. - -```ts title="test/env.d.ts" -declare module "cloudflare:workers" { - // ProvidedEnv controls the type of `import("cloudflare:workers").env` - interface ProvidedEnv extends Env {} -} -``` - -If your test bindings differ from the bindings in your Wrangler config, you should type them here in `ProvidedEnv`. ## Writing tests