Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .changeset/cruel-ears-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
"wrangler": patch
---

update `maybeStartOrUpdateRemoteProxySession` config argument (to allow callers to specify an environment)

Before this change `maybeStartOrUpdateRemoteProxySession` could be called with either the path to a wrangler config file or the configuration of a worker. The former override however did not allow the caller to specify an environment, so the `maybeStartOrUpdateRemoteProxySession` API has been updated so that in the wrangler config case an object (with the path and a potential environment) needs to be passed instead.

For example, before callers could invoke the function in the following way

```ts
await maybeStartOrUpdateRemoteProxySession(configPath);
```

note that there is no way to tell the function what environment to use when parsing the wrangle configuration.

Now callers will instead call the function in the following way:

```ts
await maybeStartOrUpdateRemoteProxySession({
path: configPath,
environment: targetEnvironment,
});
```

note that now a target environment can be specified.
5 changes: 5 additions & 0 deletions .changeset/giant-laws-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"wrangler": patch
---

fix `getPlatformProxy` not taking into account the potentially specified environment for remote bindings
5 changes: 5 additions & 0 deletions .changeset/stale-dogs-throw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@cloudflare/vitest-pool-workers": patch
---

fix the potentially specified environment not being taken into account for remote bindings
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
fetch() {
return new Response(
"Hello from a remote Worker, defined for the staging environment, part of the getPlatformProxy remote bindings fixture!"
);
},
};
61 changes: 61 additions & 0 deletions fixtures/get-platform-proxy-remote-bindings/tests/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const execOptions = {
env: { ...process.env, ...auth },
} as const;
const remoteWorkerName = `tmp-e2e-worker-test-remote-bindings-${randomUUID().split("-")[0]}`;
const remoteStagingWorkerName = `tmp-e2e-staging-worker-test-remote-bindings-${randomUUID().split("-")[0]}`;
const remoteKvName = `tmp-e2e-remote-kv-test-remote-bindings-${randomUUID().split("-")[0]}`;

if (auth) {
Expand All @@ -32,6 +33,19 @@ if (auth) {
throw new Error(`Failed to deploy ${remoteWorkerName}`);
}

const stagingDeployOut = execSync(
`pnpm wrangler deploy remote-worker.staging.js --name ${remoteStagingWorkerName} --compatibility-date 2025-06-19`,
execOptions
);

if (
!new RegExp(`Deployed\\s+${remoteStagingWorkerName}\\b`).test(
stagingDeployOut
)
) {
throw new Error(`Failed to deploy ${remoteStagingWorkerName}`);
}

const kvAddOut = execSync(
`pnpm wrangler kv namespace create ${remoteKvName}`,
execOptions
Expand Down Expand Up @@ -71,6 +85,24 @@ if (auth) {
experimental_remote: true,
},
],
env: {
staging: {
services: [
{
binding: "MY_WORKER",
service: remoteStagingWorkerName,
experimental_remote: true,
},
],
kv_namespaces: [
{
binding: "MY_KV",
id: remoteKvId,
experimental_remote: true,
},
],
},
},
},
undefined,
2
Expand All @@ -84,6 +116,10 @@ if (auth) {
`pnpm wrangler delete --name ${remoteWorkerName}`,
execOptions
);
execSync(
`pnpm wrangler delete --name ${remoteStagingWorkerName}`,
execOptions
);
execSync(
`pnpm wrangler kv namespace delete --namespace-id=${remoteKvId}`,
execOptions
Expand Down Expand Up @@ -115,6 +151,31 @@ if (auth) {
await dispose();
});

test("getPlatformProxy works with remote bindings specified in an environment", async () => {
vi.stubEnv("CLOUDFLARE_ACCOUNT_ID", auth.CLOUDFLARE_ACCOUNT_ID);
vi.stubEnv("CLOUDFLARE_API_TOKEN", auth.CLOUDFLARE_API_TOKEN);
const { env, dispose } = await getPlatformProxy<{
MY_WORKER: Fetcher;
MY_KV: KVNamespace;
}>({
configPath: "./.tmp/wrangler.json",
experimental: { remoteBindings: true },
environment: "staging",
});

const workerText = await (
await env.MY_WORKER.fetch("http://example.com")
).text();
expect(workerText).toEqual(
"Hello from a remote Worker, defined for the staging environment, part of the getPlatformProxy remote bindings fixture!"
);

const kvValue = await env.MY_KV.get("test-key");
expect(kvValue).toEqual("remote-kv-value");

await dispose();
});

