Skip to content

Commit 30eb97f

Browse files
authored
Add miniflare docs (#18690)
1 parent 2b9c70e commit 30eb97f

28 files changed

+1778
-27
lines changed

src/content/docs/workers/testing/integration-testing.mdx

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,25 @@ sidebar:
55
order: 3
66
head: []
77
description: Test multiple units of your Worker working together.
8-
98
---
109

11-
import { Render } from "~/components"
10+
import { Render } from "~/components";
1211

1312
Integration tests test multiple units of your Worker together by sending HTTP requests to your Worker and asserting on the HTTP responses. As an example, consider the following Worker:
1413

1514
```js
1615
export function add(a, b) {
17-
return a + b;
16+
return a + b;
1817
}
1918

2019
export default {
21-
async fetch(request) {
22-
const url = new URL(request.url);
23-
const a = parseInt(url.searchParams.get("a"));
24-
const b = parseInt(url.searchParams.get("b"));
25-
return new Response(add(a, b));
26-
}
27-
}
20+
async fetch(request) {
21+
const url = new URL(request.url);
22+
const a = parseInt(url.searchParams.get("a"));
23+
const b = parseInt(url.searchParams.get("b"));
24+
return new Response(add(a, b));
25+
},
26+
};
2827
```
2928

3029
An integration test for this Worker might look like the following example:
@@ -75,16 +74,14 @@ it("dispatches fetch event", async () => {
7574
});
7675
```
7776

78-
Instead of running the Worker-under-test in the same Worker as the test runner like `SELF`, this example defines the Worker-under-test as an *auxiliary* Worker. This means the Worker runs in a separate isolate to the test runner, with a different global scope. The Worker-under-test runs in an environment closer to production, but Vite transformations and hot-module-reloading aren't applied to the Worker—you must compile your TypeScript to JavaScript beforehand.
77+
Instead of running the Worker-under-test in the same Worker as the test runner like `SELF`, this example defines the Worker-under-test as an _auxiliary_ Worker. This means the Worker runs in a separate isolate to the test runner, with a different global scope. The Worker-under-test runs in an environment closer to production, but Vite transformations and hot-module-reloading aren't applied to the Worker—you must compile your TypeScript to JavaScript beforehand.
7978

8079
Auxiliary Workers cannot be configured from `wrangler.toml` files. You must use Miniflare [`WorkerOptions`](https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare#interface-workeroptions) in `vitest.config.ts`.
8180

8281
:::note
8382

84-
8583
This method is less recommended than `SELF` for integration tests because of its developer experience. However, it can be useful when you are testing multiple Workers. You can define multiple Workers by different names in `vitest.config.ts` and reference them via `env`.
8684

87-
8885
:::
8986

9087
## Wrangler's `unstable_dev()` API
@@ -97,51 +94,47 @@ import { unstable_dev } from "wrangler";
9794

9895
const worker = await unstable_dev("./index.mjs");
9996
try {
100-
const response = await worker.fetch("/?a=1&b=2");
101-
assert.strictEqual(await response.text(), "3");
97+
const response = await worker.fetch("/?a=1&b=2");
98+
assert.strictEqual(await response.text(), "3");
10299
} finally {
103-
await worker.stop();
100+
await worker.stop();
104101
}
105102
```
106103

107104
:::note
108105

109-
110106
If you have been using `unstable_dev()` for integration testing and want to migrate to Cloudflare's Vitest integration, refer to the [Migrate from `unstable_dev` migration guide](/workers/testing/vitest-integration/get-started/migrate-from-unstable-dev/) for more information.
111107

112-
113108
:::
114109

115110
## Miniflare's API
116111

117-
If you would like to write integration tests for multiple Workers, need direct access to [bindings](/workers/runtime-apis/bindings/) outside your Worker in tests, or have another advanced use case, consider using [Miniflare's API](https://github.com/cloudflare/workers-sdk/blob/main/packages/miniflare/README.md) directly. Miniflare is the foundation for the other testing tools on this page, exposing a JavaScript API for the [`workerd` runtime](https://github.com/cloudflare/workerd) and local simulators for the other Developer Platform products. Unlike `unstable_dev()`, Miniflare does not automatically load options from your Wrangler configuration file.
112+
If you would like to write integration tests for multiple Workers, need direct access to [bindings](/workers/runtime-apis/bindings/) outside your Worker in tests, or have another advanced use case, consider using [Miniflare's API](/workers/testing/miniflare) directly. Miniflare is the foundation for the other testing tools on this page, exposing a JavaScript API for the [`workerd` runtime](https://github.com/cloudflare/workerd) and local simulators for the other Developer Platform products. Unlike `unstable_dev()`, Miniflare does not automatically load options from your Wrangler configuration file.
118113

119114
```js
120115
import assert from "node:assert";
121116
import { Miniflare } from "miniflare";
122117

123118
const mf = new Miniflare({
124-
modules: true,
125-
scriptPath: "./index.mjs",
119+
modules: true,
120+
scriptPath: "./index.mjs",
126121
});
127122
try {
128-
const response = await mf.dispatchFetch("http://example.com/?a=1&b=2");
129-
assert.strictEqual(await response.text(), "3");
123+
const response = await mf.dispatchFetch("http://example.com/?a=1&b=2");
124+
assert.strictEqual(await response.text(), "3");
130125
} finally {
131-
await mf.dispose();
126+
await mf.dispose();
132127
}
133128
```
134129

135130
:::note
136131

137-
138132
If you have been using the test environments from Miniflare 2 for integration testing and want to migrate to Cloudflare's Vitest integration, refer to the [Migrate from Miniflare 2 migration guide](/workers/testing/vitest-integration/get-started/migrate-from-miniflare-2/) for more information.
139133

140-
141134
:::
142135

143136
<Render file="testing-pages-functions" product="workers" />
144137

145138
## Related Resources
146139

147-
* [Recipes](/workers/testing/vitest-integration/recipes/) - Example integration tests for Workers using the Workers Vitest integration.
140+
- [Recipes](/workers/testing/vitest-integration/recipes/) - Example integration tests for Workers using the Workers Vitest integration.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
order: 8
3+
title: "📅 Compatibility Dates"
4+
---
5+
6+
- [Compatibility Dates Reference](/workers/configuration/compatibility-dates)
7+
8+
## Compatibility Dates
9+
10+
Miniflare uses compatibility dates to opt-into backwards-incompatible changes
11+
from a specific date. If one isn't set, it will default to some time far in the
12+
past.
13+
14+
```js
15+
const mf = new Miniflare({
16+
compatibilityDate: "2021-11-12",
17+
});
18+
```
19+
20+
## Compatibility Flags
21+
22+
Miniflare also lets you opt-in/out of specific changes using compatibility
23+
flags:
24+
25+
```js
26+
const mf = new Miniflare({
27+
compatibilityFlags: [
28+
"formdata_parser_supports_files",
29+
"durable_object_fetch_allows_relative_url",
30+
],
31+
});
32+
```
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
---
2+
order: 0
3+
title: "📨 Fetch Events"
4+
---
5+
6+
- [`FetchEvent` Reference](/workers/runtime-apis/handlers/fetch/)
7+
8+
## HTTP Requests
9+
10+
Whenever an HTTP request is made, a `Request` object is dispatched to your worker, then the generated `Response` is returned. The
11+
`Request` object will include a
12+
[`cf` object](/workers/runtime-apis/request#incomingrequestcfproperties).
13+
Miniflare will log the method, path, status, and the time it took to respond.
14+
15+
If the Worker throws an error whilst generating a response, an error page
16+
containing the stack trace is returned instead.
17+
18+
## Dispatching Events
19+
20+
When using the API, the `dispatchFetch` function can be used to dispatch `fetch`
21+
events to your Worker. This can be used for testing responses. `dispatchFetch`
22+
has the same API as the regular `fetch` method: it either takes a `Request`
23+
object, or a URL and optional `RequestInit` object:
24+
25+
```js
26+
import { Miniflare, Request } from "miniflare";
27+
28+
const mf = new Miniflare({
29+
modules: true,
30+
script: `
31+
export default {
32+
async fetch(request, env, ctx) {
33+
const body = JSON.stringify({
34+
url: event.request.url,
35+
header: event.request.headers.get("X-Message"),
36+
});
37+
return new Response(body, {
38+
headers: { "Content-Type": "application/json" },
39+
});
40+
})
41+
}
42+
`,
43+
});
44+
45+
let res = await mf.dispatchFetch("http://localhost:8787/");
46+
console.log(await res.json()); // { url: "http://localhost:8787/", header: null }
47+
48+
res = await mf.dispatchFetch("http://localhost:8787/1", {
49+
headers: { "X-Message": "1" },
50+
});
51+
console.log(await res.json()); // { url: "http://localhost:8787/1", header: "1" }
52+
53+
res = await mf.dispatchFetch(
54+
new Request("http://localhost:8787/2", {
55+
headers: { "X-Message": "2" },
56+
}),
57+
);
58+
console.log(await res.json()); // { url: "http://localhost:8787/2", header: "2" }
59+
```
60+
61+
When dispatching events, you are responsible for adding
62+
[`CF-*` headers](https://support.cloudflare.com/hc/en-us/articles/200170986-How-does-Cloudflare-handle-HTTP-Request-headers-)
63+
and the
64+
[`cf` object](/workers/runtime-apis/request#incomingrequestcfproperties).
65+
This lets you control their values for testing:
66+
67+
```js
68+
const res = await mf.dispatchFetch("http://localhost:8787", {
69+
headers: {
70+
"CF-IPCountry": "GB",
71+
},
72+
cf: {
73+
country: "GB",
74+
},
75+
});
76+
```
77+
78+
## Upstream
79+
80+
Miniflare will call each `fetch` listener until a response is returned. If no
81+
response is returned, or an exception is thrown and `passThroughOnException()`
82+
has been called, the response will be fetched from the specified upstream
83+
instead:
84+
85+
```js
86+
import { Miniflare } from "miniflare";
87+
88+
const mf = new Miniflare({
89+
script: `
90+
addEventListener("fetch", (event) => {
91+
event.passThroughOnException();
92+
throw new Error();
93+
});
94+
`,
95+
upstream: "https://miniflare.dev",
96+
});
97+
// If you don't use the same upstream URL when dispatching, Miniflare will
98+
// rewrite it to match the upstream
99+
const res = await mf.dispatchFetch("https://miniflare.dev/core/fetch");
100+
console.log(await res.text()); // Source code of this page
101+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
title: Core
3+
order: 2
4+
---
5+
6+
import { DirectoryListing } from "~/components";
7+
8+
<DirectoryListing path="/core" />
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
---
2+
order: 3
3+
title: "📚 Modules"
4+
---
5+
6+
- [Modules Reference](/workers/reference/migrate-to-module-workers/)
7+
8+
## Enabling Modules
9+
10+
Miniflare supports both the traditional `service-worker` and the newer `modules` formats for writing workers. To use the `modules` format, enable it with:
11+
12+
```js
13+
const mf = new Miniflare({
14+
modules: true,
15+
});
16+
```
17+
18+
You can then use `modules` worker scripts like the following:
19+
20+
```js
21+
export default {
22+
async fetch(request, env, ctx) {
23+
// - `request` is the incoming `Request` instance
24+
// - `env` contains bindings, KV namespaces, Durable Objects, etc
25+
// - `ctx` contains `waitUntil` and `passThroughOnException` methods
26+
return new Response("Hello Miniflare!");
27+
},
28+
async scheduled(controller, env, ctx) {
29+
// - `controller` contains `scheduledTime` and `cron` properties
30+
// - `env` contains bindings, KV namespaces, Durable Objects, etc
31+
// - `ctx` contains the `waitUntil` method
32+
console.log("Doing something scheduled...");
33+
},
34+
};
35+
```
36+
37+
<Aside type="warning" header="Warning">
38+
39+
String scripts via the `script` option are supported using
40+
the `modules` format, but you cannot import other modules using them. You must
41+
use a script file via the `scriptPath` option for this.
42+
43+
</Aside>
44+
45+
## Module Rules
46+
47+
Miniflare supports all module types: `ESModule`, `CommonJS`, `Text`, `Data` and
48+
`CompiledWasm`. You can specify additional module resolution rules as follows:
49+
50+
```js
51+
const mf = new Miniflare({
52+
modulesRules: [
53+
{ type: "ESModule", include: ["**/*.js"], fallthrough: true },
54+
{ type: "Text", include: ["**/*.txt"] },
55+
],
56+
});
57+
```
58+
59+
### Default Rules
60+
61+
The following rules are automatically added to the end of your modules rules
62+
list. You can override them by specifying rules matching the same `globs`:
63+
64+
```js
65+
[
66+
{ type: "ESModule", include: ["**/*.mjs"] },
67+
{ type: "CommonJS", include: ["**/*.js", "**/*.cjs"] },
68+
];
69+
```

0 commit comments

Comments
 (0)