diff --git a/.changeset/modern-flowers-care.md b/.changeset/modern-flowers-care.md new file mode 100644 index 00000000000..359a56d6e20 --- /dev/null +++ b/.changeset/modern-flowers-care.md @@ -0,0 +1,10 @@ +--- +"wrangler": patch +--- + +fix: allow Workflow bindings when calling getPlatformProxy() + +Workflow bindings are not supported in practice when using `getPlatformProxy()`. +But their existence in a Wrangler config file should not prevent other bindings from working. +Previously, calling `getPlatformProxy()` would crash if there were any Workflow bindings defined. +Now, instead, you get a warning telling you that these bindings are not available. 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 2fc44412ffa..cf8996ee22f 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 @@ -14,6 +14,7 @@ import type { Fetcher, Hyperdrive, KVNamespace, + Workflow, } from "@cloudflare/workers-types"; import type { Unstable_DevWorker } from "wrangler"; @@ -28,16 +29,21 @@ type Env = { MY_D1: D1Database; MY_HYPERDRIVE: Hyperdrive; ASSETS: Fetcher; + MY_WORKFLOW_INTERNAL: Workflow; + MY_WORKFLOW_EXTERNAL: Workflow; }; const wranglerConfigFilePath = path.join(__dirname, "..", "wrangler.jsonc"); describe("getPlatformProxy - env", () => { let devWorkers: Unstable_DevWorker[]; + let warn = {} as MockInstance; beforeEach(() => { // Hide stdout messages from the test logs vi.spyOn(console, "log").mockImplementation(() => {}); + vi.spyOn(console, "error").mockImplementation(() => {}); + warn = vi.spyOn(console, "warn").mockImplementation(() => {}); }); describe("var bindings", () => { @@ -221,41 +227,20 @@ describe("getPlatformProxy - env", () => { }); describe("DO warnings", () => { - let warn = {} as MockInstance; - beforeEach(() => { - warn = vi.spyOn(console, "warn").mockImplementation(() => {}); - }); - afterEach(() => { - warn.mockRestore(); - }); - it("warns about internal DOs and doesn't crash", async () => { await getPlatformProxy({ configPath: path.join(__dirname, "..", "wrangler_internal_do.jsonc"), }); - expect(warn).toMatchInlineSnapshot(` - [MockFunction warn] { - "calls": [ - [ - "▲ [WARNING]  You have defined bindings to the following internal Durable Objects: - - - {"class_name":"MyDurableObject","name":"MY_DURABLE_OBJECT"} - These will not work in local development, but they should work in production. - - If you want to develop these locally, you can define your DO in a separate Worker, with a separate configuration file. - For detailed instructions, refer to the Durable Objects section here: https://developers.cloudflare.com/workers/wrangler/api#supported-bindings + expect(warn.mock.calls[0][0].replaceAll(/[\r\n]+/g, "\n")) + .toMatchInlineSnapshot(` + "▲ [WARNING]  You have defined bindings to the following internal Durable Objects: + - {"class_name":"MyDurableObject","name":"MY_DURABLE_OBJECT"} + These will not work in local development, but they should work in production. - ", - ], - ], - "results": [ - { - "type": "return", - "value": undefined, - }, - ], - } - `); + If you want to develop these locally, you can define your DO in a separate Worker, with a separate configuration file. + For detailed instructions, refer to the Durable Objects section here: https://developers.cloudflare.com/workers/wrangler/api#supported-bindings + " + `); }); it("doesn't warn about external DOs and doesn't crash", async () => { @@ -264,6 +249,20 @@ describe("getPlatformProxy - env", () => { }); expect(warn).not.toHaveBeenCalled(); }); + + it("warns about Workflows and doesn't crash", async () => { + await getPlatformProxy({ + configPath: path.join(__dirname, "..", "wrangler_workflow.jsonc"), + }); + expect(warn.mock.calls[0][0].replaceAll(/[\r\n]+/g, "\n")) + .toMatchInlineSnapshot(` + "▲ [WARNING]  You have defined bindings to the following Workflows: + - {"binding":"MY_WORKFLOW_INTERNAL","name":"my-workflow-internal","class_name":"MyWorkflowInternal"} + - {"binding":"MY_WORKFLOW_EXTERNAL","name":"my-workflow-external","class_name":"MyWorkflowExternal","script_name":"OtherWorker"} + These are not available in local development, so you will not be able to bind to them when testing locally, but they should work in production. + " + `); + }); }); describe("with a target environment", () => { diff --git a/fixtures/get-platform-proxy/vitest.config.mts b/fixtures/get-platform-proxy/vitest.config.mts index 74c6ea85d13..7e6a5dfa673 100644 --- a/fixtures/get-platform-proxy/vitest.config.mts +++ b/fixtures/get-platform-proxy/vitest.config.mts @@ -6,5 +6,6 @@ export default defineConfig({ hookTimeout: 25_000, teardownTimeout: 25_000, useAtomics: true, + restoreMocks: true, }, }); diff --git a/fixtures/get-platform-proxy/wrangler_workflow.jsonc b/fixtures/get-platform-proxy/wrangler_workflow.jsonc new file mode 100644 index 00000000000..d636accf61b --- /dev/null +++ b/fixtures/get-platform-proxy/wrangler_workflow.jsonc @@ -0,0 +1,22 @@ +{ + "name": "workflow-test", + "main": "src/index.ts", + // An internal workflow is indicated by the binding not specifying a script name. + // This implies the workflow is exported alongside this worker in `index.ts`, which it isn't actually. + // However we don't care about this here because `getPlatformProxy()` will discard all user code anyway. + // We are simply making sure the warning shows up. + "compatibility_date": "2023-11-21", + "workflows": [ + { + "binding": "MY_WORKFLOW_INTERNAL", + "name": "my-workflow-internal", + "class_name": "MyWorkflowInternal", + }, + { + "binding": "MY_WORKFLOW_EXTERNAL", + "name": "my-workflow-external", + "class_name": "MyWorkflowExternal", + "script_name": "OtherWorker", + }, + ], +} diff --git a/packages/wrangler/src/api/integrations/platform/index.ts b/packages/wrangler/src/api/integrations/platform/index.ts index 88ec3860140..edffe4cd309 100644 --- a/packages/wrangler/src/api/integrations/platform/index.ts +++ b/packages/wrangler/src/api/integrations/platform/index.ts @@ -161,6 +161,17 @@ async function getMiniflareOptionsFromConfig( durableObjects: rawConfig["durable_objects"], }); + if (rawConfig.workflows?.length > 0) { + logger.warn(dedent` + You have defined bindings to the following Workflows: + ${rawConfig.workflows.map((b) => `- ${JSON.stringify(b)}`).join("\n")} + These are not available in local development, so you will not be able to bind to them when testing locally, but they should work in production. + `); + + // Remove workflows from bindings to prevent Miniflare from complaining + bindings.workflows = []; + } + const { bindingOptions, externalWorkers } = buildMiniflareBindingOptions({ name: rawConfig.name, bindings,