diff --git a/.changeset/fair-chairs-rhyme.md b/.changeset/fair-chairs-rhyme.md new file mode 100644 index 000000000000..a78769fc17a6 --- /dev/null +++ b/.changeset/fair-chairs-rhyme.md @@ -0,0 +1,15 @@ +--- +"wrangler": patch +--- + +feat: testing scheduled events with `wrangler dev` remote mode + +Using the new middleware (https://github.com/cloudflare/wrangler2/pull/1735), we implement a way of testing scheduled workers from a fetch using `wrangler dev` in remote mode, by passing a new command line flag `--test-scheduled`. This exposes a route `/__scheduled` which will trigger the scheduled event. + +```sh +$ npx wrangler dev index.js --test-scheduled + +$ curl http://localhost:8787/__scheduled +``` + +Closes https://github.com/cloudflare/wrangler2/issues/570 diff --git a/packages/wrangler/src/__tests__/dev.test.tsx b/packages/wrangler/src/__tests__/dev.test.tsx index 6ea7a89a82f2..06a78cb2744d 100644 --- a/packages/wrangler/src/__tests__/dev.test.tsx +++ b/packages/wrangler/src/__tests__/dev.test.tsx @@ -1027,7 +1027,8 @@ describe("wrangler dev", () => { --node-compat Enable node.js compatibility [boolean] --persist Enable persistence for local mode, using default path: .wrangler/state [boolean] --persist-to Specify directory to use for local persistence (implies --persist) [string] - --inspect Enable dev tools [deprecated] [boolean]", + --inspect Enable dev tools [deprecated] [boolean] + --test-scheduled Test scheduled events by visiting /__scheduled in browser [boolean] [default: false]", "warn": "", } `); diff --git a/packages/wrangler/src/__tests__/middleware.scheduled.test.ts b/packages/wrangler/src/__tests__/middleware.scheduled.test.ts new file mode 100644 index 000000000000..49377100483b --- /dev/null +++ b/packages/wrangler/src/__tests__/middleware.scheduled.test.ts @@ -0,0 +1,135 @@ +import * as fs from "node:fs"; +import { unstable_dev } from "../api"; +import { runInTempDir } from "./helpers/run-in-tmp"; + +jest.unmock("undici"); + +describe("run scheduled events with middleware", () => { + describe("module workers", () => { + runInTempDir(); + + beforeEach(() => { + const scriptContent = ` + export default { + fetch(request, env, ctx) { + const url = new URL(request.url); + if (url.pathname === "/__scheduled") { + return new Response("Fetch triggered at /__scheduled"); + } + return new Response("Hello world!"); + }, + scheduled(controller, env, ctx) { + console.log("Doing something scheduled in modules..."); + }, + }; + `; + fs.writeFileSync("index.js", scriptContent); + }); + + it("should not intercept when middleware is not enabled", async () => { + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch("/__scheduled"); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Fetch triggered at /__scheduled"`); + await worker.stop(); + }); + + it("should intercept when middleware is enabled", async () => { + const worker = await unstable_dev( + "index.js", + { testScheduled: true }, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch("/__scheduled"); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Ran scheduled event"`); + await worker.stop(); + }); + + it("should not trigger scheduled event on wrong route", async () => { + const worker = await unstable_dev( + "index.js", + { testScheduled: true }, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch("/test"); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world!"`); + await worker.stop(); + }); + }); + + describe("service workers", () => { + runInTempDir(); + + beforeEach(() => { + const scriptContent = ` + addEventListener("scheduled", (event) => { + console.log("Doing something scheduled in service worker..."); + }); + + addEventListener("fetch", (event) => { + const url = new URL(event.request.url); + if (url.pathname === "/__scheduled") { + event.respondWith(new Response("Fetch triggered at /__scheduled")); + } else { + event.respondWith(new Response("Hello world!")); + } + }); + `; + fs.writeFileSync("index.js", scriptContent); + }); + + it("should not intercept when middleware is not enabled", async () => { + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch("/__scheduled"); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Fetch triggered at /__scheduled"`); + await worker.stop(); + }); + + it("should intercept when middleware is enabled", async () => { + const worker = await unstable_dev( + "index.js", + { testScheduled: true }, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch("/__scheduled"); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Ran scheduled event"`); + await worker.stop(); + }); + + it("should not trigger scheduled event on wrong route", async () => { + const worker = await unstable_dev( + "index.js", + { testScheduled: true }, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch("/test"); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world!"`); + await worker.stop(); + }); + }); +}); diff --git a/packages/wrangler/src/__tests__/middleware.test.ts b/packages/wrangler/src/__tests__/middleware.test.ts index cf8f67d4d4da..ff73701a80fc 100644 --- a/packages/wrangler/src/__tests__/middleware.test.ts +++ b/packages/wrangler/src/__tests__/middleware.test.ts @@ -1,768 +1,726 @@ import * as fs from "node:fs"; import { unstable_dev } from "../api"; -import { unsetAllMocks } from "./helpers/mock-cfetch"; -import { useMockIsTTY } from "./helpers/mock-istty"; import { runInTempDir } from "./helpers/run-in-tmp"; jest.unmock("undici"); -describe("module workers change behaviour with middleware with wrangler dev", () => { +describe("workers change behaviour with middleware with wrangler dev", () => { runInTempDir(); - const { setIsTTY } = useMockIsTTY(); - - beforeEach(() => { - setIsTTY(true); - }); - - afterEach(() => { - unsetAllMocks(); - }); - - process.env.EXPERIMENTAL_MIDDLEWARE = "true"; - - it("should register a middleware and intercept", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - const response = await middlewareCtx.next(request, env); - const text = await response.text(); - return new Response(text + ' world'); - } - - export default { - middleware: [middleware], - fetch(request, env, ctx) { - return new Response('Hello'); - } - }; - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should be able to access scheduled workers from middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); - return new Response("OK"); - } - - export default { - middleware: [middleware], - scheduled(controller, env, ctx) { - console.log("Scheduled worker called"); - } - } - `; - - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"OK"`); - await worker.stop(); - }); - - it("should trigger an error in a scheduled work from middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - try { - await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); - } catch (e) { - return new Response(e.message); - } - } - - export default { - middleware: [middleware], - scheduled(controller, env, ctx) { - throw new Error("Error in scheduled worker"); - } - } - `; - - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Error in scheduled worker"`); - await worker.stop(); - }); -}); - -describe("service workers change behaviour with middleware with wrangler dev", () => { - runInTempDir(); - const { setIsTTY } = useMockIsTTY(); - - beforeEach(() => { - setIsTTY(true); - }); - - afterEach(() => { - unsetAllMocks(); - }); - - process.env.EXPERIMENTAL_MIDDLEWARE = "true"; - - it("should register a middleware and intercept using addMiddleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - const response = await middlewareCtx.next(request, env); - const text = await response.text(); - return new Response(text + ' world'); - } - - addMiddleware(middleware); - - addEventListener("fetch", (event) => { - event.respondWith(new Response('Hello')); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should register a middleware and intercept using addMiddlewareInternal", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - const response = await middlewareCtx.next(request, env); - const text = await response.text(); - return new Response(text + ' world'); - } - - addMiddlewareInternal(middleware); - - addEventListener("fetch", (event) => { - event.respondWith(new Response('Hello')); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should be able to access scheduled workers from middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); - return new Response("OK"); - } - - addMiddleware(middleware); - - addEventListener("scheduled", (event) => { - console.log("Scheduled worker called"); - }); - `; - - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"OK"`); - await worker.stop(); - }); - - it("should trigger an error in a scheduled work from middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - try { - await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); - } catch (e) { - return new Response(e.message); - } - } - - addMiddleware(middleware); - - addEventListener("scheduled", (event) => { - throw new Error("Error in scheduled worker"); - }); - `; - - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Error in scheduled worker"`); - await worker.stop(); - }); -}); - -describe("unchanged functionality when wrapping with middleware (modules)", () => { - runInTempDir(); - const { setIsTTY } = useMockIsTTY(); - - beforeEach(() => { - setIsTTY(true); - }); - - afterEach(() => { - unsetAllMocks(); - }); process.env.EXPERIMENTAL_MIDDLEWARE = "true"; - it("should return Hello World with no middleware export", async () => { - const scriptContent = ` - export default { - fetch(request, env, ctx) { - return new Response("Hello world"); - } - }; - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); + describe("module workers", () => { + it("should register a middleware and intercept", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + const response = await middlewareCtx.next(request, env); + const text = await response.text(); + return new Response(text + ' world'); + } + + export default { + middleware: [middleware], + fetch(request, env, ctx) { + return new Response('Hello'); + } + }; + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); - } - await worker.stop(); - }); - - it("should return hello world with empty middleware array", async () => { - const scriptContent = ` - export default { - middleware: [], - fetch() { - return new Response("Hello world"); - } - } - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should return hello world passing through middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - export default { - middleware: [middleware], - fetch(request, env, ctx) { - return new Response("Hello world"); - } - } - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); + await worker.stop(); + }); + + it("should be able to access scheduled workers from middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); + return new Response("OK"); + } + + export default { + middleware: [middleware], + scheduled(controller, env, ctx) { + console.log("Scheduled worker called"); + } + } + `; + + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"OK"`); + await worker.stop(); + }); + + it("should trigger an error in a scheduled work from middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + try { + await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); + } catch (e) { + return new Response(e.message); + } + } + + export default { + middleware: [middleware], + scheduled(controller, env, ctx) { + throw new Error("Error in scheduled worker"); + } + } + `; + + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Error in scheduled worker"`); + await worker.stop(); + }); + }); + + describe("service workers", () => { + it("should register a middleware and intercept using addMiddleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + const response = await middlewareCtx.next(request, env); + const text = await response.text(); + return new Response(text + ' world'); + } + + addMiddleware(middleware); + + addEventListener("fetch", (event) => { + event.respondWith(new Response('Hello')); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); - } - await worker.stop(); - }); - - it("should return hello world with multiple middleware in array", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - const middleware2 = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - - export default { - middleware: [middleware, middleware2], - fetch() { - return new Response("Hello world"); - } - } - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should leave response headers unchanged with middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - export default { - middleware: [middleware], - fetch() { - return new Response("Hello world", { status: 500, headers: { "x-test": "test" } }); - } - } - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - const status = resp?.status; - let text; - if (resp) text = await resp.text(); - const testHeader = resp?.headers.get("x-test"); - expect(status).toEqual(500); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - expect(testHeader).toEqual("test"); - await worker.stop(); - }); - - it("waitUntil should not block responses", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - export default { - middleware: [middleware], - async fetch(request, env, ctx) { - let count = 0; - ctx.waitUntil(new Promise(resolve => { - setTimeout(() => { - count += 1; - console.log("waitUntil", count); - resolve() - }, 1000); - })); - return new Response("Hello world" + String(count)); - } - } - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world0"`); - await worker.stop(); + await worker.stop(); + }); + + it("should register a middleware and intercept using addMiddlewareInternal", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + const response = await middlewareCtx.next(request, env); + const text = await response.text(); + return new Response(text + ' world'); + } + + addMiddlewareInternal(middleware); + + addEventListener("fetch", (event) => { + event.respondWith(new Response('Hello')); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + await worker.stop(); + }); + + it("should be able to access scheduled workers from middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); + return new Response("OK"); + } + + addMiddleware(middleware); + + addEventListener("scheduled", (event) => { + console.log("Scheduled worker called"); + }); + `; + + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"OK"`); + await worker.stop(); + }); + + it("should trigger an error in a scheduled work from middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + try { + await middlewareCtx.dispatch("scheduled", { cron: "* * * * *" }); + } catch (e) { + return new Response(e.message); + } + } + + addMiddleware(middleware); + + addEventListener("scheduled", (event) => { + throw new Error("Error in scheduled worker"); + }); + `; + + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Error in scheduled worker"`); + await worker.stop(); + }); }); }); -describe("unchanged functionality when wrapping with middlware (service workers)", () => { +describe("unchanged functionality when wrapping with middleware", () => { runInTempDir(); - const { setIsTTY } = useMockIsTTY(); - - beforeEach(() => { - setIsTTY(true); - }); - - afterEach(() => { - unsetAllMocks(); - }); process.env.EXPERIMENTAL_MIDDLEWARE = "true"; - it("should return Hello World with no middleware export", async () => { - const scriptContent = ` - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); + describe("module workers", () => { + it("should return Hello World with no middleware export", async () => { + const scriptContent = ` + export default { + fetch(request, env, ctx) { + return new Response("Hello world"); + } + }; + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + if (resp) { + const text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + } + await worker.stop(); + }); + + it("should return hello world with empty middleware array", async () => { + const scriptContent = ` + export default { + middleware: [], + fetch() { + return new Response("Hello world"); + } + } + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); - } - await worker.stop(); - }); - - it("should return hello world with empty middleware array", async () => { - const scriptContent = ` - addMiddleware([]); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should return hello world passing through middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - addMiddleware(middleware); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - if (resp) { - const text = await resp.text(); + await worker.stop(); + }); + + it("should return hello world passing through middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + export default { + middleware: [middleware], + fetch(request, env, ctx) { + return new Response("Hello world"); + } + } + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + if (resp) { + const text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + } + await worker.stop(); + }); + + it("should return hello world with multiple middleware in array", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + const middleware2 = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + + export default { + middleware: [middleware, middleware2], + fetch() { + return new Response("Hello world"); + } + } + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); expect(text).toMatchInlineSnapshot(`"Hello world"`); - } - await worker.stop(); - }); - - it("should return hello world with addMiddleware function called multiple times", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - const middleware2 = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - addMiddleware(middleware); - addMiddleware(middleware2); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should return hello world with addMiddleware function called with array of middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - const middleware2 = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - addMiddleware(middleware, middleware2); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should return hello world with addMiddlewareInternal function called multiple times", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - const middleware2 = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - addMiddlewareInternal(middleware); - addMiddlewareInternal(middleware2); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should return hello world with addMiddlewareInternal function called with array of middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - const middleware2 = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - addMiddlewareInternal(middleware, middleware2); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should return hello world with both addMiddleware and addMiddlewareInternal called", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - const middleware2 = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - addMiddleware(middleware); - addMiddlewareInternal(middleware2); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world")); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - await worker.stop(); - }); - - it("should leave response headers unchanged with middleware", async () => { - const scriptContent = ` - const middleware = async (request, env, _ctx, middlewareCtx) => { - return middlewareCtx.next(request, env); - } - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world", { status: 500, headers: { "x-test": "test" } })); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - const status = resp?.status; - let text; - if (resp) text = await resp.text(); - const testHeader = resp?.headers.get("x-test"); - expect(status).toEqual(500); - expect(text).toMatchInlineSnapshot(`"Hello world"`); - expect(testHeader).toEqual("test"); - await worker.stop(); - }); - - it("should allow multiple addEventListeners for fetch", async () => { - const scriptContent = ` - let count = 0; - - addEventListener("fetch", (event) => { - count += 1; - }); - - addEventListener("fetch", (event) => { - event.respondWith(new Response("Hello world" + String(count))); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world1"`); - await worker.stop(); - }); - - it("waitUntil should not block responses", async () => { - const scriptContent = ` - addEventListener("fetch", (event) => { - - let count = 0; - event.waitUntil(new Promise((resolve) => { - setTimeout(() => { - count +=1; - console.log('waitUntil', count); - resolve(); - }, 1000); - })); - event.respondWith(new Response("Hello world" + String(count))); - }); - `; - fs.writeFileSync("index.js", scriptContent); - - const worker = await unstable_dev( - "index.js", - {}, - { disableExperimentalWarning: true } - ); - - const resp = await worker.fetch(); - let text; - if (resp) text = await resp.text(); - expect(text).toMatchInlineSnapshot(`"Hello world0"`); - await worker.stop(); + await worker.stop(); + }); + + it("should leave response headers unchanged with middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + export default { + middleware: [middleware], + fetch() { + return new Response("Hello world", { status: 500, headers: { "x-test": "test" } }); + } + } + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + const status = resp?.status; + let text; + if (resp) text = await resp.text(); + const testHeader = resp?.headers.get("x-test"); + expect(status).toEqual(500); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + expect(testHeader).toEqual("test"); + await worker.stop(); + }); + + it("waitUntil should not block responses", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + export default { + middleware: [middleware], + async fetch(request, env, ctx) { + let count = 0; + ctx.waitUntil(new Promise(resolve => { + setTimeout(() => { + count += 1; + console.log("waitUntil", count); + resolve() + }, 1000); + })); + return new Response("Hello world" + String(count)); + } + } + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world0"`); + await worker.stop(); + }); + }); + + describe("service workers", () => { + it("should return Hello World with no middleware export", async () => { + const scriptContent = ` + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + if (resp) { + const text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + } + await worker.stop(); + }); + + it("should return hello world with empty middleware array", async () => { + const scriptContent = ` + addMiddleware([]); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + await worker.stop(); + }); + + it("should return hello world passing through middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + addMiddleware(middleware); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + if (resp) { + const text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + } + await worker.stop(); + }); + + it("should return hello world with addMiddleware function called multiple times", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + const middleware2 = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + addMiddleware(middleware); + addMiddleware(middleware2); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + await worker.stop(); + }); + + it("should return hello world with addMiddleware function called with array of middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + const middleware2 = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + addMiddleware(middleware, middleware2); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + await worker.stop(); + }); + + it("should return hello world with addMiddlewareInternal function called multiple times", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + const middleware2 = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + addMiddlewareInternal(middleware); + addMiddlewareInternal(middleware2); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + await worker.stop(); + }); + + it("should return hello world with addMiddlewareInternal function called with array of middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + const middleware2 = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + addMiddlewareInternal(middleware, middleware2); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + await worker.stop(); + }); + + it("should return hello world with both addMiddleware and addMiddlewareInternal called", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + const middleware2 = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + addMiddleware(middleware); + addMiddlewareInternal(middleware2); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world")); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + await worker.stop(); + }); + + it("should leave response headers unchanged with middleware", async () => { + const scriptContent = ` + const middleware = async (request, env, _ctx, middlewareCtx) => { + return middlewareCtx.next(request, env); + } + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world", { status: 500, headers: { "x-test": "test" } })); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + const status = resp?.status; + let text; + if (resp) text = await resp.text(); + const testHeader = resp?.headers.get("x-test"); + expect(status).toEqual(500); + expect(text).toMatchInlineSnapshot(`"Hello world"`); + expect(testHeader).toEqual("test"); + await worker.stop(); + }); + + it("should allow multiple addEventListeners for fetch", async () => { + const scriptContent = ` + let count = 0; + + addEventListener("fetch", (event) => { + count += 1; + }); + + addEventListener("fetch", (event) => { + event.respondWith(new Response("Hello world" + String(count))); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world1"`); + await worker.stop(); + }); + + it("waitUntil should not block responses", async () => { + const scriptContent = ` + addEventListener("fetch", (event) => { + + let count = 0; + event.waitUntil(new Promise((resolve) => { + setTimeout(() => { + count +=1; + console.log('waitUntil', count); + resolve(); + }, 1000); + })); + event.respondWith(new Response("Hello world" + String(count))); + }); + `; + fs.writeFileSync("index.js", scriptContent); + + const worker = await unstable_dev( + "index.js", + {}, + { disableExperimentalWarning: true } + ); + + const resp = await worker.fetch(); + let text; + if (resp) text = await resp.text(); + expect(text).toMatchInlineSnapshot(`"Hello world0"`); + await worker.stop(); + }); }); }); diff --git a/packages/wrangler/src/api/dev.ts b/packages/wrangler/src/api/dev.ts index 6f743efc9ca9..0edaccec892e 100644 --- a/packages/wrangler/src/api/dev.ts +++ b/packages/wrangler/src/api/dev.ts @@ -50,6 +50,7 @@ interface DevOptions { enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions; _?: (string | number)[]; //yargs wants this $0?: string; //yargs wants this + testScheduled?: boolean; } interface DevApiOptions { diff --git a/packages/wrangler/src/bundle.ts b/packages/wrangler/src/bundle.ts index 6798cc137580..44dcfc2cbfc9 100644 --- a/packages/wrangler/src/bundle.ts +++ b/packages/wrangler/src/bundle.ts @@ -7,7 +7,7 @@ import NodeModulesPolyfills from "@esbuild-plugins/node-modules-polyfill"; import * as esbuild from "esbuild"; import tmp from "tmp-promise"; import createModuleCollector from "./module-collection"; -import { getBasePath } from "./paths"; +import { getBasePath, toUrlPath } from "./paths"; import type { Config } from "./config"; import type { WorkerRegistry } from "./dev-registry"; import type { Entry } from "./entry"; @@ -76,6 +76,7 @@ export async function bundleWorker( workerDefinitions: WorkerRegistry | undefined; firstPartyWorkerDevFacade: boolean | undefined; targetConsumer: "dev" | "publish"; + testScheduled?: boolean | undefined; } ): Promise { const { @@ -93,6 +94,7 @@ export async function bundleWorker( services, firstPartyWorkerDevFacade, targetConsumer, + testScheduled, } = options; // We create a temporary directory for any oneoff files we @@ -144,16 +146,13 @@ export async function bundleWorker( // We also have middleware that uses a more "traditional" middleware stack, // which is all loaded as one in a stack. - const middlewareToLoad: MiddlewareLoader[] = [ - // { - // path: "templates/middleware/middleware-pretty-error.ts", - // publish: true, - // dev: false, - // }, - // { - // path: "../templates/middleware/middleware-scheduled.ts", - // }, - ]; + const middlewareToLoad: MiddlewareLoader[] = []; + + if (testScheduled) { + middlewareToLoad.push({ + path: "templates/middleware/middleware-scheduled.ts", + }); + } type MiddlewareFn = (arg0: Entry) => Promise; const middleware: (false | undefined | MiddlewareFn)[] = [ @@ -445,7 +444,7 @@ async function applyMiddlewareLoaderFacade( ...Object.fromEntries( middleware.map((val, index) => [ middlewareIdentifiers[index], - path.resolve(getBasePath(), val.path), + toUrlPath(path.resolve(getBasePath(), val.path)), ]) ), }), @@ -471,9 +470,8 @@ async function applyMiddlewareLoaderFacade( const imports = middlewareIdentifiers .map( (m, i) => - `import ${m} from "${path.resolve( - getBasePath(), - middleware[i].path + `import ${m} from "${toUrlPath( + path.resolve(getBasePath(), middleware[i].path) )}";` ) .join("\n"); diff --git a/packages/wrangler/src/dev.tsx b/packages/wrangler/src/dev.tsx index 4398cf9e6c84..188476080f5d 100644 --- a/packages/wrangler/src/dev.tsx +++ b/packages/wrangler/src/dev.tsx @@ -72,6 +72,7 @@ interface DevArgs { logLevel?: "none" | "error" | "log" | "warn" | "debug"; logPrefix?: string; showInteractiveDevSession?: boolean; + "test-scheduled"?: boolean; } export function devOptions(yargs: Argv): Argv { @@ -273,6 +274,11 @@ export function devOptions(yargs: Argv): Argv { describe: "Use legacy environments", hidden: true, }) + .option("test-scheduled", { + describe: "Test scheduled events by visiting /__scheduled in browser", + type: "boolean", + default: false, + }) ); } @@ -430,6 +436,7 @@ export async function startDev(args: StartDevOptions) { enablePagesAssetsServiceBinding={args.enablePagesAssetsServiceBinding} firstPartyWorker={configParam.first_party_worker} sendMetrics={configParam.send_metrics} + testScheduled={args["test-scheduled"]} /> ); } @@ -543,6 +550,7 @@ export async function startApiDev(args: StartDevOptions) { local: true, firstPartyWorker: undefined, sendMetrics: undefined, + testScheduled: args.testScheduled, }); } diff --git a/packages/wrangler/src/dev/dev.tsx b/packages/wrangler/src/dev/dev.tsx index 1d29734c5d1e..533f8860ed85 100644 --- a/packages/wrangler/src/dev/dev.tsx +++ b/packages/wrangler/src/dev/dev.tsx @@ -164,6 +164,7 @@ export type DevProps = { enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions; firstPartyWorker: boolean | undefined; sendMetrics: boolean | undefined; + testScheduled: boolean | undefined; }; export function DevImplementation(props: DevProps): JSX.Element { @@ -259,6 +260,7 @@ function DevSession(props: DevSessionProps) { firstPartyWorkerDevFacade: props.firstPartyWorker, // Enable the bundling to know whether we are using dev or publish targetConsumer: "dev", + testScheduled: props.testScheduled ?? false, }); return props.local ? ( diff --git a/packages/wrangler/src/dev/local.tsx b/packages/wrangler/src/dev/local.tsx index e1c98f026a2a..04d776ff2c15 100644 --- a/packages/wrangler/src/dev/local.tsx +++ b/packages/wrangler/src/dev/local.tsx @@ -52,6 +52,7 @@ export interface LocalProps { logLevel: "none" | "error" | "log" | "warn" | "debug" | undefined; logPrefix?: string; enablePagesAssetsServiceBinding?: EnablePagesAssetsServiceBindingOptions; + testScheduled?: boolean; } export function Local(props: LocalProps) { diff --git a/packages/wrangler/src/dev/start-server.ts b/packages/wrangler/src/dev/start-server.ts index fc71932dd485..5987f1f48073 100644 --- a/packages/wrangler/src/dev/start-server.ts +++ b/packages/wrangler/src/dev/start-server.ts @@ -65,6 +65,7 @@ export async function startDevServer( noBundle: props.noBundle, assets: props.assetsConfig, services: props.bindings.services, + testScheduled: props.testScheduled, }); //run local now @@ -129,6 +130,7 @@ async function runEsbuild({ nodeCompat, define, noBundle, + testScheduled, }: { entry: Entry; destination: string | undefined; @@ -143,6 +145,7 @@ async function runEsbuild({ minify: boolean | undefined; nodeCompat: boolean | undefined; noBundle: boolean; + testScheduled?: boolean; }): Promise { if (!destination) return; @@ -178,6 +181,7 @@ async function runEsbuild({ workerDefinitions: undefined, firstPartyWorkerDevFacade: undefined, targetConsumer: "dev", // We are starting a dev server + testScheduled, }); return { diff --git a/packages/wrangler/src/dev/use-esbuild.ts b/packages/wrangler/src/dev/use-esbuild.ts index ada7c3629bc7..6006a734d144 100644 --- a/packages/wrangler/src/dev/use-esbuild.ts +++ b/packages/wrangler/src/dev/use-esbuild.ts @@ -37,6 +37,7 @@ export function useEsbuild({ durableObjects, firstPartyWorkerDevFacade, targetConsumer, + testScheduled, }: { entry: Entry; destination: string | undefined; @@ -55,6 +56,7 @@ export function useEsbuild({ durableObjects: Config["durable_objects"]; firstPartyWorkerDevFacade: boolean | undefined; targetConsumer: "dev" | "publish"; + testScheduled: boolean; }): EsbuildBundle | undefined { const [bundle, setBundle] = useState(); const { exit } = useApp(); @@ -119,6 +121,7 @@ export function useEsbuild({ services, firstPartyWorkerDevFacade, targetConsumer, + testScheduled, }); // Capture the `stop()` method to use as the `useEffect()` destructor. @@ -177,6 +180,7 @@ export function useEsbuild({ workerDefinitions, firstPartyWorkerDevFacade, targetConsumer, + testScheduled, ]); return bundle; } diff --git a/packages/wrangler/templates/middleware/middleware-scheduled.ts b/packages/wrangler/templates/middleware/middleware-scheduled.ts index ae659dfb5b1f..3d9da2836858 100644 --- a/packages/wrangler/templates/middleware/middleware-scheduled.ts +++ b/packages/wrangler/templates/middleware/middleware-scheduled.ts @@ -6,7 +6,8 @@ const scheduled: Middleware = async (request, env, _ctx, middlewareCtx) => { if (url.pathname === "/__scheduled") { const cron = url.searchParams.get("cron") ?? ""; await middlewareCtx.dispatch("scheduled", { cron }); - return new Response("OK"); + + return new Response("Ran scheduled event"); } return middlewareCtx.next(request, env); };