Repository: cloudflare/workers-sdk
Pull request #7802: Add fixtures using startWorker() and Miniflare directly
Author: login: penalosa
Labels: name: skip-pr-description-validation
description: Skip validation of the required PR description format
name: no-changeset-required
Created: 2025-01-16T20:07:46Z | Merged: 2025-04-14T11:36:57Z

Just adding some additional fixtures to demostrate direct use of the Miniflare API and `startWorker()` in a non-Vitest testing framework.

---

<!--
Please don't delete the checkboxes <3
The following selections do not need to be completed if this PR only contains changes to .md files
-->

- Tests
  - [ ] TODO (before merge)
  - [x] Tests included
  - [ ] Tests not necessary because:
- E2E Tests CI Job required? (Use "e2e" label or ask maintainer to run separately)
  - [ ] I don't know
  - [ ] Required
  - [x] Not required because: only changes fixtures
- Public documentation
  - [ ] TODO (before merge)
  - [ ] Cloudflare docs PR(s): <!--e.g. <https://github.com/cloudflare/cloudflare-docs/pull/>...-->
  - [x] Documentation not necessary because: only changes fixtures

<!--
Have you read our [Contributing guide](https://github.com/cloudflare/workers-sdk/blob/main/CONTRIBUTING.md)?
In particular, for non-trivial changes, please always engage on the issue or create a discussion or feature request issue first before writing your code.
-->



Diff:
diff --git a/fixtures/miniflare-node-test/package.json b/fixtures/miniflare-node-test/package.json
new file mode 100644
index 0000000000..c59fe1ba5f
--- /dev/null
+++ b/fixtures/miniflare-node-test/package.json
@@ -0,0 +1,22 @@
+{
+	"name": "miniflare-node-test",
+	"private": true,
+	"description": "",
+	"license": "ISC",
+	"author": "",
+	"type": "module",
+	"scripts": {
+		"test:ci": "node --test"
+	},
+	"devDependencies": {
+		"@cloudflare/workers-tsconfig": "workspace:*",
+		"@cloudflare/workers-types": "^4.20241230.0",
+		"@types/is-even": "^1.0.2",
+		"is-even": "^1.0.0",
+		"miniflare": "workspace:*",
+		"wrangler": "workspace:*"
+	},
+	"volta": {
+		"extends": "../../package.json"
+	}
+}
diff --git a/fixtures/miniflare-node-test/src/index-build.test.js b/fixtures/miniflare-node-test/src/index-build.test.js
new file mode 100644
index 0000000000..a9985b54b5
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/index-build.test.js
@@ -0,0 +1,41 @@
+import assert from "node:assert";
+import { spawnSync } from "node:child_process";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+before(() => {
+	spawnSync("npx wrangler build -c wrangler-build.json", {
+		shell: true,
+		stdio: "pipe",
+	});
+});
+
+describe("worker build", () => {
+	/**
+	 * @type {Miniflare}
+	 */
+	let worker;
+
+	before(async () => {
+		worker = new Miniflare({
+			modules: [
+				{
+					type: "ESModule",
+					path: "dist/index.js",
+				},
+			],
+		});
+		await worker.ready;
+	});
+
+	test("even", async () => {
+		assert.strictEqual(
+			await (await worker.dispatchFetch("http://example.com?number=2")).text(),
+			"even"
+		);
+	});
+
+	after(async () => {
+		await worker.dispose();
+	});
+});
diff --git a/fixtures/miniflare-node-test/src/index-with-bindings.test.js b/fixtures/miniflare-node-test/src/index-with-bindings.test.js
new file mode 100644
index 0000000000..6287e9a869
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/index-with-bindings.test.js
@@ -0,0 +1,51 @@
+import assert from "node:assert";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+describe("worker", () => {
+	/**
+	 * @type {Miniflare}
+	 */
+	let worker;
+
+	before(async () => {
+		worker = new Miniflare({
+			modules: [
+				{
+					type: "ESModule",
+					path: "src/index.js",
+				},
+			],
+			bindings: {
+				FOO: "Hello Bindings",
+			},
+			kvNamespaces: ["KV"],
+		});
+		await worker.ready;
+	});
+
+	test("hello world", async () => {
+		assert.strictEqual(
+			await (await worker.dispatchFetch("http://example.com")).text(),
+			"Hello World"
+		);
+	});
+
+	test("text binding", async () => {
+		const bindings = await worker.getBindings();
+		assert.strictEqual(bindings.FOO, "Hello Bindings");
+	});
+
+	test("kv binding", async () => {
+		/**
+		 * @type {{KV: import("@cloudflare/workers-types/experimental").KVNamespace, FOO: string}}
+		 */
+		const bindings = await worker.getBindings();
+		await bindings.KV.put("key", "value");
+		assert.strictEqual(await bindings.KV.get("key"), "value");
+	});
+
+	after(async () => {
+		await worker.dispose();
+	});
+});
diff --git a/fixtures/miniflare-node-test/src/index-with-imports.js b/fixtures/miniflare-node-test/src/index-with-imports.js
new file mode 100644
index 0000000000..1c2052b687
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/index-with-imports.js
@@ -0,0 +1,12 @@
+import { sayHello } from "./say-hello.js";
+
+export default {
+	/**
+	 *
+	 * @param {Request} request
+	 * @returns
+	 */
+	async fetch(request) {
+		return new Response(sayHello(request.url));
+	},
+};
diff --git a/fixtures/miniflare-node-test/src/index-with-imports.test.js b/fixtures/miniflare-node-test/src/index-with-imports.test.js
new file mode 100644
index 0000000000..1a070adfa9
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/index-with-imports.test.js
@@ -0,0 +1,34 @@
+import assert from "node:assert";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+describe("worker", () => {
+	/**
+	 * @type {Miniflare}
+	 */
+	let worker;
+
+	before(async () => {
+		worker = new Miniflare({
+			scriptPath: "src/index-with-imports.js",
+			modules: true,
+			modulesRules: [{ type: "ESModule", include: ["**/*.js"] }],
+		});
+		try {
+			await worker.ready;
+		} catch (e) {
+			console.error(e);
+		}
+	});
+
+	test("hello world", async () => {
+		assert.strictEqual(
+			await (await worker.dispatchFetch("http://example.com/path")).text(),
+			"Hello from http://example.com/path"
+		);
+	});
+
+	after(async () => {
+		await worker.dispose();
+	});
+});
diff --git a/fixtures/miniflare-node-test/src/index.js b/fixtures/miniflare-node-test/src/index.js
new file mode 100644
index 0000000000..2bd0131457
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/index.js
@@ -0,0 +1,10 @@
+export default {
+	/**
+	 *
+	 * @param {Request} request
+	 * @returns
+	 */
+	async fetch(request) {
+		return new Response(`Hello World`);
+	},
+};
diff --git a/fixtures/miniflare-node-test/src/index.test.js b/fixtures/miniflare-node-test/src/index.test.js
new file mode 100644
index 0000000000..874f120888
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/index.test.js
@@ -0,0 +1,33 @@
+import assert from "node:assert";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+describe("worker", () => {
+	/**
+	 * @type {Miniflare}
+	 */
+	let worker;
+
+	before(async () => {
+		worker = new Miniflare({
+			modules: [
+				{
+					type: "ESModule",
+					path: "src/index.js",
+				},
+			],
+		});
+		await worker.ready;
+	});
+
+	test("hello world", async () => {
+		assert.strictEqual(
+			await (await worker.dispatchFetch("http://example.com")).text(),
+			"Hello World"
+		);
+	});
+
+	after(async () => {
+		await worker.dispose();
+	});
+});
diff --git a/fixtures/miniflare-node-test/src/index.ts b/fixtures/miniflare-node-test/src/index.ts
new file mode 100644
index 0000000000..2f3566acd4
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/index.ts
@@ -0,0 +1,10 @@
+import isEven from "is-even";
+
+export default {
+	async fetch(request): Promise<Response> {
+		const url = new URL(request.url);
+		return new Response(
+			isEven(Number(url.searchParams.get("number") ?? "0")) ? "even" : "odd"
+		);
+	},
+} satisfies ExportedHandler;
diff --git a/fixtures/miniflare-node-test/src/say-hello.js b/fixtures/miniflare-node-test/src/say-hello.js
new file mode 100644
index 0000000000..79451b8616
--- /dev/null
+++ b/fixtures/miniflare-node-test/src/say-hello.js
@@ -0,0 +1,8 @@
+/**
+ *
+ * @param {string} url
+ * @returns
+ */
+export function sayHello(url) {
+	return `Hello from ${url}`;
+}
diff --git a/fixtures/miniflare-node-test/tsconfig.json b/fixtures/miniflare-node-test/tsconfig.json
new file mode 100644
index 0000000000..76e6c380ac
--- /dev/null
+++ b/fixtures/miniflare-node-test/tsconfig.json
@@ -0,0 +1,8 @@
+{
+	"extends": "@cloudflare/workers-tsconfig/tsconfig.json",
+	"compilerOptions": {
+		"types": ["@cloudflare/workers-types"],
+		"checkJs": true
+	},
+	"include": ["**/*.js", "**/*.ts"]
+}
diff --git a/fixtures/miniflare-node-test/wrangler-build.json b/fixtures/miniflare-node-test/wrangler-build.json
new file mode 100644
index 0000000000..46ed31d033
--- /dev/null
+++ b/fixtures/miniflare-node-test/wrangler-build.json
@@ -0,0 +1,5 @@
+{
+	"name": "build-miniflare",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-01-16"
+}
diff --git a/fixtures/miniflare-node-test/wrangler.toml b/fixtures/miniflare-node-test/wrangler.toml
new file mode 100644
index 0000000000..27d3873ffe
--- /dev/null
+++ b/fixtures/miniflare-node-test/wrangler.toml
@@ -0,0 +1,6 @@
+name = "miniflare-node-test"
+main = "dist/out.js"
+compatibility_date = "2022-12-08"
+
+[build]
+command = "npx esbuild src/index.js --outfile=dist/out.js"
diff --git a/fixtures/start-worker-node-test/package.json b/fixtures/start-worker-node-test/package.json
new file mode 100644
index 0000000000..be3430bd1f
--- /dev/null
+++ b/fixtures/start-worker-node-test/package.json
@@ -0,0 +1,22 @@
+{
+	"name": "start-worker-node-test",
+	"private": true,
+	"description": "",
+	"license": "ISC",
+	"author": "",
+	"type": "module",
+	"scripts": {
+		"test:ci": "node --test"
+	},
+	"devDependencies": {
+		"@cloudflare/workers-tsconfig": "workspace:*",
+		"@cloudflare/workers-types": "^4.20241230.0",
+		"@types/is-even": "^1.0.2",
+		"is-even": "^1.0.0",
+		"miniflare": "workspace:*",
+		"wrangler": "workspace:*"
+	},
+	"volta": {
+		"extends": "../../package.json"
+	}
+}
diff --git a/fixtures/start-worker-node-test/src/index.test.js b/fixtures/start-worker-node-test/src/index.test.js
new file mode 100644
index 0000000000..4bec671d78
--- /dev/null
+++ b/fixtures/start-worker-node-test/src/index.test.js
@@ -0,0 +1,25 @@
+import assert from "node:assert";
+import test, { after, before, describe } from "node:test";
+import { unstable_startWorker } from "wrangler";
+
+describe("worker", () => {
+	/**
+	 * @type {Awaited<ReturnType<typeof unstable_startWorker>>}
+	 */
+	let worker;
+
+	before(async () => {
+		worker = await unstable_startWorker({ config: "wrangler.json" });
+	});
+
+	test("hello world", async () => {
+		assert.strictEqual(
+			await (await worker.fetch("http://example.com")).text(),
+			"Hello from even"
+		);
+	});
+
+	after(async () => {
+		await worker.dispose();
+	});
+});
diff --git a/fixtures/start-worker-node-test/src/index.ts b/fixtures/start-worker-node-test/src/index.ts
new file mode 100644
index 0000000000..ac53f66922
--- /dev/null
+++ b/fixtures/start-worker-node-test/src/index.ts
@@ -0,0 +1,13 @@
+import isEven from "is-even";
+import { sayHello } from "./say-hello";
+
+export default {
+	async fetch(request): Promise<Response> {
+		const url = new URL(request.url);
+		return new Response(
+			sayHello(
+				isEven(Number(url.searchParams.get("number") ?? "0")) ? "even" : "odd"
+			)
+		);
+	},
+} satisfies ExportedHandler;
diff --git a/fixtures/start-worker-node-test/src/say-hello.ts b/fixtures/start-worker-node-test/src/say-hello.ts
new file mode 100644
index 0000000000..b83bb8bca9
--- /dev/null
+++ b/fixtures/start-worker-node-test/src/say-hello.ts
@@ -0,0 +1,3 @@
+export function sayHello(url: string) {
+	return `Hello from ${url}`;
+}
diff --git a/fixtures/start-worker-node-test/tsconfig.json b/fixtures/start-worker-node-test/tsconfig.json
new file mode 100644
index 0000000000..76e6c380ac
--- /dev/null
+++ b/fixtures/start-worker-node-test/tsconfig.json
@@ -0,0 +1,8 @@
+{
+	"extends": "@cloudflare/workers-tsconfig/tsconfig.json",
+	"compilerOptions": {
+		"types": ["@cloudflare/workers-types"],
+		"checkJs": true
+	},
+	"include": ["**/*.js", "**/*.ts"]
+}
diff --git a/fixtures/start-worker-node-test/wrangler.json b/fixtures/start-worker-node-test/wrangler.json
new file mode 100644
index 0000000000..46ed31d033
--- /dev/null
+++ b/fixtures/start-worker-node-test/wrangler.json
@@ -0,0 +1,5 @@
+{
+	"name": "build-miniflare",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-01-16"
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cb2afa401b..7554aa1ce8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -388,6 +388,27 @@ importers:
         specifier: workspace:*
         version: link:../../packages/wrangler
 
+  fixtures/miniflare-node-test:
+    devDependencies:
+      '@cloudflare/workers-tsconfig':
+        specifier: workspace:*
+        version: link:../../packages/workers-tsconfig
+      '@cloudflare/workers-types':
+        specifier: ^4.20241230.0
+        version: 4.20250410.0
+      '@types/is-even':
+        specifier: ^1.0.2
+        version: 1.0.2
+      is-even:
+        specifier: ^1.0.0
+        version: 1.0.0
+      miniflare:
+        specifier: workspace:*
+        version: link:../../packages/miniflare
+      wrangler:
+        specifier: workspace:*
+        version: link:../../packages/wrangler
+
   fixtures/no-bundle-import:
     devDependencies:
       get-port:
@@ -926,6 +947,27 @@ importers:
         specifier: workspace:*
         version: link:../../packages/kv-asset-handler
 
+  fixtures/start-worker-node-test:
+    devDependencies:
+      '@cloudflare/workers-tsconfig':
+        specifier: workspace:*
+        version: link:../../packages/workers-tsconfig
+      '@cloudflare/workers-types':
+        specifier: ^4.20241230.0
+        version: 4.20250410.0
+      '@types/is-even':
+        specifier: ^1.0.2
+        version: 1.0.2
+      is-even:
+        specifier: ^1.0.0
+        version: 1.0.0
+      miniflare:
+        specifier: workspace:*
+        version: link:../../packages/miniflare
+      wrangler:
+        specifier: workspace:*
+        version: link:../../packages/wrangler
+
   fixtures/unstable_dev:
     devDependencies:
       wrangler:
@@ -6342,6 +6384,9 @@ packages:
   '@types/is-ci@3.0.0':
     resolution: {integrity: sha512-Q0Op0hdWbYd1iahB+IFNQcWXFq4O0Q5MwQP7uN0souuQ4rPg1vEYcnIOfr1gY+M+6rc8FGoRaBO1mOOvL29sEQ==}
 
+  '@types/is-even@1.0.2':
+    resolution: {integrity: sha512-qXDiw1zrRSrExwuJHRvxr5eGANlWscPwvQw3xURyax0GkY+fSwwei2uy0ReJBF2N0EeniUr+h2iD9e/KQNroaQ==}
+
   '@types/istanbul-lib-coverage@2.0.6':
     resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==}
 
@@ -8956,6 +9001,9 @@ packages:
     resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
     engines: {node: '>= 0.4'}
 
+  is-buffer@1.1.6:
+    resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+
   is-callable@1.2.7:
     resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
     engines: {node: '>= 0.4'}
@@ -8992,6 +9040,10 @@ packages:
     engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
     hasBin: true
 
+  is-even@1.0.0:
+    resolution: {integrity: sha512-LEhnkAdJqic4Dbqn58A0y52IXoHWlsueqQkKfMfdEnIYG8A1sm/GHidKkS6yvXlMoRrkM34csHnXQtOqcb+Jzg==}
+    engines: {node: '>=0.10.0'}
+
   is-extglob@2.1.1:
     resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
     engines: {node: '>=0.10.0'}
@@ -9051,6 +9103,10 @@ packages:
     resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==}
     engines: {node: '>= 0.4'}
 