test("getPlatformProxy does not work with remote bindings if the experimental remoteBindings flag is not turned on", async () => {
const { env, dispose } = await getPlatformProxy<{
MY_WORKER: Fetcher;
Expand Down
7 changes: 7 additions & 0 deletions fixtures/vitest-pool-workers-remote-bindings/env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Fetcher } from "@cloudflare/workers-types/experimental";

declare module "cloudflare:test" {
interface ProvidedEnv {
MY_WORKER: Fetcher;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
fetch() {
return new Response(
"Hello from a remote Worker, defined for the staging environment, part of the vitest-pool-workers remote bindings fixture!"
);
},
};
51 changes: 46 additions & 5 deletions fixtures/vitest-pool-workers-remote-bindings/run-tests.mjs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
/**
* This fixture is particular since it needs to communicate with remote resources, namely
* a remote worker.
* two remote workers.
*
* This script is used to deploy a remote worker and run the fixture using said worker.
*
* Alternatively you can simply deploy, using your account, the `./remote-worker.js` file as
* a worker named `my-worker-test` and directly run the fixture using vitest.
* This script is used to deploy the remote workers and run the fixture using said workers
* with the appropriate vitest configurations.
*/
import { execSync } from "child_process";
import { randomUUID } from "crypto";
Expand All @@ -22,11 +20,17 @@ rmSync("./.tmp", { recursive: true, force: true });
cpSync("./src", "./.tmp/src", { recursive: true });
cpSync("./test", "./.tmp/test", { recursive: true });
cpSync("./vitest.workers.config.ts", "./.tmp/vitest.workers.config.ts");
cpSync(
"./vitest.workers.config.staging.ts",
"./.tmp/vitest.workers.config.staging.ts"
);

const remoteWorkerName = `tmp-e2e-worker-test-remote-bindings-${randomUUID().split("-")[0]}`;
const remoteStagingWorkerName = `tmp-e2e-staging-worker-test-remote-bindings-${randomUUID().split("-")[0]}`;

const wranglerJson = JSON.parse(readFileSync("./wrangler.json", "utf8"));
wranglerJson.services[0].service = remoteWorkerName;
wranglerJson.env.staging.services[0].service = remoteStagingWorkerName;

writeFileSync(
"./.tmp/wrangler.json",
Expand Down Expand Up @@ -60,12 +64,49 @@ if (!new RegExp(`Deployed\\s+${remoteWorkerName}\\b`).test(`${deployOut}`)) {
throw new Error(`Failed to deploy ${remoteWorkerName}`);
}

writeFileSync(
"./.tmp/remote-wrangler.staging.json",
JSON.stringify(
{
name: remoteStagingWorkerName,
main: "../remote-worker.staging.js",
compatibility_date: "2025-06-01",
},
undefined,
2
),
"utf8"
);

const deployStagingOut = execSync(
"pnpm wrangler deploy -c .tmp/remote-wrangler.staging.json",
{
stdio: "pipe",
cwd: "./.tmp",
env,
}
);
if (
!new RegExp(`Deployed\\s+${remoteStagingWorkerName}\\b`).test(
`${deployStagingOut}`
)
) {
throw new Error(`Failed to deploy ${remoteStagingWorkerName}`);
}

try {
execSync("pnpm test:vitest --config ./.tmp/vitest.workers.config.ts", {
env,
});
execSync(
"pnpm test:vitest --config ./.tmp/vitest.workers.config.staging.ts",
{
env,
}
);
} finally {
execSync(`pnpm wrangler delete --name ${remoteWorkerName}`, { env });
execSync(`pnpm wrangler delete --name ${remoteStagingWorkerName}`, { env });
rmSync("./.tmp", { recursive: true, force: true });
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {
createExecutionContext,
env,
SELF,
waitOnExecutionContext,
} from "cloudflare:test";
import { describe, expect, test } from "vitest";

describe("Vitest pool workers remote bindings with a staging environment", () => {
test(
"fetching unit-style from a remote service binding",
{ timeout: 50_000 },
async () => {
const response = await env.MY_WORKER.fetch("http://example.com");
const ctx = createExecutionContext();
await waitOnExecutionContext(ctx);
expect(await response.text()).toMatchInlineSnapshot(
`"Hello from a remote Worker, defined for the staging environment, part of the vitest-pool-workers remote bindings fixture!"`
);
}
);

test("fetching integration-style from the local worker (which uses remote bindings)", async () => {
const response = await SELF.fetch("https://example.com");
expect(await response.text()).toMatchInlineSnapshot(
`"Response from remote worker: Hello from a remote Worker, defined for the staging environment, part of the vitest-pool-workers remote bindings fixture!"`
);
});
});
15 changes: 6 additions & 9 deletions fixtures/vitest-pool-workers-remote-bindings/test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,24 @@ import {
env,
SELF,
waitOnExecutionContext,
// @ts-ignore
} from "cloudflare:test";
import { describe, expect, it } from "vitest";
import { describe, expect, test } from "vitest";

describe("Hello World worker", () => {
it(
"responds with Hello World! (unit style)",
describe("Vitest pool workers remote bindings", () => {
test(
"fetching unit-style from a remote service binding",
{ timeout: 50_000 },
async () => {
const request = new Request("http://example.com");
const response = await env.MY_WORKER.fetch("http://example.com");
const ctx = createExecutionContext();
debugger;
const response = await env.MY_WORKER.fetch(request, env, ctx);
await waitOnExecutionContext(ctx);
expect(await response.text()).toMatchInlineSnapshot(
`"Hello from a remote Worker part of the vitest-pool-workers remote bindings fixture!"`
);
}
);

it("responds with Hello World! (integration style)", async () => {
test("fetching integration-style from the local worker (which uses remote bindings)", async () => {
const response = await SELF.fetch("https://example.com");
expect(await response.text()).toMatchInlineSnapshot(
`"Response from remote worker: Hello from a remote Worker part of the vitest-pool-workers remote bindings fixture!"`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";

class FilteredPushArray<T> extends Array<T> {
constructor(private readonly predicate: (item: T) => boolean) {
super();
}

push(...items: T[]) {
return super.push(...items.filter(this.predicate));
}
}

export default defineWorkersConfig({
test: {
include: ["test-staging/**/*.spec.ts"],
poolOptions: {
workers: {
experimental_remoteBindings: true,
wrangler: { configPath: "./wrangler.json", environment: "staging" },
},
},

// Configure the `vite-node` server used by Vitest code to import configs,
// custom pools and tests. By default, Vitest effectively applies Vite
// transforms to all files outside `node_modules`. This means by default,
// our custom pool code is transformed by Vite during development, but not
// when published, leading to possible behaviour mismatches. To fix this,
// we ensure file paths containing `packages/vitest-pool-workers/dist` are
// always "externalised", meaning they're imported directly by Node.
server: {
deps: {
// Vitest automatically adds `/^(?!.*node_modules).*\.mjs$/` as an
// `inline` RegExp: https://github.com/vitest-dev/vitest/blob/v2.1.1/packages/vitest/src/constants.ts#L9
// We'd like `packages/vitest-pool-workers/dist/pool/index.mjs` to be
// externalised though. Unfortunately, `inline`s are checked before
// `external`s, so there's no nice way we can override this. Instead,
// we prevent the extra `inline` being added in the first place.
inline: new FilteredPushArray((item: any) => {
const str = item.toString();
return str !== "/^(?!.*node_modules).*\\.mjs$/";
}),
external: [
/packages\/vitest-pool-workers\/dist/,
/packages\/wrangler\//,
],
},
},
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ class FilteredPushArray<T> extends Array<T> {
}
}

debugger;
export default defineWorkersConfig({
test: {
include: ["test/**/*.spec.ts"],
poolOptions: {
workers: {
experimental_remoteBindings: true,
Expand Down
13 changes: 12 additions & 1 deletion fixtures/vitest-pool-workers-remote-bindings/wrangler.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,16 @@
"service": "my-worker-test",
"experimental_remote": true
}
]
],
"env": {
"staging": {
"services": [
{
"binding": "MY_WORKER",
"service": "my-staging-worker-test",
"experimental_remote": true
}
]
}
}
}
5 changes: 4 additions & 1 deletion packages/vitest-pool-workers/src/pool/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,10 @@ async function parseCustomPoolOptions(

const remoteProxySessionData = options.experimental_remoteBindings
? await wrangler.experimental_maybeStartOrUpdateRemoteProxySession(
configPath,
{
path: options.wrangler.configPath,
environment: options.wrangler.environment,
},
preExistingRemoteProxySessionData ?? null
)
: null;
Expand Down
Loading
Loading