diff --git a/.gitignore b/.gitignore index c6d2fbc22689..c12ec25fd76c 100644 --- a/.gitignore +++ b/.gitignore @@ -231,4 +231,6 @@ dist/** !.env.example .node-cache/ -AGENTS.local.md \ No newline at end of file +.opencode/plans + +AGENTS.local.md diff --git a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts index 8e49a4308a95..6b3da1e16226 100644 --- a/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts +++ b/fixtures/get-platform-proxy/tests/get-platform-proxy.env.test.ts @@ -1,15 +1,7 @@ import path from "path"; import { D1Database, R2Bucket } from "@cloudflare/workers-types"; import { toMatchImageSnapshot } from "jest-image-snapshot"; -import { - afterEach, - beforeEach, - describe, - expect, - it, - MockInstance, - vi, -} from "vitest"; +import { beforeEach, describe, expect, it, MockInstance, vi } from "vitest"; import { getPlatformProxy } from "./shared"; import type { Fetcher, @@ -18,7 +10,6 @@ import type { KVNamespace, Workflow, } from "@cloudflare/workers-types"; -import type { Unstable_DevWorker } from "wrangler"; type Env = { MY_VAR: string; @@ -39,7 +30,6 @@ type Env = { const wranglerConfigFilePath = path.join(__dirname, "..", "wrangler.jsonc"); describe("getPlatformProxy - env", () => { - let devWorkers: Unstable_DevWorker[]; let warn = {} as MockInstance; beforeEach(() => { diff --git a/fixtures/local-mode-tests/tests/logging.test.ts b/fixtures/local-mode-tests/tests/logging.test.ts index 018656c81410..a06d858e4c92 100644 --- a/fixtures/local-mode-tests/tests/logging.test.ts +++ b/fixtures/local-mode-tests/tests/logging.test.ts @@ -2,7 +2,7 @@ import path from "node:path"; import { setTimeout } from "node:timers/promises"; import util from "node:util"; import { afterEach, beforeEach, expect, it, Mock, vi } from "vitest"; -import { unstable_dev } from "wrangler"; +import { unstable_startWorker } from "wrangler"; let output = ""; function spyOnConsoleMethod(name: keyof typeof console) { @@ -25,21 +25,17 @@ afterEach(() => { it("logs startup errors", async () => { let caughtError: unknown; try { - const worker = await unstable_dev( - path.resolve(__dirname, "..", "src", "nodejs-compat.ts"), - { - config: path.resolve(__dirname, "..", "wrangler.logging.jsonc"), - // Intentionally omitting `compatibilityFlags: ["nodejs_compat"]` - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - devEnv: true, - }, - } - ); - await worker.stop(); - expect.fail("Expected unstable_dev() to fail"); + const worker = await unstable_startWorker({ + entrypoint: path.resolve(__dirname, "..", "src", "nodejs-compat.ts"), + config: path.resolve(__dirname, "..", "wrangler.logging.jsonc"), + // Intentionally omitting `compatibilityFlags: ["nodejs_compat"]` + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, + }, + }); + await worker.dispose(); + expect.fail("Expected unstable_startWorker() to fail"); } catch (e) { caughtError = e; } diff --git a/fixtures/local-mode-tests/tests/module.test.ts b/fixtures/local-mode-tests/tests/module.test.ts index 00bfbe177e45..f1606bc47486 100644 --- a/fixtures/local-mode-tests/tests/module.test.ts +++ b/fixtures/local-mode-tests/tests/module.test.ts @@ -1,10 +1,9 @@ import path from "path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { Unstable_DevWorker } from "wrangler"; +import { unstable_startWorker } from "wrangler"; describe("module worker", () => { - let worker: Unstable_DevWorker; + let worker: Awaited>; let originalNodeEnv: string | undefined; @@ -14,25 +13,22 @@ describe("module worker", () => { process.env.NODE_ENV = "local-testing"; - worker = await unstable_dev( - path.resolve(__dirname, "..", "src", "module.ts"), - { - config: path.resolve(__dirname, "..", "wrangler.module.jsonc"), - vars: { VAR4: "https://google.com" }, - ip: "127.0.0.1", - port: 0, - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - devEnv: true, - }, - } - ); + worker = await unstable_startWorker({ + entrypoint: path.resolve(__dirname, "..", "src", "module.ts"), + config: path.resolve(__dirname, "..", "wrangler.module.jsonc"), + bindings: { + VAR4: { type: "plain_text", value: "https://google.com" }, + }, + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, + }, + }); }); afterAll(async () => { try { - await worker.stop(); + await worker.dispose(); } catch (e) { console.error("Failed to stop worker", e); } @@ -40,7 +36,7 @@ describe("module worker", () => { }); it("renders variables", async () => { - const resp = await worker.fetch("/vars"); + const resp = await worker.fetch("http://example.com/vars"); expect(resp).not.toBe(undefined); const text = await resp.text(); @@ -60,13 +56,15 @@ describe("module worker", () => { }); it("should return Hi by default", async () => { - const resp = await worker.fetch("/"); + const resp = await worker.fetch("http://example.com/"); expect(resp).not.toBe(undefined); const respJson = await resp.text(); expect(respJson).toBe(JSON.stringify({ greeting: "Hi!" })); }); it("should return Bonjour when French", async () => { - const resp = await worker.fetch("/", { headers: { lang: "fr-FR" } }); + const resp = await worker.fetch("http://example.com/", { + headers: { lang: "fr-FR" }, + }); expect(resp).not.toBe(undefined); if (resp) { const respJson = await resp.text(); @@ -75,7 +73,9 @@ describe("module worker", () => { }); it("should return G'day when Australian", async () => { - const resp = await worker.fetch("/", { headers: { lang: "en-AU" } }); + const resp = await worker.fetch("http://example.com/", { + headers: { lang: "en-AU" }, + }); expect(resp).not.toBe(undefined); if (resp) { const respJson = await resp.text(); @@ -84,7 +84,9 @@ describe("module worker", () => { }); it("should return Good day when British", async () => { - const resp = await worker.fetch("/", { headers: { lang: "en-GB" } }); + const resp = await worker.fetch("http://example.com/", { + headers: { lang: "en-GB" }, + }); expect(resp).not.toBe(undefined); if (resp) { const respJson = await resp.text(); @@ -93,7 +95,9 @@ describe("module worker", () => { }); it("should return Howdy when Texan", async () => { - const resp = await worker.fetch("/", { headers: { lang: "en-TX" } }); + const resp = await worker.fetch("http://example.com/", { + headers: { lang: "en-TX" }, + }); expect(resp).not.toBe(undefined); if (resp) { const respJson = await resp.text(); @@ -102,7 +106,9 @@ describe("module worker", () => { }); it("should return Hello when American", async () => { - const resp = await worker.fetch("/", { headers: { lang: "en-US" } }); + const resp = await worker.fetch("http://example.com/", { + headers: { lang: "en-US" }, + }); expect(resp).not.toBe(undefined); if (resp) { const respJson = await resp.text(); @@ -111,7 +117,9 @@ describe("module worker", () => { }); it("should return Hola when Spanish", async () => { - const resp = await worker.fetch("/", { headers: { lang: "es-ES" } }); + const resp = await worker.fetch("http://example.com/", { + headers: { lang: "es-ES" }, + }); expect(resp).not.toBe(undefined); if (resp) { const respJson = await resp.text(); @@ -120,7 +128,7 @@ describe("module worker", () => { }); it("returns hex string", async () => { - const resp = await worker.fetch("/buffer"); + const resp = await worker.fetch("http://example.com/buffer"); expect(resp).not.toBe(undefined); const text = await resp.text(); diff --git a/fixtures/local-mode-tests/tests/ports.test.ts b/fixtures/local-mode-tests/tests/ports.test.ts index cd117f769582..c81bda6348cf 100644 --- a/fixtures/local-mode-tests/tests/ports.test.ts +++ b/fixtures/local-mode-tests/tests/ports.test.ts @@ -1,49 +1,45 @@ import path from "path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { Unstable_DevWorker } from "wrangler"; +import { unstable_startWorker } from "wrangler"; describe("multiple workers", () => { - let workers: Unstable_DevWorker[]; + let workers: Awaited>[]; beforeAll(async () => { //since the script is invoked from the directory above, need to specify index.js is in src/ workers = await Promise.all([ - unstable_dev(path.resolve(__dirname, "..", "src", "module.ts"), { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - devEnv: true, + unstable_startWorker({ + entrypoint: path.resolve(__dirname, "..", "src", "module.ts"), + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }), - unstable_dev(path.resolve(__dirname, "..", "src", "module.ts"), { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - devEnv: true, + unstable_startWorker({ + entrypoint: path.resolve(__dirname, "..", "src", "module.ts"), + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }), - unstable_dev(path.resolve(__dirname, "..", "src", "module.ts"), { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - devEnv: true, + unstable_startWorker({ + entrypoint: path.resolve(__dirname, "..", "src", "module.ts"), + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }), ]); }); afterAll(async () => { - await Promise.all(workers.map(async (worker) => await worker.stop())); + await Promise.all(workers.map(async (worker) => await worker.dispose())); }); it.concurrent("all workers should be fetchable", async () => { const responses = await Promise.all( - workers.map(async (worker) => await worker.fetch()) + workers.map(async (worker) => await worker.fetch("http://example.com/")) ); const parsedResponses = await Promise.all( responses.map(async (resp) => await resp.text()) diff --git a/fixtures/local-mode-tests/tests/specified-port.test.ts b/fixtures/local-mode-tests/tests/specified-port.test.ts index cbeec2639bb8..6bfa5b838226 100644 --- a/fixtures/local-mode-tests/tests/specified-port.test.ts +++ b/fixtures/local-mode-tests/tests/specified-port.test.ts @@ -2,8 +2,7 @@ import assert from "node:assert"; import nodeNet from "node:net"; import path from "path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { Unstable_DevWorker } from "wrangler"; +import { unstable_startWorker } from "wrangler"; function getPort() { return new Promise((resolve, reject) => { @@ -20,30 +19,25 @@ function getPort() { } describe("specific port", () => { - let worker: Unstable_DevWorker; + let worker: Awaited>; beforeAll(async () => { - worker = await unstable_dev( - path.resolve(__dirname, "..", "src", "module.ts"), - { - config: path.resolve(__dirname, "..", "wrangler.module.jsonc"), - port: await getPort(), - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - devEnv: true, - }, - } - ); + worker = await unstable_startWorker({ + entrypoint: path.resolve(__dirname, "..", "src", "module.ts"), + config: path.resolve(__dirname, "..", "wrangler.module.jsonc"), + dev: { + server: { hostname: "127.0.0.1", port: await getPort() }, + inspector: false, + }, + }); }); afterAll(async () => { - await worker?.stop(); + await worker?.dispose(); }); it("fetches worker", async () => { - const resp = await worker.fetch("/"); + const resp = await worker.fetch("http://example.com/"); expect(resp.status).toBe(200); }); }); diff --git a/fixtures/local-mode-tests/tests/sw.test.ts b/fixtures/local-mode-tests/tests/sw.test.ts index e8b01e4fcc45..326601e45c56 100644 --- a/fixtures/local-mode-tests/tests/sw.test.ts +++ b/fixtures/local-mode-tests/tests/sw.test.ts @@ -1,10 +1,9 @@ import path from "path"; import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { Unstable_DevWorker } from "wrangler"; +import { unstable_startWorker } from "wrangler"; describe("service worker", () => { - let worker: Unstable_DevWorker; + let worker: Awaited>; let originalNodeEnv: string | undefined; @@ -14,24 +13,23 @@ describe("service worker", () => { process.env.NODE_ENV = "local-testing"; //since the script is invoked from the directory above, need to specify index.js is in src/ - worker = await unstable_dev(path.resolve(__dirname, "..", "src", "sw.ts"), { + worker = await unstable_startWorker({ + entrypoint: path.resolve(__dirname, "..", "src", "sw.ts"), config: path.resolve(__dirname, "..", "wrangler.sw.jsonc"), - ip: "127.0.0.1", - experimental: { - disableDevRegistry: true, - disableExperimentalWarning: true, - devEnv: true, + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); }); afterAll(async () => { - await worker.stop(); + await worker.dispose(); process.env.NODE_ENV = originalNodeEnv; }); it("renders", async () => { - const resp = await worker.fetch(); + const resp = await worker.fetch("http://example.com/"); expect(resp).not.toBe(undefined); const text = await resp.text(); diff --git a/fixtures/no-bundle-import/src/index.test.ts b/fixtures/no-bundle-import/src/index.test.ts index 3b434d9bf811..7bbf012f045e 100644 --- a/fixtures/no-bundle-import/src/index.test.ts +++ b/fixtures/no-bundle-import/src/index.test.ts @@ -1,26 +1,25 @@ import path from "path"; import { afterAll, beforeAll, describe, expect, test } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { Unstable_DevWorker } from "wrangler"; +import { unstable_startWorker } from "wrangler"; describe("Worker", () => { - let worker: Unstable_DevWorker; + let worker: Awaited>; beforeAll(async () => { - worker = await unstable_dev(path.resolve(__dirname, "index.js"), { - logLevel: "none", - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - devEnv: true, + worker = await unstable_startWorker({ + entrypoint: path.resolve(__dirname, "index.js"), + dev: { + logLevel: "none", + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); }, 30_000); - afterAll(() => worker.stop()); + afterAll(() => worker.dispose()); test("module traversal results in correct response", async () => { - const resp = await worker.fetch(); + const resp = await worker.fetch("http://example.com/"); const text = await resp.text(); expect(text).toMatchInlineSnapshot( `"Hello Jane Smith and Hello John Smith"` @@ -28,7 +27,7 @@ describe("Worker", () => { }); test("module traversal results in correct response for CommonJS", async () => { - const resp = await worker.fetch("/cjs"); + const resp = await worker.fetch("http://example.com/cjs"); const text = await resp.text(); expect(text).toMatchInlineSnapshot( `"CJS: Hello Jane Smith and Hello John Smith"` @@ -36,43 +35,43 @@ describe("Worker", () => { }); test("correct response for CommonJS which imports ESM", async () => { - const resp = await worker.fetch("/cjs-loop"); + const resp = await worker.fetch("http://example.com/cjs-loop"); const text = await resp.text(); expect(text).toMatchInlineSnapshot('"CJS: cjs-string"'); }); test("support for dynamic imports", async () => { - const resp = await worker.fetch("/dynamic"); + const resp = await worker.fetch("http://example.com/dynamic"); const text = await resp.text(); expect(text).toMatchInlineSnapshot(`"dynamic"`); }); test("basic wasm support", async () => { - const resp = await worker.fetch("/wasm"); + const resp = await worker.fetch("http://example.com/wasm"); const text = await resp.text(); expect(text).toMatchInlineSnapshot('"42"'); }); test("resolves wasm import paths relative to root", async () => { - const resp = await worker.fetch("/wasm-nested"); + const resp = await worker.fetch("http://example.com/wasm-nested"); const text = await resp.text(); expect(text).toMatchInlineSnapshot('"nested42"'); }); test("wasm can be imported from a dynamic import", async () => { - const resp = await worker.fetch("/wasm-dynamic"); + const resp = await worker.fetch("http://example.com/wasm-dynamic"); const text = await resp.text(); expect(text).toMatchInlineSnapshot('"sibling42subdirectory42"'); }); test("text data can be imported", async () => { - const resp = await worker.fetch("/txt"); + const resp = await worker.fetch("http://example.com/txt"); const text = await resp.text(); expect(text).toMatchInlineSnapshot('"TEST DATA"'); }); test("binary data can be imported", async () => { - const resp = await worker.fetch("/bin"); + const resp = await worker.fetch("http://example.com/bin"); const bin = await resp.arrayBuffer(); const expected = new Uint8Array(new ArrayBuffer(4)); expected.set([0, 1, 2, 10]); @@ -80,7 +79,7 @@ describe("Worker", () => { }); test("actual dynamic import (that cannot be inlined by an esbuild run)", async () => { - const resp = await worker.fetch("/lang/fr.json"); + const resp = await worker.fetch("http://example.com/lang/fr.json"); const text = await resp.text(); expect(text).toMatchInlineSnapshot('"Bonjour"'); }); diff --git a/fixtures/unstable_dev/package.json b/fixtures/unstable_dev/package.json deleted file mode 100644 index 307b7250b5b3..000000000000 --- a/fixtures/unstable_dev/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@fixture/unstable-dev", - "private": true, - "description": "", - "license": "ISC", - "author": "", - "scripts": { - "dev": "node --no-warnings ./src/wrangler-dev.mjs", - "test:ci": "npm run dev" - }, - "devDependencies": { - "wrangler": "workspace:*" - }, - "volta": { - "extends": "../../package.json" - } -} diff --git a/fixtures/unstable_dev/src/index.js b/fixtures/unstable_dev/src/index.js deleted file mode 100644 index 2a8547782586..000000000000 --- a/fixtures/unstable_dev/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -export default { - async fetch(request) { - return new Response(`${request.url} ${new Date()}`); - }, -}; diff --git a/fixtures/unstable_dev/src/wrangler-dev.mjs b/fixtures/unstable_dev/src/wrangler-dev.mjs deleted file mode 100644 index 8ae981ce8cdc..000000000000 --- a/fixtures/unstable_dev/src/wrangler-dev.mjs +++ /dev/null @@ -1,11 +0,0 @@ -import { unstable_dev } from "wrangler"; - -//since the script is invoked from the directory above, need to specify index.js is in src/ -const worker = await unstable_dev("dist/out.js", { config: "wrangler.jsonc" }); - -const resp = await worker.fetch("http://localhost:8787/"); -const text = await resp.text(); - -console.log("Invoked worker: ", text); - -await worker.stop(); diff --git a/fixtures/unstable_dev/wrangler.jsonc b/fixtures/unstable_dev/wrangler.jsonc deleted file mode 100644 index bc93fcbd9608..000000000000 --- a/fixtures/unstable_dev/wrangler.jsonc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "unstable_dev", - "main": "dist/out.js", - "compatibility_date": "2022-12-08", - "build": { - "command": "npx esbuild src/index.js --outfile=dist/out.js", - }, -} diff --git a/packages/edge-preview-authenticated-proxy/package.json b/packages/edge-preview-authenticated-proxy/package.json index 03354fc5104b..c04aed14fc7c 100644 --- a/packages/edge-preview-authenticated-proxy/package.json +++ b/packages/edge-preview-authenticated-proxy/package.json @@ -12,12 +12,14 @@ }, "devDependencies": { "@cloudflare/eslint-config-shared": "workspace:*", + "@cloudflare/vitest-pool-workers": "catalog:default", "@cloudflare/workers-types": "catalog:default", "@types/cookie": "^0.6.0", "cookie": "^0.7.2", "eslint": "catalog:default", "promjs": "^0.4.2", "toucan-js": "4.0.0", + "vitest": "catalog:default", "wrangler": "workspace:*" }, "volta": { diff --git a/packages/edge-preview-authenticated-proxy/tests/index.test.ts b/packages/edge-preview-authenticated-proxy/tests/index.test.ts index 889659bb002e..800069b921a3 100644 --- a/packages/edge-preview-authenticated-proxy/tests/index.test.ts +++ b/packages/edge-preview-authenticated-proxy/tests/index.test.ts @@ -1,10 +1,9 @@ import { randomBytes } from "node:crypto"; -import fs from "node:fs/promises"; -import os from "node:os"; -import path from "node:path"; -import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { Unstable_DevWorker } from "wrangler"; +import { SELF } from "cloudflare:test"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +// Mock URL for the remote worker - all outbound fetches will be intercepted +const MOCK_REMOTE_URL = "http://mock-remote.test"; function removeUUID(str: string) { return str.replace( @@ -13,88 +12,80 @@ function removeUUID(str: string) { ); } -describe("Preview Worker", () => { - let worker: Unstable_DevWorker; - let remote: Unstable_DevWorker; - let tmpDir: string; - - beforeAll(async () => { - worker = await unstable_dev(path.join(__dirname, "../src/index.ts"), { - config: path.join(__dirname, "../wrangler.jsonc"), - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - }, - logLevel: "none", - }); +// Mock implementation for the remote worker +function createMockFetchImplementation() { + return async (input: Request | string | URL, init?: RequestInit) => { + const request = new Request(input, init); + const url = new URL(request.url); - tmpDir = await fs.realpath( - await fs.mkdtemp(path.join(os.tmpdir(), "preview-tests")) - ); - - await fs.writeFile( - path.join(tmpDir, "remote.js"), - /*javascript*/ ` - export default { - fetch(request) { - const url = new URL(request.url) - if(url.pathname === "/exchange") { - return Response.json({ - token: "TEST_TOKEN", - prewarm: "TEST_PREWARM" - }) - } - if(url.pathname === "/redirect") { - return Response.redirect("https://example.com", 302) - } - if(url.pathname === "/method") { - return new Response(request.method) - } - if(url.pathname === "/status") { - return new Response(407) - } - if(url.pathname === "/header") { - return new Response(request.headers.get("X-Custom-Header")) - } - return Response.json({ - url: request.url, - headers: [...request.headers.entries()] - }) - } - } - `.trim() - ); + // Only intercept requests to our mock remote URL + if (url.origin !== MOCK_REMOTE_URL) { + return new Response("OK", { status: 200 }); + } + + if (url.pathname === "/exchange") { + return Response.json({ + token: "TEST_TOKEN", + prewarm: "TEST_PREWARM", + }); + } + if (url.pathname === "/redirect") { + // Use manual redirect to avoid trailing slash being added + return new Response(null, { + status: 302, + headers: { Location: "https://example.com" }, + }); + } + if (url.pathname === "/method") { + // HEAD requests should return empty body + const body = request.method === "HEAD" ? null : request.method; + return new Response(body, { + headers: { "Test-Http-Method": request.method }, + }); + } + if (url.pathname === "/status") { + return new Response("407"); + } + if (url.pathname === "/header") { + return new Response(request.headers.get("X-Custom-Header")); + } + if (url.pathname === "/cookies") { + const headers = new Headers(); + headers.append("Set-Cookie", "foo=1"); + headers.append("Set-Cookie", "bar=2"); + return new Response(undefined, { headers }); + } + if (url.pathname === "/prewarm") { + return new Response("OK"); + } - await fs.writeFile( - path.join(tmpDir, "wrangler.toml"), - /*toml*/ ` -name = "remote-worker" -compatibility_date = "2023-01-01" - `.trim() + return Response.json( + { + url: request.url, + headers: [...request.headers.entries()], + }, + { headers: { "Content-Encoding": "identity" } } ); + }; +} - remote = await unstable_dev(path.join(tmpDir, "remote.js"), { - config: path.join(tmpDir, "wrangler.toml"), - ip: "127.0.0.1", - experimental: { disableExperimentalWarning: true }, - }); +describe("Preview Worker", () => { + beforeEach(() => { + vi.spyOn(globalThis, "fetch").mockImplementation( + createMockFetchImplementation() + ); }); - afterAll(async () => { - await worker.stop(); - await remote.stop(); - - try { - await fs.rm(tmpDir, { recursive: true }); - } catch {} + afterEach(() => { + vi.restoreAllMocks(); }); let tokenId: string | null = null; it("should obtain token from exchange_url", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://preview.devprod.cloudflare.dev/exchange?exchange_url=${encodeURIComponent( - `http://127.0.0.1:${remote.port}/exchange` + `${MOCK_REMOTE_URL}/exchange` )}`, { method: "POST", @@ -112,7 +103,7 @@ compatibility_date = "2023-01-01" }); it("should reject invalid exchange_url", async () => { vi.spyOn(console, "error").mockImplementation(() => {}); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://preview.devprod.cloudflare.dev/exchange?exchange_url=not_an_exchange_url`, { method: "POST" } ); @@ -126,13 +117,13 @@ compatibility_date = "2023-01-01" const token = randomBytes(4096).toString("hex"); expect(token.length).toBe(8192); - let resp = await worker.fetch( + let resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/.update-preview-token?token=${encodeURIComponent( token )}&prewarm=${encodeURIComponent( - `http://127.0.0.1:${remote.port}/prewarm` + `${MOCK_REMOTE_URL}/prewarm` )}&remote=${encodeURIComponent( - `http://127.0.0.1:${remote.port}` + `${MOCK_REMOTE_URL}` )}&suffix=${encodeURIComponent("/hello?world")}`, { method: "GET", @@ -151,7 +142,7 @@ compatibility_date = "2023-01-01" tokenId = (resp.headers.get("set-cookie") ?? "") .split(";")[0] .split("=")[1]; - resp = await worker.fetch( + resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev`, { method: "GET", @@ -165,16 +156,16 @@ compatibility_date = "2023-01-01" const json = (await resp.json()) as any; expect(json).toMatchObject({ - url: `http://127.0.0.1:${remote.port}/`, + url: `${MOCK_REMOTE_URL}/`, headers: expect.arrayContaining([["cf-workers-preview-token", token]]), }); }); it("should be redirected with cookie", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/.update-preview-token?token=TEST_TOKEN&prewarm=${encodeURIComponent( - `http://127.0.0.1:${remote.port}/prewarm` + `${MOCK_REMOTE_URL}/prewarm` )}&remote=${encodeURIComponent( - `http://127.0.0.1:${remote.port}` + `${MOCK_REMOTE_URL}` )}&suffix=${encodeURIComponent("/hello?world")}`, { method: "GET", @@ -195,9 +186,9 @@ compatibility_date = "2023-01-01" }); it("should reject invalid prewarm url", async () => { vi.spyOn(console, "error").mockImplementation(() => {}); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/.update-preview-token?token=TEST_TOKEN&prewarm=not_a_prewarm_url&remote=${encodeURIComponent( - `http://127.0.0.1:${remote.port}` + `${MOCK_REMOTE_URL}` )}&suffix=${encodeURIComponent("/hello?world")}` ); expect(resp.status).toBe(400); @@ -207,9 +198,9 @@ compatibility_date = "2023-01-01" }); it("should reject invalid remote url", async () => { vi.spyOn(console, "error").mockImplementation(() => {}); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/.update-preview-token?token=TEST_TOKEN&prewarm=${encodeURIComponent( - `http://127.0.0.1:${remote.port}/prewarm` + `${MOCK_REMOTE_URL}/prewarm` )}&remote=not_a_remote_url&suffix=${encodeURIComponent("/hello?world")}` ); expect(resp.status).toBe(400); @@ -219,7 +210,7 @@ compatibility_date = "2023-01-01" }); it("should convert cookie to header", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev`, { method: "GET", @@ -231,14 +222,14 @@ compatibility_date = "2023-01-01" const json = (await resp.json()) as { headers: string[][]; url: string }; expect(json).toMatchObject({ - url: `http://127.0.0.1:${remote.port}/`, + url: `${MOCK_REMOTE_URL}/`, headers: expect.arrayContaining([ ["cf-workers-preview-token", "TEST_TOKEN"], ]), }); }); it("should not follow redirects", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/redirect`, { method: "GET", @@ -256,7 +247,7 @@ compatibility_date = "2023-01-01" expect(await resp.text()).toMatchInlineSnapshot('""'); }); it("should return method", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/method`, { method: "PUT", @@ -270,7 +261,7 @@ compatibility_date = "2023-01-01" expect(await resp.text()).toMatchInlineSnapshot('"PUT"'); }); it("should return header", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/header`, { method: "PUT", @@ -285,7 +276,7 @@ compatibility_date = "2023-01-01" expect(await resp.text()).toMatchInlineSnapshot('"custom"'); }); it("should return status", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://random-data.preview.devprod.cloudflare.dev/status`, { method: "PUT", @@ -301,90 +292,18 @@ compatibility_date = "2023-01-01" }); describe("Raw HTTP preview", () => { - let worker: Unstable_DevWorker; - let remote: Unstable_DevWorker; - let tmpDir: string; - - beforeAll(async () => { - worker = await unstable_dev(path.join(__dirname, "../src/index.ts"), { - // @ts-expect-error TODO: figure out the right way to get the server to accept host from the request - host: "0000.rawhttp.devprod.cloudflare.dev", - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - }, - }); - - tmpDir = await fs.realpath( - await fs.mkdtemp(path.join(os.tmpdir(), "preview-tests")) - ); - - await fs.writeFile( - path.join(tmpDir, "remote.js"), - /*javascript*/ ` - export default { - fetch(request) { - const url = new URL(request.url) - if(url.pathname === "/exchange") { - return Response.json({ - token: "TEST_TOKEN", - prewarm: "TEST_PREWARM" - }) - } - if(url.pathname === "/redirect") { - return Response.redirect("https://example.com", 302) - } - if(url.pathname === "/method") { - return new Response(request.method, { - headers: { "Test-Http-Method": request.method }, - }) - } - if(url.pathname === "/status") { - return new Response(407) - } - if(url.pathname === "/header") { - return new Response(request.headers.get("X-Custom-Header")) - } - if(url.pathname === "/cookies") { - const headers = new Headers(); - - headers.append("Set-Cookie", "foo=1"); - headers.append("Set-Cookie", "bar=2"); - - return new Response(undefined, { - headers, - }); - } - return Response.json({ - url: request.url, - headers: [...request.headers.entries()] - }, { headers: { "Content-Encoding": "identity" } }) - } - } - `.trim() + beforeEach(() => { + vi.spyOn(globalThis, "fetch").mockImplementation( + createMockFetchImplementation() ); - - await fs.writeFile( - path.join(tmpDir, "wrangler.toml"), - /*toml*/ ` -name = "remote-worker" -compatibility_date = "2023-01-01" - `.trim() - ); - - remote = await unstable_dev(path.join(tmpDir, "remote.js"), { - config: path.join(tmpDir, "wrangler.toml"), - ip: "127.0.0.1", - experimental: { disableExperimentalWarning: true }, - }); }); - afterAll(async () => { - await worker.stop(); + afterEach(() => { + vi.restoreAllMocks(); }); it("should allow arbitrary headers in cross-origin requests", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev`, { method: "OPTIONS", @@ -399,7 +318,7 @@ compatibility_date = "2023-01-01" }); it("should allow arbitrary methods in cross-origin requests", async () => { - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev`, { method: "OPTIONS", @@ -415,7 +334,7 @@ compatibility_date = "2023-01-01" it("should preserve multiple cookies", async () => { const token = randomBytes(4096).toString("hex"); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev/cookies`, { method: "GET", @@ -423,7 +342,7 @@ compatibility_date = "2023-01-01" "Access-Control-Request-Method": "GET", origin: "https://cloudflare.dev", "X-CF-Token": token, - "X-CF-Remote": `http://127.0.0.1:${remote.port}`, + "X-CF-Remote": MOCK_REMOTE_URL, }, } ); @@ -435,7 +354,7 @@ compatibility_date = "2023-01-01" it("should pass headers to the user-worker", async () => { const token = randomBytes(4096).toString("hex"); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev/`, { method: "GET", @@ -443,7 +362,7 @@ compatibility_date = "2023-01-01" "Access-Control-Request-Method": "GET", origin: "https://cloudflare.dev", "X-CF-Token": token, - "X-CF-Remote": `http://127.0.0.1:${remote.port}`, + "X-CF-Remote": MOCK_REMOTE_URL, "Some-Custom-Header": "custom", Accept: "application/json", }, @@ -473,14 +392,14 @@ compatibility_date = "2023-01-01" it("should use the method specified on the X-CF-Http-Method header", async () => { const token = randomBytes(4096).toString("hex"); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev/method`, { method: "POST", headers: { origin: "https://cloudflare.dev", "X-CF-Token": token, - "X-CF-Remote": `http://127.0.0.1:${remote.port}`, + "X-CF-Remote": MOCK_REMOTE_URL, "X-CF-Http-Method": "PUT", }, } @@ -493,14 +412,14 @@ compatibility_date = "2023-01-01" "should support %s method specified on the X-CF-Http-Method header", async (method) => { const token = randomBytes(4096).toString("hex"); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev/method`, { method: "POST", headers: { origin: "https://cloudflare.dev", "X-CF-Token": token, - "X-CF-Remote": `http://127.0.0.1:${remote.port}`, + "X-CF-Remote": MOCK_REMOTE_URL, "X-CF-Http-Method": method, }, } @@ -515,14 +434,14 @@ compatibility_date = "2023-01-01" it("should fallback to the request method if the X-CF-Http-Method header is missing", async () => { const token = randomBytes(4096).toString("hex"); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev/method`, { method: "PUT", headers: { origin: "https://cloudflare.dev", "X-CF-Token": token, - "X-CF-Remote": `http://127.0.0.1:${remote.port}`, + "X-CF-Remote": MOCK_REMOTE_URL, }, } ); @@ -532,7 +451,7 @@ compatibility_date = "2023-01-01" it("should strip cf-ew-raw- prefix from headers which have it before hitting the user-worker", async () => { const token = randomBytes(4096).toString("hex"); - const resp = await worker.fetch( + const resp = await SELF.fetch( `https://0000.rawhttp.devprod.cloudflare.dev/`, { method: "GET", @@ -540,7 +459,7 @@ compatibility_date = "2023-01-01" "Access-Control-Request-Method": "GET", origin: "https://cloudflare.dev", "X-CF-Token": token, - "X-CF-Remote": `http://127.0.0.1:${remote.port}`, + "X-CF-Remote": MOCK_REMOTE_URL, "cf-ew-raw-Some-Custom-Header": "custom", "cf-ew-raw-Accept": "application/json", }, diff --git a/packages/edge-preview-authenticated-proxy/tests/tsconfig.json b/packages/edge-preview-authenticated-proxy/tests/tsconfig.json index d52edf9eed2b..1ba476ce3ea9 100644 --- a/packages/edge-preview-authenticated-proxy/tests/tsconfig.json +++ b/packages/edge-preview-authenticated-proxy/tests/tsconfig.json @@ -1,19 +1,18 @@ { "compilerOptions": { - "target": "esnext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "lib": [ - "esnext" - ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, - "module": "es2022" /* Specify what module code is generated. */, - "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, - "allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */, - "checkJs": false /* Enable error reporting in type-checked JavaScript files. */, - "noEmit": true /* Disable emitting files from a compilation. */, - "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, - "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */, - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - "strict": true /* Enable all strict type-checking options. */, - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "target": "esnext", + "lib": ["esnext"], + "module": "esnext", + "moduleResolution": "bundler", + "types": ["@cloudflare/vitest-pool-workers"], + "allowJs": true, + "checkJs": false, + "noEmit": true, + "isolatedModules": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true }, - "include": ["**/*.test.ts"] + "include": ["**/*.test.ts", "../src/env.d.ts"] } diff --git a/packages/edge-preview-authenticated-proxy/tsconfig.json b/packages/edge-preview-authenticated-proxy/tsconfig.json index a9031db0d0e2..a95fca4d43f8 100644 --- a/packages/edge-preview-authenticated-proxy/tsconfig.json +++ b/packages/edge-preview-authenticated-proxy/tsconfig.json @@ -18,5 +18,5 @@ "strict": true /* Enable all strict type-checking options. */, "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "exclude": ["**/*.test.ts"] + "exclude": ["**/*.test.ts", "vitest.config.mts"] } diff --git a/packages/edge-preview-authenticated-proxy/vitest.config.mts b/packages/edge-preview-authenticated-proxy/vitest.config.mts index 846cddc41995..2537c5862e35 100644 --- a/packages/edge-preview-authenticated-proxy/vitest.config.mts +++ b/packages/edge-preview-authenticated-proxy/vitest.config.mts @@ -1,9 +1,27 @@ -import { defineProject, mergeConfig } from "vitest/config"; -import configShared from "../../vitest.shared"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config"; -export default mergeConfig( - configShared, - defineProject({ - test: {}, - }) -); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export default defineWorkersConfig({ + test: { + poolOptions: { + workers: { + singleWorker: true, + isolatedStorage: false, + wrangler: { + configPath: "./wrangler.jsonc", + }, + }, + }, + }, + resolve: { + // promjs has broken package.json (main points to lib/index.js but files are at root) + // This was reported 5 years ago and is still not fixed: https://github.com/weaveworks/promjs/issues/23 + // TODO: find a more maintained alternative to promjs + alias: { + promjs: path.resolve(__dirname, "node_modules/promjs/index.js"), + }, + }, +}); diff --git a/packages/wrangler/e2e/dev-registry.test.ts b/packages/wrangler/e2e/dev-registry.test.ts index 648cbd63e2e1..0eaad3a8fb3f 100644 --- a/packages/wrangler/e2e/dev-registry.test.ts +++ b/packages/wrangler/e2e/dev-registry.test.ts @@ -1,4 +1,3 @@ -import { execSync } from "node:child_process"; import getPort from "get-port"; import dedent from "ts-dedent"; import { fetch, Request } from "undici"; @@ -7,8 +6,7 @@ import { WranglerE2ETestHelper } from "./helpers/e2e-wrangler-test"; import { fetchText } from "./helpers/fetch-text"; import { generateResourceName } from "./helpers/generate-resource-name"; import { normalizeOutput } from "./helpers/normalize"; -import { seed as baseSeed, makeRoot, seed } from "./helpers/setup"; -import { WRANGLER_IMPORT } from "./helpers/wrangler"; +import { seed as baseSeed, makeRoot } from "./helpers/setup"; import type { RequestInit } from "undici"; async function fetchJson(url: string, info?: RequestInit): Promise { @@ -34,125 +32,6 @@ async function fetchJson(url: string, info?: RequestInit): Promise { ); } -describe("unstable_dev()", () => { - let parent: string; - let child: string; - let workerName: string; - let registryPath: string; - - beforeEach(async () => { - workerName = generateResourceName("worker"); - - registryPath = makeRoot(); - - parent = makeRoot(); - - await seed(parent, { - "wrangler.toml": dedent` - name = "app" - compatibility_date = "2023-01-01" - compatibility_flags = ["nodejs_compat"] - - [[services]] - binding = "WORKER" - service = '${workerName}' - `, - "src/index.ts": dedent/* javascript */ ` - export default { - async fetch(req, env) { - return new Response("Hello from Parent!" + await env.WORKER.fetch(req).then(r => r.text())) - }, - }; - `, - "package.json": dedent` - { - "name": "app", - "version": "0.0.0", - "private": true - } - `, - }); - - child = await makeRoot(); - await seed(child, { - "wrangler.toml": dedent` - name = "${workerName}" - main = "src/index.ts" - compatibility_date = "2023-01-01" - `, - "src/index.ts": dedent/* javascript */ ` - export default { - fetch(req, env) { - return new Response("Hello from Child!") - }, - }; - `, - "package.json": dedent` - { - "name": "${workerName}", - "version": "0.0.0", - "private": true - } - `, - }); - }); - - async function runInNode() { - await seed(parent, { - "index.mjs": dedent/*javascript*/ ` - import { unstable_dev } from "${WRANGLER_IMPORT}" - import { setTimeout } from "node:timers/promises"; - import { readdirSync } from "node:fs" - - const childWorker = await unstable_dev( - "${child.replaceAll("\\", "/")}/src/index.ts", - { - experimental: { - disableExperimentalWarning: true, - }, - } - ); - - for (const timeout of [1000, 2000, 4000, 8000, 16000]) { - if(readdirSync(process.env.WRANGLER_REGISTRY_PATH).includes("${workerName}")) { - break - } - await setTimeout(timeout) - } - - const parentWorker = await unstable_dev( - "src/index.ts", - { - experimental: { - disableExperimentalWarning: true, - }, - } - ); - - console.log(await parentWorker.fetch("/").then(r => r.text())) - - process.exit(0); - `, - }); - const stdout = execSync(`node index.mjs`, { - cwd: parent, - encoding: "utf-8", - env: { - ...process.env, - WRANGLER_REGISTRY_PATH: registryPath, - }, - }); - return stdout; - } - - it("can fetch child", async () => { - await expect(runInNode()).resolves.toMatchInlineSnapshot(` - "Hello from Parent!Hello from Child! - " - `); - }); -}); - describe.each([{ cmd: "wrangler dev" }])("dev registry $cmd", ({ cmd }) => { let workerName: string; let workerName2: string; diff --git a/packages/wrangler/src/__tests__/api-dev.test.ts b/packages/wrangler/src/__tests__/api-dev.test.ts deleted file mode 100644 index 32adc0e4b70a..000000000000 --- a/packages/wrangler/src/__tests__/api-dev.test.ts +++ /dev/null @@ -1,263 +0,0 @@ -import * as fs from "node:fs"; -import { Request } from "undici"; -import { describe, expect, it, vi } from "vitest"; -import { unstable_dev } from "../api"; -import { mockConsoleMethods } from "./helpers/mock-console"; -import { runInTempDir } from "./helpers/run-in-tmp"; - -vi.unmock("child_process"); -vi.unmock("undici"); - -describe("unstable_dev", () => { - runInTempDir(); - mockConsoleMethods(); - it("should return Hello World", async () => { - writeHelloWorldWorker(); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello World!"`); - } - await worker.stop(); - }); - - it("should return the port that the server started on (1)", async () => { - writeHelloWorldWorker(); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - expect(worker.port).toBeGreaterThan(0); - await worker.stop(); - }); - - it("should return the port that the server started on (2)", async () => { - writeHelloWorldWorker(); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - expect(worker.port).not.toBe(0); - await worker.stop(); - }); -}); - -describe("unstable dev fetch input protocol", () => { - runInTempDir(); - - it("should use http localProtocol", async () => { - writeHelloWorldWorker(); - const worker = await unstable_dev("index.js", { - localProtocol: "http", - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const res = await worker.fetch(); - if (res) { - const text = await res.text(); - expect(text).toMatchInlineSnapshot(`"Hello World!"`); - } - await worker.stop(); - }); - - it("should use undefined localProtocol", async () => { - writeHelloWorldWorker(); - const worker = await unstable_dev("index.js", { - localProtocol: undefined, - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const res = await worker.fetch(); - if (res) { - const text = await res.text(); - expect(text).toMatchInlineSnapshot(`"Hello World!"`); - } - await worker.stop(); - }); -}); - -describe("unstable dev fetch input parsing", () => { - runInTempDir(); - - it("should pass in a request object unchanged", async () => { - const scriptContent = ` - export default { - fetch(request, env, ctx) { - const url = new URL(request.url); - if (url.pathname === "/test") { - if (request.method === "POST") { - return new Response("requestPOST"); - } - return new Response("requestGET"); - } - return new Response('Hello world'); - } - }; - `; - fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const req = new Request(`http://127.0.0.1:${worker.port}/test`, { - method: "POST", - }); - const resp = await worker.fetch(req); - let text; - if (resp) { - text = await resp.text(); - } - expect(text).toMatchInlineSnapshot(`"requestPOST"`); - await worker.stop(); - }); - - it("should strip back to pathname for URL objects", async () => { - const scriptContent = ` - export default { - fetch(request, env, ctx) { - const url = new URL(request.url); - if (url.pathname === "/test") { - return new Response("request"); - } - return new Response('Hello world'); - } - }; - `; - fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const url = new URL("http://localhost:80/test"); - const resp = await worker.fetch(url); - let text; - if (resp) { - text = await resp.text(); - } - expect(text).toMatchInlineSnapshot(`"request"`); - await worker.stop(); - }); - - it("should allow full url passed in string, and stripped back to pathname", async () => { - const scriptContent = ` - export default { - fetch(request, env, ctx) { - const url = new URL(request.url); - if (url.pathname === "/test") { - return new Response("request"); - } - return new Response('Hello world'); - } - }; - `; - fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const resp = await worker.fetch("http://example.com/test"); - let text; - if (resp) { - text = await resp.text(); - } - expect(text).toMatchInlineSnapshot(`"request"`); - await worker.stop(); - }); - - it("should allow pathname to be passed in", async () => { - const scriptContent = ` - export default { - fetch(request, env, ctx) { - const url = new URL(request.url); - if (url.pathname === "/test") { - return new Response("request"); - } - return new Response('Hello world'); - } - }; - `; - fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const resp = await worker.fetch("/test"); - let text; - if (resp) { - text = await resp.text(); - } - expect(text).toMatchInlineSnapshot(`"request"`); - await worker.stop(); - }); - - it("should allow no input be passed in", async () => { - const scriptContent = ` - export default { - fetch(request, env, ctx) { - const url = new URL(request.url); - if (url.pathname === "/test") { - return new Response("request"); - } - return new Response('Hello world'); - } - }; - `; - fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, - }, - }); - const resp = await worker.fetch(""); - let text; - if (resp) { - text = await resp.text(); - } - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); -}); - -const writeHelloWorldWorker = () => { - const scriptContent = ` - export default { - fetch(request, env, ctx) { - return new Response("Hello World!"); - }, - }; - `; - fs.writeFileSync("index.js", scriptContent); -}; diff --git a/packages/wrangler/src/__tests__/middleware.scheduled.test.ts b/packages/wrangler/src/__tests__/middleware.scheduled.test.ts index 3b3088868e07..c140da11d8ca 100644 --- a/packages/wrangler/src/__tests__/middleware.scheduled.test.ts +++ b/packages/wrangler/src/__tests__/middleware.scheduled.test.ts @@ -1,6 +1,6 @@ import * as fs from "node:fs"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { unstable_dev } from "../api"; +import { startWorker } from "../api/startDevWorker"; import { runInTempDir } from "./helpers/run-in-tmp"; vi.unmock("child_process"); @@ -38,98 +38,98 @@ describe("run scheduled events with middleware", () => { }); it("should not intercept when middleware is not enabled", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch("/__scheduled"); + const resp = await worker.fetch("http://dummy/__scheduled"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Fetch triggered at /__scheduled"`); - await worker.stop(); + await worker.dispose(); }); it("should intercept when middleware is enabled", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/__scheduled"); + const resp = await worker.fetch("http://dummy/__scheduled"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Ran scheduled event"`); - await worker.stop(); + await worker.dispose(); }); it("should not trigger scheduled event on wrong route", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/test"); + const resp = await worker.fetch("http://dummy/test"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world!"`); - await worker.stop(); + await worker.dispose(); }); it("should respond with 404 for favicons", async () => { - const worker = await unstable_dev("only-scheduled.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "only-scheduled.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/favicon.ico", { + const resp = await worker.fetch("http://dummy/favicon.ico", { headers: { referer: "http://localhost/__scheduled", }, }); expect(resp.status).toEqual(404); - await worker.stop(); + await worker.dispose(); }); it("should not respond with 404 for favicons if user-worker has a response", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/favicon.ico", { + const resp = await worker.fetch("http://dummy/favicon.ico", { headers: { referer: "http://localhost/__scheduled", }, }); expect(resp.status).not.toEqual(404); - await worker.stop(); + await worker.dispose(); }); }); @@ -162,98 +162,98 @@ describe("run scheduled events with middleware", () => { }); it("should not intercept when middleware is not enabled", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch("/__scheduled"); + const resp = await worker.fetch("http://dummy/__scheduled"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Fetch triggered at /__scheduled"`); - await worker.stop(); + await worker.dispose(); }); it("should intercept when middleware is enabled", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/__scheduled"); + const resp = await worker.fetch("http://dummy/__scheduled"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Ran scheduled event"`); - await worker.stop(); + await worker.dispose(); }); it("should not trigger scheduled event on wrong route", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/test"); + const resp = await worker.fetch("http://dummy/test"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world!"`); - await worker.stop(); + await worker.dispose(); }); it("should respond with 404 for favicons", async () => { - const worker = await unstable_dev("only-scheduled.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "only-scheduled.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/favicon.ico", { + const resp = await worker.fetch("http://dummy/favicon.ico", { headers: { referer: "http://localhost/__scheduled", }, }); expect(resp.status).toEqual(404); - await worker.stop(); + await worker.dispose(); }); it("should not respond with 404 for favicons if user-worker has a response", async () => { - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, }, }); - const resp = await worker.fetch("/favicon.ico", { + const resp = await worker.fetch("http://dummy/favicon.ico", { headers: { referer: "http://localhost/__scheduled", }, }); expect(resp.status).not.toEqual(404); - await worker.stop(); + await worker.dispose(); }); }); }); diff --git a/packages/wrangler/src/__tests__/middleware.test.ts b/packages/wrangler/src/__tests__/middleware.test.ts index f0cede87de01..20d930448586 100644 --- a/packages/wrangler/src/__tests__/middleware.test.ts +++ b/packages/wrangler/src/__tests__/middleware.test.ts @@ -3,7 +3,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import dedent from "ts-dedent"; import { beforeEach, describe, expect, it, vi } from "vitest"; -import { unstable_dev } from "../api"; +import { startWorker } from "../api/startDevWorker"; import { mockConsoleMethods } from "./helpers/mock-console"; import { runInTempDir } from "./helpers/run-in-tmp"; import { runWrangler } from "./helpers/run-wrangler"; @@ -52,21 +52,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should be able to access scheduled workers from middleware", async () => { @@ -86,21 +86,21 @@ describe("middleware", () => { fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"OK"`); - await worker.stop(); + await worker.dispose(); }); it("should trigger an error in a scheduled work from middleware", async () => { @@ -123,21 +123,21 @@ describe("middleware", () => { fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Error in scheduled worker"`); - await worker.stop(); + await worker.dispose(); }); }); @@ -156,21 +156,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should register a middleware and intercept using addMiddlewareInternal", async () => { @@ -187,21 +187,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should be able to access scheduled workers from middleware", async () => { @@ -218,21 +218,21 @@ describe("middleware", () => { fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"OK"`); - await worker.stop(); + await worker.dispose(); }); it("should trigger an error in a scheduled work from middleware", async () => { @@ -252,21 +252,21 @@ describe("middleware", () => { fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Error in scheduled worker"`); - await worker.stop(); + await worker.dispose(); }); }); }); @@ -289,20 +289,20 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); if (resp) { const text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); } - await worker.stop(); + await worker.dispose(); }); it("should return hello world with empty middleware array", async () => { @@ -317,21 +317,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should return hello world passing through middleware", async () => { @@ -349,20 +349,20 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); if (resp) { const text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); } - await worker.stop(); + await worker.dispose(); }); it("should return hello world with multiple middleware in array", async () => { @@ -383,21 +383,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should leave response headers unchanged with middleware", async () => { @@ -415,15 +415,15 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); const status = resp?.status; let text; if (resp) { @@ -433,7 +433,7 @@ describe("middleware", () => { expect(status).toEqual(500); expect(text).toMatchInlineSnapshot(`"Hello world"`); expect(testHeader).toEqual("test"); - await worker.stop(); + await worker.dispose(); }); it("waitUntil should not block responses", async () => { @@ -460,21 +460,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world0"`); - await worker.stop(); + await worker.dispose(); }); }); @@ -487,20 +487,20 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); if (resp) { const text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); } - await worker.stop(); + await worker.dispose(); }); it("should return hello world with empty middleware array", async () => { @@ -512,21 +512,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should return hello world passing through middleware", async () => { @@ -541,20 +541,20 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); if (resp) { const text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); } - await worker.stop(); + await worker.dispose(); }); it("should return hello world with addMiddleware function called multiple times", async () => { @@ -573,21 +573,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should return hello world with addMiddleware function called with array of middleware", async () => { @@ -605,21 +605,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should return hello world with addMiddlewareInternal function called multiple times", async () => { @@ -638,21 +638,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should return hello world with addMiddlewareInternal function called with array of middleware", async () => { @@ -670,21 +670,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should return hello world with both addMiddleware and addMiddlewareInternal called", async () => { @@ -703,21 +703,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); + await worker.dispose(); }); it("should leave response headers unchanged with middleware", async () => { @@ -731,15 +731,15 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); const status = resp?.status; let text; if (resp) { @@ -749,7 +749,7 @@ describe("middleware", () => { expect(status).toEqual(500); expect(text).toMatchInlineSnapshot(`"Hello world"`); expect(testHeader).toEqual("test"); - await worker.stop(); + await worker.dispose(); }); it("should allow multiple addEventListeners for fetch", async () => { @@ -764,21 +764,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world1"`); - await worker.stop(); + await worker.dispose(); }); it("waitUntil should not block responses", async () => { @@ -797,21 +797,21 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, }, }); - const resp = await worker.fetch(); + const resp = await worker.fetch("http://dummy"); let text; if (resp) { text = await resp.text(); } expect(text).toMatchInlineSnapshot(`"Hello world0"`); - await worker.stop(); + await worker.dispose(); }); }); }); @@ -1058,32 +1058,38 @@ describe("middleware", () => { `; fs.writeFileSync("index.js", scriptContent); - const worker = await unstable_dev("index.js", { - ip: "127.0.0.1", - experimental: { - disableExperimentalWarning: true, - disableDevRegistry: true, + const worker = await startWorker({ + entrypoint: "index.js", + dev: { + server: { hostname: "127.0.0.1", port: 0 }, + inspector: false, testScheduled: true, - d1Databases: [ - { - binding: "DB", - database_name: "db", - database_id: "00000000-0000-0000-0000-000000000000", - }, - ], + }, + bindings: { + DB: { + type: "d1", + database_name: "db", + database_id: "00000000-0000-0000-0000-000000000000", + }, }, }); try { - let res = await worker.fetch("http://localhost/setup"); + await worker.ready; + const url = await worker.url; + // TODO(startWorker): worker.fetch() doesn't work correctly with paths when + // EXPERIMENTAL_MIDDLEWARE=true is set. The request URL pathname gets + // lost, causing the worker to not match routes like "/setup". + // We use native fetch() with the worker URL as a workaround. + let res = await fetch(new URL("/setup", url).href); expect(res.status).toBe(204); - res = await worker.fetch("http://localhost/__scheduled"); + res = await fetch(new URL("/__scheduled", url).href); expect(res.status).toBe(200); expect(await res.text()).toBe("Ran scheduled event"); - res = await worker.fetch("http://localhost/query"); + res = await fetch(new URL("/query", url).href); expect(res.status).toBe(200); expect(await res.json()).toEqual([{ id: 1, value: "one" }]); - res = await worker.fetch("http://localhost/bad"); + res = await fetch(new URL("/bad", url).href); expect(res.status).toBe(500); // TODO: in miniflare we don't have the `pretty-error` middleware implemented. // instead it uses `middleware-miniflare3-json-error`, which outputs JSON rather than text. @@ -1092,7 +1098,7 @@ describe("middleware", () => { // ); expect(await res.text()).toContain("Not found!"); } finally { - await worker.stop(); + await worker.dispose(); } }); }); diff --git a/packages/wrangler/templates/init-tests/test-jest-new-worker.js b/packages/wrangler/templates/init-tests/test-jest-new-worker.js deleted file mode 100644 index d33aa9159e30..000000000000 --- a/packages/wrangler/templates/init-tests/test-jest-new-worker.js +++ /dev/null @@ -1,23 +0,0 @@ -const { unstable_dev } = require("wrangler"); - -describe("Worker", () => { - let worker; - - beforeAll(async () => { - worker = await unstable_dev("src/index.js", { - experimental: { disableExperimentalWarning: true }, - }); - }); - - afterAll(async () => { - await worker.stop(); - }); - - it("should return Hello World", async () => { - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello World!"`); - } - }); -}); diff --git a/packages/wrangler/templates/init-tests/test-vitest-new-worker.js b/packages/wrangler/templates/init-tests/test-vitest-new-worker.js deleted file mode 100644 index 3ff265e50f47..000000000000 --- a/packages/wrangler/templates/init-tests/test-vitest-new-worker.js +++ /dev/null @@ -1,24 +0,0 @@ -import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; - -describe("Worker", () => { - let worker; - - beforeAll(async () => { - worker = await unstable_dev("src/index.js", { - experimental: { disableExperimentalWarning: true }, - }); - }); - - afterAll(async () => { - await worker.stop(); - }); - - it("should return Hello World", async () => { - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello World!"`); - } - }); -}); diff --git a/packages/wrangler/templates/init-tests/test-vitest-new-worker.ts b/packages/wrangler/templates/init-tests/test-vitest-new-worker.ts deleted file mode 100644 index 2430ea5a5e03..000000000000 --- a/packages/wrangler/templates/init-tests/test-vitest-new-worker.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import { unstable_dev } from "wrangler"; -import type { Unstable_DevWorker } from "wrangler"; - -describe("Worker", () => { - let worker: Unstable_DevWorker; - - beforeAll(async () => { - worker = await unstable_dev("src/index.ts", { - experimental: { disableExperimentalWarning: true }, - }); - }); - - afterAll(async () => { - await worker.stop(); - }); - - it("should return Hello World", async () => { - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello World!"`); - } - }); -}); diff --git a/packages/wrangler/templates/tsconfig.json b/packages/wrangler/templates/tsconfig.json index 672ae3c4e8a7..0b51f60963f4 100644 --- a/packages/wrangler/templates/tsconfig.json +++ b/packages/wrangler/templates/tsconfig.json @@ -6,7 +6,6 @@ "include": ["**/*.ts"], "exclude": [ "__tests__", - "./init-tests/**", // Note: `startDevWorker` and `middleware` should also be included but some work is needed // for that first (see: https://github.com/cloudflare/workers-sdk/issues/8303) "startDevWorker", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c1c66a53217b..1d6818d5e86f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1160,12 +1160,6 @@ importers: specifier: 3.22.3 version: 3.22.3 - fixtures/unstable_dev: - devDependencies: - wrangler: - specifier: workspace:* - version: link:../../packages/wrangler - fixtures/vitest-pool-workers-examples: devDependencies: '@cloudflare/containers': @@ -1795,6 +1789,9 @@ importers: '@cloudflare/eslint-config-shared': specifier: workspace:* version: link:../eslint-config-shared + '@cloudflare/vitest-pool-workers': + specifier: catalog:default + version: 0.10.15(@cloudflare/workers-types@4.20260122.0)(@vitest/runner@3.2.3)(@vitest/snapshot@3.2.3)(vitest@3.2.3) '@cloudflare/workers-types': specifier: catalog:default version: 4.20260122.0 @@ -1813,6 +1810,9 @@ importers: toucan-js: specifier: 4.0.0 version: 4.0.0(patch_hash=qxsfpdzvzbhq2ecirbu5xq4vlq) + vitest: + specifier: catalog:default + version: 3.2.3(@types/debug@4.1.12)(@types/node@20.19.9)(@vitest/ui@3.2.3)(jiti@2.6.0)(lightningcss@1.30.2)(msw@2.12.0(@types/node@20.19.9)(typescript@5.9.3))(yaml@2.8.1) wrangler: specifier: workspace:* version: link:../wrangler @@ -8631,9 +8631,6 @@ packages: birpc@0.2.14: resolution: {integrity: sha512-37FHE8rqsYM5JEKCnXFyHpBCzvgHEExwVVTq+nUmloInU7l8ezD1TpOhKpS8oe1DTYFqEK27rFZVKG43oTqXRA==} - birpc@2.6.1: - resolution: {integrity: sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==} - birpc@2.8.0: resolution: {integrity: sha512-Bz2a4qD/5GRhiHSwj30c/8kC8QGj12nNDwz3D4ErQ4Xhy35dsSDvF+RA/tWpjyU0pdGtSDiEk6B5fBGE1qNVhw==} @@ -15469,7 +15466,7 @@ snapshots: devalue: 5.3.2 miniflare: 4.20251210.0 semver: 7.7.3 - vitest: 3.2.3(@types/debug@4.1.12)(@types/node@20.19.9)(@vitest/ui@3.2.3)(jiti@2.6.0)(lightningcss@1.30.2)(msw@2.12.0(@types/node@20.19.9)(typescript@5.8.3))(supports-color@9.2.2)(yaml@2.8.1) + vitest: 3.2.3(@types/debug@4.1.12)(@types/node@20.19.9)(@vitest/ui@3.2.3)(jiti@2.6.0)(lightningcss@1.30.2)(msw@2.12.0(@types/node@20.19.9)(typescript@5.9.3))(yaml@2.8.1) wrangler: 4.54.0(@cloudflare/workers-types@4.20260122.0) zod: 3.25.76 transitivePeerDependencies: @@ -19053,8 +19050,6 @@ snapshots: birpc@0.2.14: {} - birpc@2.6.1: {} - birpc@2.8.0: {} bl@4.1.0: @@ -23412,7 +23407,7 @@ snapshots: '@babel/parser': 7.28.4 '@babel/types': 7.28.4 ast-kit: 2.1.3 - birpc: 2.6.1 + birpc: 2.8.0 debug: 4.4.3 dts-resolver: 2.1.2 get-tsconfig: 4.13.0 diff --git a/tools/github-workflow-helpers/auto-assign-issues.ts b/tools/github-workflow-helpers/auto-assign-issues.ts index 8a1c314ec3ae..6e8bfaf7c874 100644 --- a/tools/github-workflow-helpers/auto-assign-issues.ts +++ b/tools/github-workflow-helpers/auto-assign-issues.ts @@ -39,7 +39,6 @@ const TEAM_ASSIGNMENTS: { [label: string]: { [jobRole: string]: string } } = { types: { em: "lrapoport-cf", pm: "mattietk" }, "types-ai": { em: "jkipp-cloudflare" }, unenv: { em: "lrapoport-cf", pm: "mattietk" }, - unstable_dev: { em: "lrapoport-cf", pm: "mattietk" }, vectorize: { em: "sejoker", pm: "jonesphillip" }, "vite-plugin": { em: "lrapoport-cf", pm: "mattietk" }, vitest: { em: "lrapoport-cf", pm: "mattietk" },