+  is-number@3.0.0:
+    resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==}
+    engines: {node: '>=0.10.0'}
+
   is-number@6.0.0:
     resolution: {integrity: sha512-Wu1VHeILBK8KAWJUAiSZQX94GmOE45Rg6/538fKwiloUu21KncEkYGPqob2oSZ5mUT73vLGrHQjKw3KMPwfDzg==}
     engines: {node: '>=0.10.0'}
@@ -9059,6 +9115,10 @@ packages:
     resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
     engines: {node: '>=0.12.0'}
 
+  is-odd@0.1.2:
+    resolution: {integrity: sha512-Ri7C2K7o5IrUU9UEI8losXJCCD/UtsaIrkR5sxIcFg4xQ9cRJXlWA5DQvTE0yDc0krvSNLsRGXN11UPS6KyfBw==}
+    engines: {node: '>=0.10.0'}
+
   is-odd@3.0.1:
     resolution: {integrity: sha512-CQpnWPrDwmP1+SMHXZhtLtJv90yiyVfluGsX5iNCVkrhQtU3TQHsUWPG9wkdk9Lgd5yNpAg9jQEo90CBaXgWMA==}
     engines: {node: '>=4'}
@@ -9323,6 +9383,10 @@ packages:
   keytar@7.9.0:
     resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==}
 
