Skip to content

Commit cb31836

Browse files
committed
Add Miniflare + node:test tutorial
1 parent 1bcac4e commit cb31836

File tree

3 files changed

+208
-10
lines changed

3 files changed

+208
-10
lines changed

src/content/docs/workers/testing/index.mdx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,30 @@ sidebar:
55
order: 13
66
---
77

8-
import { DirectoryListing, Render } from "~/components";
8+
import { Render, LinkButton } from "~/components";
99

10-
Review the tools available for testing and debugging Workers.
10+
The Workers platform has a variety of ways to test your applications, depending on your requirements. We recommend using the [Vitest integration](/workers/testing/vitest-integration), which allows for unit testing individual functions within your Worker. However, if you don't use Vitest, both [Miniflare's API](/workers/testing/miniflare/writing-tests) and the [`unstable_startWorker()`](/workers/testing/wrangler) API provide options for testing your Worker in any testing framework.
11+
12+
13+
<LinkButton href="/workers/testing/vitest-integration/get-started/write-your-first-test/">
14+
Write your first test
15+
</LinkButton>
1116

12-
<DirectoryListing />
1317

1418
## Testing comparison matrix
1519

16-
| Feature | Vitest Pool | `unstable_dev()` | Miniflare's API |
20+
| Feature | [Vitest integration](/workers/testing/vitest-integration) | [`unstable_startWorker()`](/workers/testing/wrangler) | [Miniflare's API](/workers/testing/miniflare) |
1721
| ----------------------------------------- | ----------- | ---------------- | --------------- |
1822
| Unit testing ||||
1923
| Integration testing ||||
2024
| Loading Wrangler configuration files ||||
2125
| Bindings directly in tests ||||
2226
| Isolated per-test storage ||||
2327
| Outbound request mocking ||||
24-
| Multiple Worker support || 🚧[^1] ||
28+
| Multiple Worker support || ||
2529
| Direct access to Durable Objects ||||
2630
| Run Durable Object alarms immediately ||||
2731
| List Durable Objects ||||
2832
| Testing service Workers ||||
2933

30-
[^1]: Support for multiple Workers in [`unstable_dev()`](/workers/wrangler/api/#unstable_dev) relies on `wrangler dev`'s service registry which can be unreliable when running multiple tests in parallel.
31-
3234
<Render file="testing-pages-functions" product="workers" />
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
title: Writing tests
3+
pcx_content_type: concept
4+
sidebar:
5+
order: 1
6+
head: []
7+
description: Write integration tests against Workers using Miniflare.
8+
---
9+
10+
:::note
11+
For most users, Cloudflare recommends using the Workers Vitest integration for testing Workers and [Pages Functions](/pages/functions/) projects. [Vitest](https://vitest.dev/) is a popular JavaScript testing framework featuring a very fast watch mode, Jest compatibility, and out-of-the-box support for TypeScript.
12+
:::
13+
14+
import { TabItem, Tabs, Details } from "~/components";
15+
16+
import { FileTree } from '@astrojs/starlight/components';
17+
18+
This guide will instruct you through setting up [Miniflare](/workers/testing/miniflare) for testing your Workers. Miniflare is a low-level API that allows you to fully control how your Workers are run and tested.
19+
20+
To use Miniflare, make sure you've installed the latest version of Miniflare v3:
21+
22+
<Tabs> <TabItem label="npm">
23+
24+
```sh
25+
npm install -D miniflare
26+
```
27+
28+
</TabItem> <TabItem label="yarn">
29+
30+
```sh
31+
yarn add -D miniflare
32+
```
33+
34+
</TabItem> <TabItem label="pnpm">
35+
36+
```sh
37+
pnpm add -D miniflare
38+
```
39+
40+
</TabItem> </Tabs>
41+
42+
The rest of this guide demonstrates concepts with the [`node:test`](https://nodejs.org/api/test.html) testing framework, but any testing framework can be used.
43+
44+
Miniflare is a low-level API that exposes a large variety of configuration options for running your Worker. In most cases, your tests will only need a subset of the available options, but you can refer to the [full API reference](/workers/testing/miniflare/get-started/#reference) to explore what's possible with Miniflare.
45+
46+
Before writing a test, you'll need to create a Worker. Since Miniflare is a low-level API that emulates the Cloudflare platform primitives, your Worker will need to be written in JavaScript or you'll need to [integrate your own build pipeline](#custom-builds) into your testing setup. Here's an example JavaScript-only worker:
47+
48+
```js title="src/index.js"
49+
export default {
50+
async fetch(request) {
51+
return new Response(`Hello World`);
52+
},
53+
};
54+
```
55+
56+
Next, you'll need to create an initial test file:
57+
58+
```js {12,13,14,15,16,17,18,19} title="src/index.test.js"
59+
import assert from "node:assert";
60+
import test, { after, before, describe } from "node:test";
61+
import { Miniflare } from "miniflare";
62+
63+
describe("worker", () => {
64+
/**
65+
* @type {Miniflare}
66+
*/
67+
let worker;
68+
69+
before(async () => {
70+
worker = new Miniflare({
71+
modules: [
72+
{
73+
type: "ESModule",
74+
path: "src/index.js",
75+
},
76+
],
77+
});
78+
await worker.ready;
79+
});
80+
81+
test("hello world", async () => {
82+
assert.strictEqual(
83+
await (await worker.dispatchFetch("http://example.com")).text(),
84+
"Hello World"
85+
);
86+
});
87+
88+
after(async () => {
89+
await worker.dispose();
90+
});
91+
});
92+
```
93+
94+
You should be able to run the above test via `node --test`
95+
96+
The highlighted lines of the test file above demonstrate how to set up Miniflare to run a JavaScript Worker. Once Miniflare has been set up, your individual tests can send requests to the running Worker and assert against the responses. This is the main limitation of using Miniflare for testing your Worker as compared to the [Vitest integration](/workers/testing/vitest-integration/)—all access to your Worker must be through the `dispatchFetch()` Miniflare API, and you cannot unit test individual functions from your Worker.
97+
98+
<Details header="What runtime are tests running in?">
99+
When using the [Vitest integration](/workers/testing/vitest-integration/), your entire test suite runs in [`workerd`](https://github.com/cloudflare/workerd), which is why it's possible to unit test individual functions. By contrast, when using a different testing framework to run run tests via Miniflare, only your Worker itself is running in [`workerd`](https://github.com/cloudflare/workerd)—your test files run in Node.js. This means that importing functions from your Worker into your test files might exhibit different behaviour than you'd see at runtime if the functions rely on `workerd`-specific behaviour.
100+
</Details>
101+
102+
## Interacting with Bindings
103+
104+
The `dispatchFetch()` API from Miniflare allows you to send requests to your Worker and assert that the correct response is returned, but sometimes you need to interact directly with bindings in tests. For use cases like that, Miniflare provides the [`getBindings()`](/workers/testing/miniflare/get-started/#reference) API. For instance, to access an environment variable in your tests, adapt the test file `src/index.test.js` as follows:
105+
106+
```diff lang="js" title="src/index.test.js"
107+
...
108+
describe("worker", () => {
109+
...
110+
before(async () => {
111+
worker = new Miniflare({
112+
...
113+
+ bindings: {
114+
+ FOO: "Hello Bindings",
115+
+ },
116+
});
117+
...
118+
});
119+
120+
test("text binding", async () => {
121+
const bindings = await worker.getBindings();
122+
assert.strictEqual(bindings.FOO, "Hello Bindings");
123+
});
124+
...
125+
});
126+
```
127+
128+
You can also interact with local resources such as KV and R2, using the same API as you would from a Worker. For example, here's how you would interact with a KV namespace:
129+
130+
131+
```diff lang="js" title="src/index.test.js"
132+
...
133+
describe("worker", () => {
134+
...
135+
before(async () => {
136+
worker = new Miniflare({
137+
...
138+
+ kvNamespaces: ["KV"],
139+
});
140+
...
141+
});
142+
143+
test("kv binding", async () => {
144+
const bindings = await worker.getBindings();
145+
await bindings.KV.put("key", "value");
146+
assert.strictEqual(await bindings.KV.get("key"), "value");
147+
});
148+
...
149+
});
150+
```
151+
152+
## More complex Workers
153+
154+
The example given above shows how to test a simple Worker consisting of a single JavaScript file. However, most real-world Workers are more complex than that. Miniflare supports providing all constituent files of your Worker directly using the API:
155+
156+
```js
157+
new Miniflare({
158+
modules: [
159+
{
160+
type: "ESModule",
161+
path: "src/index.js",
162+
},
163+
{
164+
type: "ESModule",
165+
path: "src/imported.js",
166+
},
167+
],
168+
});
169+
```
170+
171+
This can be a bit cumbersome as your Worker grows. To help with thi, Miniflare can also crawl your module graph to automatically figure out which modules to include:
172+
173+
```js
174+
new Miniflare({
175+
scriptPath: "src/index-with-imports.js",
176+
modules: true,
177+
modulesRules: [{ type: "ESModule", include: ["**/*.js"] }],
178+
});
179+
```
180+
181+
## Custom builds
182+
183+
In many real-world cases, Workers are not written as plain JavaScript, but are instead written as multiple TypeScript files importing from npm packages etc... that are then bundled by a build tool. When testing your Worker via Miniflare directly you need to run this build tool before your tests. Exactly how this build is run will depend on the specific test framework you use, but for `node:test` it would likely be in a `setup()` hook. For example, if you use [Wrangler](/workers/wrangler/) to build and deploy your Worker, you could spawn a `wrangler build` command:
184+
185+
```js
186+
before(() => {
187+
spawnSync("npx wrangler build -c wrangler-build.json", {
188+
shell: true,
189+
stdio: "pipe",
190+
});
191+
});
192+
```
193+
194+
195+
196+

src/content/docs/workers/testing/local-development.mdx renamed to src/content/docs/workers/wrangler/local-development.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ head: []
77
description: Develop your Workers locally via Wrangler.
88
---
99

10-
Cloudflare Workers and most connected resources can be fully developed and tested locally - providing confidence that the applications you build locally will work the same way in production. This allows you to be more efficient and effective by providing a faster feedback loop and removing the need to test against remote resources. Local development runs against the same production runtime used by Cloudflare Workers, [workerd](https://github.com/cloudflare/workerd).
10+
Cloudflare Workers and most connected resources can be fully developed and tested locallyproviding confidence that the applications you build locally will work the same way in production. This allows you to be more efficient and effective by providing a faster feedback loop and removing the need to test against remote resources. Local development runs against the same production runtime used by Cloudflare Workers, [workerd](https://github.com/cloudflare/workerd).
1111

12-
In addition to testing Workers locally with [`wrangler dev`](/workers/wrangler/commands/#dev), the use of Miniflare allows you to test other Developer Platform products locally, such as [R2](/r2/), [KV](/kv/), [D1](/d1/), and [Durable Objects](/durable-objects/).
12+
When devloping Workers locally with [`wrangler dev`](/workers/wrangler/commands/#dev), you can access local emulators of resources such as [R2](/r2/), [KV](/kv/), [D1](/d1/), and [Durable Objects](/durable-objects/).
1313

1414
## Start a local development server
1515

@@ -35,7 +35,7 @@ npx wrangler dev
3535
| ----------------------------------- | ------------------- | -------------------- |
3636
| AI |[^1] ||
3737
| Assets |||
38-
| Analytics Engine | ||
38+
| Analytics Engine | ||
3939
| Browser Rendering |||
4040
| D1 |||
4141
| Durable Objects |||

0 commit comments

Comments
 (0)