Skip to content

Commit 298c0fc

Browse files
chore: make fetches in getPlaformProxy remote bindings fixture tests more stable (#10145)
--------- Co-authored-by: Pete Bacon Darwin <[email protected]>
1 parent d827d95 commit 298c0fc

File tree

3 files changed

+153
-111
lines changed

3 files changed

+153
-111
lines changed

fixtures/get-platform-proxy-remote-bindings/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"devDependencies": {
1010
"@cloudflare/workers-tsconfig": "workspace:*",
1111
"@cloudflare/workers-types": "^4.20250803.0",
12+
"miniflare": "workspace:*",
1213
"typescript": "catalog:default",
1314
"vitest": "catalog:default",
1415
"wrangler": "workspace:*"

fixtures/get-platform-proxy-remote-bindings/tests/index.test.ts

Lines changed: 149 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ import { execSync } from "child_process";
22
import { randomUUID } from "crypto";
33
import assert from "node:assert";
44
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
5-
import { Fetcher, KVNamespace } from "@cloudflare/workers-types/experimental";
65
import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
76
import { getPlatformProxy } from "wrangler";
7+
import type { KVNamespace } from "@cloudflare/workers-types/experimental";
8+
import type { DispatchFetch, Response } from "miniflare";
9+
10+
type Fetcher = { fetch: DispatchFetch };
811

912
const auth = getAuthenticatedEnv();
1013
const execOptions = {
@@ -15,123 +18,158 @@ const remoteWorkerName = `tmp-e2e-worker-test-remote-bindings-${randomUUID().spl
1518
const remoteKvName = `tmp-e2e-remote-kv-test-remote-bindings-${randomUUID().split("-")[0]}`;
1619

1720
if (auth) {
18-
describe("getPlatformProxy - remote bindings", () => {
19-
let remoteKvId: string;
20-
beforeAll(async () => {
21-
const deployOut = execSync(
22-
`pnpm wrangler deploy remote-worker.js --name ${remoteWorkerName} --compatibility-date 2025-06-19`,
23-
execOptions
24-
);
25-
26-
if (!new RegExp(`Deployed\\s+${remoteWorkerName}\\b`).test(deployOut)) {
27-
throw new Error(`Failed to deploy ${remoteWorkerName}`);
28-
}
29-
30-
const kvAddOut = execSync(
31-
`pnpm wrangler kv namespace create ${remoteKvName}`,
32-
execOptions
33-
);
34-
35-
const createdKvRegexMatch = kvAddOut.match(/"id": "(?<id>[^"]*?)"/);
36-
const maybeRemoteKvId = createdKvRegexMatch?.groups?.["id"];
37-
assert(maybeRemoteKvId, `Failed to create remote kv ${remoteKvName}`);
38-
remoteKvId = maybeRemoteKvId;
39-
40-
execSync(
41-
`pnpm wrangler kv key put test-key remote-kv-value --namespace-id=${remoteKvId} --remote`,
42-
execOptions
43-
);
44-
45-
rmSync("./.tmp", { recursive: true, force: true });
46-
47-
mkdirSync("./.tmp");
48-
49-
writeFileSync(
50-
"./.tmp/wrangler.json",
51-
JSON.stringify(
52-
{
53-
name: "get-platform-proxy-fixture-test",
54-
compatibility_date: "2025-06-01",
55-
services: [
56-
{
57-
binding: "MY_WORKER",
58-
service: remoteWorkerName,
59-
experimental_remote: true,
60-
},
61-
],
62-
kv_namespaces: [
63-
{
64-
binding: "MY_KV",
65-
id: remoteKvId,
66-
experimental_remote: true,
67-
},
68-
],
69-
},
70-
undefined,
71-
2
72-
),
73-
"utf8"
74-
);
75-
}, 25_000);
76-
77-
afterAll(() => {
78-
execSync(`pnpm wrangler delete --name ${remoteWorkerName}`, execOptions);
79-
execSync(
80-
`pnpm wrangler kv namespace delete --namespace-id=${remoteKvId}`,
81-
execOptions
82-
);
83-
rmSync("./.tmp", { recursive: true, force: true });
84-
}, 25_000);
85-
86-
test("getPlatformProxy works with remote bindings", async () => {
87-
vi.stubEnv("CLOUDFLARE_ACCOUNT_ID", auth.CLOUDFLARE_ACCOUNT_ID);
88-
vi.stubEnv("CLOUDFLARE_API_TOKEN", auth.CLOUDFLARE_API_TOKEN);
89-
const { env, dispose } = await getPlatformProxy<{
90-
MY_WORKER: Fetcher;
91-
MY_KV: KVNamespace;
92-
}>({
93-
configPath: "./.tmp/wrangler.json",
94-
experimental: { remoteBindings: true },
21+
describe(
22+
"getPlatformProxy - remote bindings",
23+
() => {
24+
let remoteKvId: string;
25+
beforeAll(async () => {
26+
const deployOut = execSync(
27+
`pnpm wrangler deploy remote-worker.js --name ${remoteWorkerName} --compatibility-date 2025-06-19`,
28+
execOptions
29+
);
30+
31+
if (!new RegExp(`Deployed\\s+${remoteWorkerName}\\b`).test(deployOut)) {
32+
throw new Error(`Failed to deploy ${remoteWorkerName}`);
33+
}
34+
35+
const kvAddOut = execSync(
36+
`pnpm wrangler kv namespace create ${remoteKvName}`,
37+
execOptions
38+
);
39+
40+
const createdKvRegexMatch = kvAddOut.match(/"id": "(?<id>[^"]*?)"/);
41+
const maybeRemoteKvId = createdKvRegexMatch?.groups?.["id"];
42+
assert(maybeRemoteKvId, `Failed to create remote kv ${remoteKvName}`);
43+
remoteKvId = maybeRemoteKvId;
44+
45+
execSync(
46+
`pnpm wrangler kv key put test-key remote-kv-value --namespace-id=${remoteKvId} --remote`,
47+
execOptions
48+
);
49+
50+
rmSync("./.tmp", { recursive: true, force: true });
51+
52+
mkdirSync("./.tmp");
53+
54+
writeFileSync(
55+
"./.tmp/wrangler.json",
56+
JSON.stringify(
57+
{
58+
name: "get-platform-proxy-fixture-test",
59+
compatibility_date: "2025-06-01",
60+
services: [
61+
{
62+
binding: "MY_WORKER",
63+
service: remoteWorkerName,
64+
experimental_remote: true,
65+
},
66+
],
67+
kv_namespaces: [
68+
{
69+
binding: "MY_KV",
70+
id: remoteKvId,
71+
experimental_remote: true,
72+
},
73+
],
74+
},
75+
undefined,
76+
2
77+
),
78+
"utf8"
79+
);
80+
}, 25_000);
81+
82+
afterAll(() => {
83+
execSync(
84+
`pnpm wrangler delete --name ${remoteWorkerName}`,
85+
execOptions
86+
);
87+
execSync(
88+
`pnpm wrangler kv namespace delete --namespace-id=${remoteKvId}`,
89+
execOptions
90+
);
91+
rmSync("./.tmp", { recursive: true, force: true });
92+
}, 25_000);
93+
94+
test("getPlatformProxy works with remote bindings", async () => {
95+
vi.stubEnv("CLOUDFLARE_ACCOUNT_ID", auth.CLOUDFLARE_ACCOUNT_ID);
96+
vi.stubEnv("CLOUDFLARE_API_TOKEN", auth.CLOUDFLARE_API_TOKEN);
97+
98+
const { env, dispose } = await getPlatformProxy<{
99+
MY_WORKER: Fetcher;
100+
MY_KV: KVNamespace;
101+
}>({
102+
configPath: "./.tmp/wrangler.json",
103+
experimental: { remoteBindings: true },
104+
});
105+
106+
const response = await fetchFromWorker(env.MY_WORKER, "OK");
107+
const workerText = await response?.text();
108+
expect(workerText).toEqual(
109+
"Hello from a remote Worker part of the getPlatformProxy remote bindings fixture!"
110+
);
111+
112+
const kvValue = await env.MY_KV.get("test-key");
113+
expect(kvValue).toEqual("remote-kv-value");
114+
115+
await dispose();
95116
});
96117

97-
const workerText = await (
98-
await env.MY_WORKER.fetch("http://example.com")
99-
).text();
100-
expect(workerText).toEqual(
101-
"Hello from a remote Worker part of the getPlatformProxy remote bindings fixture!"
102-
);
103-
104-
const kvValue = await env.MY_KV.get("test-key");
105-
expect(kvValue).toEqual("remote-kv-value");
106-
107-
await dispose();
108-
});
109-
110-
test("getPlatformProxy does not work with remote bindings if the experimental remoteBindings flag is not turned on", async () => {
111-
const { env, dispose } = await getPlatformProxy<{
112-
MY_WORKER: Fetcher;
113-
MY_KV: KVNamespace;
114-
}>({
115-
configPath: "./.tmp/wrangler.json",
118+
test("getPlatformProxy does not work with remote bindings if the experimental remoteBindings flag is not turned on", async () => {
119+
const { env, dispose } = await getPlatformProxy<{
120+
MY_WORKER: Fetcher;
121+
MY_KV: KVNamespace;
122+
}>({
123+
configPath: "./.tmp/wrangler.json",
124+
});
125+
126+
const response = await fetchFromWorker(
127+
env.MY_WORKER,
128+
"Service Unavailable"
129+
);
130+
const workerText = await response?.text();
131+
expect(workerText).toEqual(
132+
`[wrangler] Couldn\'t find \`wrangler dev\` session for service "${remoteWorkerName}" to proxy to`
133+
);
134+
135+
const kvValue = await env.MY_KV.get("test-key");
136+
expect(kvValue).toEqual(null);
137+
138+
await dispose();
116139
});
117-
118-
const workerText = await (
119-
await env.MY_WORKER.fetch("http://example.com")
120-
).text();
121-
expect(workerText).toEqual(
122-
`[wrangler] Couldn\'t find \`wrangler dev\` session for service "${remoteWorkerName}" to proxy to`
123-
);
124-
125-
const kvValue = await env.MY_KV.get("test-key");
126-
expect(kvValue).toEqual(null);
127-
128-
await dispose();
129-
});
130-
});
140+
},
141+
{ timeout: 50_000 }
142+
);
131143
} else {
132144
test.skip("getPlatformProxy - remote bindings (no auth credentials)");
133145
}
134146

147+
/**
148+
* Tries to fetch from a worker multiple times until a response is returned which matches a specified
149+
* statusText. Each fetch has a timeout signal making sure that it can't simply get stuck.
150+
*
151+
* This utility is used, instead of directly fetching from the Worker in order to prevent flakiness.
152+
*
153+
* @param worker The Worker to fetch from.
154+
* @param expectedStatusText The response's expected statusText.
155+
* @returns The successful Worker's response or null if no such response was obtained.
156+
*/
157+
async function fetchFromWorker(
158+
worker: Fetcher,
159+
expectedStatusText: string
160+
): Promise<Response> {
161+
return vi.waitFor(
162+
async () => {
163+
const response = await worker.fetch("http://example.com", {
164+
signal: AbortSignal.timeout(5_000),
165+
});
166+
expect(response.statusText).toEqual(expectedStatusText);
167+
return response;
168+
},
169+
{ timeout: 30_000, interval: 500 }
170+
);
171+
}
172+
135173
/**
136174
* Gets an env object containing Cloudflare credentials or undefined if not authenticated.
137175
*

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)