+  kind-of@3.2.2:
+    resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==}
+    engines: {node: '>=0.10.0'}
+
   kleur@3.0.3:
     resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
     engines: {node: '>=6'}
@@ -15869,6 +15933,8 @@ snapshots:
     dependencies:
       ci-info: 3.9.0
 
+  '@types/is-even@1.0.2': {}
+
   '@types/istanbul-lib-coverage@2.0.6': {}
 
   '@types/istanbul-lib-report@3.0.3':
@@ -19089,6 +19155,8 @@ snapshots:
       call-bind: 1.0.8
       has-tostringtag: 1.0.2
 
+  is-buffer@1.1.6: {}
+
   is-callable@1.2.7: {}
 
   is-ci@3.0.1:
@@ -19117,6 +19185,10 @@ snapshots:
 
   is-docker@3.0.0: {}
 
+  is-even@1.0.0:
+    dependencies:
+      is-odd: 0.1.2
+
   is-extglob@2.1.1: {}
 
   is-finalizationregistry@1.1.0:
@@ -19160,10 +19232,18 @@ snapshots:
     dependencies:
       has-tostringtag: 1.0.2
 
+  is-number@3.0.0:
+    dependencies:
+      kind-of: 3.2.2
+
   is-number@6.0.0: {}
 
   is-number@7.0.0: {}
 
+  is-odd@0.1.2:
+    dependencies:
+      is-number: 3.0.0
+
   is-odd@3.0.1:
     dependencies:
       is-number: 6.0.0
@@ -19425,6 +19505,10 @@ snapshots:
       node-addon-api: 4.3.0
       prebuild-install: 7.1.2
 
+  kind-of@3.2.2:
+    dependencies:
+      is-buffer: 1.1.6
+
   kleur@3.0.3: {}
 
   kleur@4.1.5: {}


Reviews:
user: login: vicb
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-17T07:02:52Z
user: login: penalosa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-03T14:50:03Z
user: login: vicb
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-03T15:17:07Z
user: login: penalosa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-03T15:23:54Z
user: login: dario-piotrowicz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-14T10:04:57Z
user: login: penalosa
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T10:11:45Z
user: login: dario-piotrowicz
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-14T10:24:08Z
user: login: dario-piotrowicz
body: looks good to me 😄 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-14T10:25:28Z

Review comments:
diff_hunk: @@ -0,0 +1,41 @@
+import assert from "node:assert";
+import { spawnSync } from "node:child_process";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+before(() => {
+	spawnSync("npx wrangler build -c wrangler-build.json", {
+		shell: true,
+		stdio: "pipe",
+	});
+});
+
+describe("worker build", () => {
path: fixtures/miniflare-node-test/src/index-build.test.js
user: login: vicb
body: Very nice PR!

nit: "worker build" and "worker" names in the next file are not very descriptive.

(question: how to use a different worked when interacting with Miniflare? I don't see an option so I guess `MINIFLARE_WORKERD_VERSION` is respected?)

created_at: 2025-01-17T07:02:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+import assert from "node:assert";
+import { spawnSync } from "node:child_process";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+before(() => {
+	spawnSync("npx wrangler build -c wrangler-build.json", {
+		shell: true,
+		stdio: "pipe",
+	});
+});
+
+describe("worker build", () => {
path: fixtures/miniflare-node-test/src/index-build.test.js
user: login: penalosa
body: `MINIFLARE_WORKERD_VERSION` should be respected, yes
created_at: 2025-02-03T14:50:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+import assert from "node:assert";
+import { spawnSync } from "node:child_process";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+before(() => {
+	spawnSync("npx wrangler build -c wrangler-build.json", {
+		shell: true,
+		stdio: "pipe",
+	});
+});
+
+describe("worker build", () => {
path: fixtures/miniflare-node-test/src/index-build.test.js
user: login: vicb
body: Do you think it would be worth adding some docs [on the class](https://github.com/cloudflare/workers-sdk/blob/59c7c8ee177d9345948a416377c6625269d58925/packages/miniflare/src/index.ts#L706)?
created_at: 2025-02-03T15:17:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,41 @@
+import assert from "node:assert";
+import { spawnSync } from "node:child_process";
+import test, { after, before, describe } from "node:test";
+import { Miniflare } from "miniflare";
+
+before(() => {
+	spawnSync("npx wrangler build -c wrangler-build.json", {
+		shell: true,
+		stdio: "pipe",
+	});
+});
+
+describe("worker build", () => {
path: fixtures/miniflare-node-test/src/index-build.test.js
user: login: penalosa
body: It's documented in the README: https://github.com/cloudflare/workers-sdk/tree/main/packages/miniflare/README.md#L873
created_at: 2025-04-03T15:23:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,6 @@
+name = "unstable_dev"
+main = "dist/out.js"
+compatibility_date = "2022-12-08"
+
+[build]
+command = "npx esbuild src/index.js --outfile=dist/out.js"
path: fixtures/miniflare-node-test/wrangler.toml
user: login: dario-piotrowicz
body: ```suggestion
command = "npx esbuild src/index.js --outfile=dist/out.js"

```
created_at: 2025-04-14T09:58:07Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,6 @@
+name = "unstable_dev"
path: fixtures/miniflare-node-test/wrangler.toml
user: login: dario-piotrowicz
body: should this be
```suggestion
name = "miniflare-node-test"
```
?

(probably it doesn't really matter 🤷)
created_at: 2025-04-14T09:59:17Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,10 @@
+import isEven from "is-even";
+
+export default {
+	async fetch(request): Promise<Response> {
+		const url = new URL(request.url);
+		return new Response(
+			isEven(Number(url.searchParams.get("number") ?? "0")) ? "even" : "odd"
path: fixtures/miniflare-node-test/src/index.ts
user: login: dario-piotrowicz
body: why are you using `is-even` instead of just doing `% 2 === 0`? is it to test module resolution? 🤔 
created_at: 2025-04-14T10:04:52Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,10 @@
+import isEven from "is-even";
+
+export default {
+	async fetch(request): Promise<Response> {
+		const url = new URL(request.url);
+		return new Response(
+			isEven(Number(url.searchParams.get("number") ?? "0")) ? "even" : "odd"
path: fixtures/miniflare-node-test/src/index.ts
user: login: penalosa
body: Yeah—tested in https://github.com/cloudflare/workers-sdk/pull/7802/files/fe10741b093ffbece2ebac749aa746b31ee717b5#diff-3023250eb0476b0beae6fb7213ed15a640ed39f45a701803ace0c77d847fa10b
created_at: 2025-04-14T10:11:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,10 @@
+import isEven from "is-even";
+
+export default {
+	async fetch(request): Promise<Response> {
+		const url = new URL(request.url);
+		return new Response(
+			isEven(Number(url.searchParams.get("number") ?? "0")) ? "even" : "odd"
path: fixtures/miniflare-node-test/src/index.ts
user: login: dario-piotrowicz
body: ah ok, I would probably put a comment somewhere on why the function is used, but I'm also ok not to have such a comment if you think that this is obvious 🙂 
created_at: 2025-04-14T10:24:08Z
author_association: MEMBER

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-01-16T20:07:50Z
body: ###  ⚠️  No Changeset found

Latest commit: e09009ad4fc586362032930ade57af101554caa2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/cloudflare/workers-sdk/new/penalosa/node-test-fixtures?filename=.changeset/kind-flowers-jog.md&value=---%0A%22miniflare-node-test%22%3A%20patch%0A%22start-worker-node-test%22%3A%20patch%0A---%0A%0AAdd%20fixtures%20using%20startWorker()%20and%20Miniflare%20directly%0A)


author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-03T15:53:03Z
body: A wrangler prerelease is available for testing. You can install this latest build in your project with:

```sh
npm install --save-dev https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-wrangler-7802
```

You can reference the automatically updated head of this PR with:

```sh
npm install --save-dev https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/prs/7802/npm-package-wrangler-7802
```

Or you can use `npx` with this latest build directly:

```sh
npx https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-wrangler-7802 dev path/to/script.js
```

<details><summary>Additional artifacts:</summary>


cloudflare-workers-bindings-extension:
```sh
wget https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-workers-bindings-extension-7802 -O ./cloudflare-workers-bindings-extension.0.0.0-va0266942d.vsix && code --install-extension ./cloudflare-workers-bindings-extension.0.0.0-va0266942d.vsix
```



create-cloudflare:
```sh
npx https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-create-cloudflare-7802 --no-auto-update
```



@cloudflare/kv-asset-handler:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-kv-asset-handler-7802
```



miniflare:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-miniflare-7802
```



@cloudflare/pages-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-pages-shared-7802
```



@cloudflare/unenv-preset:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-unenv-preset-7802
```



@cloudflare/vite-plugin:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-vite-plugin-7802
```



@cloudflare/vitest-pool-workers:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-vitest-pool-workers-7802
```



@cloudflare/workers-editor-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-workers-editor-shared-7802
```



@cloudflare/workers-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-workers-shared-7802
```



@cloudflare/workflows-shared:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14405979572/npm-package-cloudflare-workflows-shared-7802
```


Note that these links will no longer work once [the GitHub Actions artifact expires](https://docs.github.com/en/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization).

</details>

---

`wrangler@4.10.0` includes the following runtime dependencies:

|Package|Constraint|Resolved|
|-------|----------|--------|
|`miniflare`|workspace:*|4.20250409.0|
|`workerd`|1.20250409.0|1.20250409.0|
|`workerd --version`|1.20250409.0|2025-04-09|

Please ensure constraints are pinned, and `miniflare`/`workerd` minor versions match.
<!-- Sticky Pull Request Comment -->
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-14T11:18:09Z
body: A Wrangler prerelease is available for testing. You can install this latest build in your project with:

```sh
npm install --save-dev https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-wrangler-7802
```

<details><summary>Prereleases for other packages:</summary>


`cloudflare-workers-bindings-extension`:
```sh
wget https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-workers-bindings-extension-7802 -O ./cloudflare-workers-bindings-extension.0.0.0-v1d71ae65e.vsix && code --install-extension ./cloudflare-workers-bindings-extension.0.0.0-v1d71ae65e.vsix
```



`create-cloudflare`:
```sh
npx https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-create-cloudflare-7802 --no-auto-update
```



`@cloudflare/kv-asset-handler`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-kv-asset-handler-7802
```



`miniflare`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-miniflare-7802
```



`@cloudflare/pages-shared`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-pages-shared-7802
```



`@cloudflare/unenv-preset`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-unenv-preset-7802
```



`@cloudflare/vite-plugin`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-vite-plugin-7802
```



`@cloudflare/vitest-pool-workers`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-vitest-pool-workers-7802
```



`@cloudflare/workers-editor-shared`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-workers-editor-shared-7802
```



`@cloudflare/workers-shared`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-workers-shared-7802
```



`@cloudflare/workflows-shared`:
```sh
npm install https://prerelease-registry.devprod.cloudflare.dev/workers-sdk/runs/14444246979/npm-package-cloudflare-workflows-shared-7802
```


Note that these links will no longer work once [the GitHub Actions artifact expires](https://docs.github.com/en/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization).

</details>
<!-- Sticky Pull Request Commentprerelease -->
author_association: CONTRIBUTOR