Skip to content

Commit 438c146

Browse files
Improve our CI and local failures (#9932)
* reduce flakes on worker-app fixture tests * Cleanup remote-mode bindings fixtures so that they work nicely locally * Add GITHUB token for begit to clone the solid-start template repo in the c3 e2e tests
1 parent b46386c commit 438c146

File tree

6 files changed

+229
-159
lines changed

6 files changed

+229
-159
lines changed

.github/workflows/c3-e2e.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ jobs:
8787
E2E_TEST_PM: ${{ matrix.pm.name }}
8888
E2E_TEST_PM_VERSION: ${{ matrix.pm.version }}
8989
CI_OS: ${{ runner.os }}
90+
GITHUB_TOKEN: ${{ github.token }} # Needed for begit to clone the repo in the e2e tests for solid-start
9091

9192
- name: Upload Logs
9293
uses: actions/upload-artifact@v4
Lines changed: 148 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,144 +1,159 @@
11
import { execSync } from "child_process";
22
import { randomUUID } from "crypto";
3+
import assert from "node:assert";
34
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
45
import { Fetcher, KVNamespace } from "@cloudflare/workers-types/experimental";
5-
import { afterAll, beforeAll, describe, expect, test } from "vitest";
6+
import { afterAll, beforeAll, describe, expect, test, vi } from "vitest";
67
import { getPlatformProxy } from "wrangler";
78

8-
if (
9-
!process.env.TEST_CLOUDFLARE_API_TOKEN ||
10-
!process.env.TEST_CLOUDFLARE_ACCOUNT_ID
11-
) {
12-
console.warn("No credentials provided, skipping test...");
13-
process.exit(0);
14-
}
15-
16-
describe("getPlatformProxy - remote bindings", () => {
17-
const remoteWorkerName = `tmp-e2e-worker-test-${randomUUID().split("-")[0]}`;
18-
const remoteKvName = `tmp-e2e-remote-kv-test-${randomUUID().split("-")[0]}`;
19-
let remoteKvId = "";
20-
21-
beforeAll(async () => {
22-
// Note: ideally we pass the auth data to `getPlatformProxy`, that currently is not
23-
// possible (DEVX-1857) so we need to make sure that the CLOUDFLARE_ACCOUNT_ID
24-
// and CLOUDFLARE_API_TOKEN env variables are set so that `getPlatformProxy`
25-
// can establish the remote proxy connection
26-
process.env.CLOUDFLARE_ACCOUNT_ID = process.env.TEST_CLOUDFLARE_ACCOUNT_ID;
27-
process.env.CLOUDFLARE_API_TOKEN = process.env.TEST_CLOUDFLARE_API_TOKEN;
28-
29-
const deployOut = execSync(
30-
`pnpm dlx wrangler deploy remote-worker.js --name ${remoteWorkerName} --compatibility-date 2025-06-19`,
31-
{
32-
stdio: "pipe",
9+
const auth = getAuthenticatedEnv();
10+
const execOptions = {
11+
encoding: "utf8",
12+
env: { ...process.env, ...auth },
13+
} as const;
14+
const remoteWorkerName = `tmp-e2e-worker-test-remote-bindings-${randomUUID().split("-")[0]}`;
15+
const remoteKvName = `tmp-e2e-remote-kv-test-remote-bindings-${randomUUID().split("-")[0]}`;
16+
17+
if (auth) {
18+
describe("getPlatformProxy - remote bindings", () => {
19+
let remoteKvId: string;
20+
beforeAll(async () => {
21+
const deployOut = execSync(
22+
`pnpm dlx 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}`);
3328
}
34-
);
35-
36-
if (
37-
!new RegExp(`Deployed\\s+${remoteWorkerName}\\b`).test(`${deployOut}`)
38-
) {
39-
throw new Error(`Failed to deploy ${remoteWorkerName}`);
40-
}
41-
42-
const kvAddOut = execSync(
43-
`pnpm dlx wrangler kv namespace create ${remoteKvName}`,
44-
{
45-
stdio: "pipe",
46-
}
47-
);
48-
49-
const createdKvRegexMatch = `${kvAddOut}`.match(/"id": "(?<id>[^"]*?)"/);
50-
const maybeRemoteKvId = createdKvRegexMatch?.groups?.["id"];
51-
52-
if (!maybeRemoteKvId) {
53-
throw new Error(`Failed to create remote kv ${remoteKvName}`);
54-
}
55-
56-
remoteKvId = maybeRemoteKvId;
57-
58-
execSync(
59-
`pnpm dlx wrangler kv key put test-key remote-kv-value --namespace-id=${remoteKvId} --remote`
60-
);
61-
62-
rmSync("./.tmp", { recursive: true, force: true });
63-
64-
mkdirSync("./.tmp");
65-
66-
writeFileSync(
67-
"./.tmp/wrangler.json",
68-
JSON.stringify(
69-
{
70-
name: "get-platform-proxy-fixture-test",
71-
compatibility_date: "2025-06-01",
72-
services: [
73-
{
74-
binding: "MY_WORKER",
75-
service: remoteWorkerName,
76-
experimental_remote: true,
77-
},
78-
],
79-
kv_namespaces: [
80-
{
81-
binding: "MY_KV",
82-
id: remoteKvId,
83-
experimental_remote: true,
84-
},
85-
],
86-
},
87-
undefined,
88-
2
89-
),
90-
"utf8"
91-
);
92-
}, 25_000);
93-
94-
afterAll(async () => {
95-
execSync(`pnpm dlx wrangler delete --name ${remoteWorkerName}`);
96-
execSync(
97-
`pnpm dlx wrangler kv namespace delete --namespace-id=${remoteKvId}`
98-
);
99-
rmSync("./.tmp", { recursive: true, force: true });
100-
}, 25_000);
101-
102-
test("getPlatformProxy works with remote bindings", async () => {
103-
const { env, dispose } = await getPlatformProxy<{
104-
MY_WORKER: Fetcher;
105-
MY_KV: KVNamespace;
106-
}>({
107-
configPath: "./.tmp/wrangler.json",
108-
experimental: { remoteBindings: true },
109-
});
110-
111-
const workerText = await (
112-
await env.MY_WORKER.fetch("http://example.com")
113-
).text();
114-
expect(workerText).toEqual(
115-
"Hello from a remote Worker part of the getPlatformProxy remote bindings fixture!"
116-
);
117-
118-
const kvValue = await env.MY_KV.get("test-key");
119-
expect(kvValue).toEqual("remote-kv-value");
120-
121-
await dispose();
122-
});
12329

124-
test("getPlatformProxy does not work with remote bindings if the experimental remoteBindings flag is not turned on", async () => {
125-
const { env, dispose } = await getPlatformProxy<{
126-
MY_WORKER: Fetcher;
127-
MY_KV: KVNamespace;
128-
}>({
129-
configPath: "./.tmp/wrangler.json",
30+
const kvAddOut = execSync(
31+
`pnpm dlx 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 dlx 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(
79+
`pnpm dlx wrangler delete --name ${remoteWorkerName}`,
80+
execOptions
81+
);
82+
execSync(
83+
`pnpm dlx wrangler kv namespace delete --namespace-id=${remoteKvId}`,
84+
execOptions
85+
);
86+
rmSync("./.tmp", { recursive: true, force: true });
87+
}, 25_000);
88+
89+
test("getPlatformProxy works with remote bindings", async () => {
90+
vi.stubEnv("CLOUDFLARE_ACCOUNT_ID", auth.CLOUDFLARE_ACCOUNT_ID);
91+
vi.stubEnv("CLOUDFLARE_API_TOKEN", auth.CLOUDFLARE_API_TOKEN);
92+
const { env, dispose } = await getPlatformProxy<{
93+
MY_WORKER: Fetcher;
94+
MY_KV: KVNamespace;
95+
}>({
96+
configPath: "./.tmp/wrangler.json",
97+
experimental: { remoteBindings: true },
98+
});
99+
100+
const workerText = await (
101+
await env.MY_WORKER.fetch("http://example.com")
102+
).text();
103+
expect(workerText).toEqual(
104+
"Hello from a remote Worker part of the getPlatformProxy remote bindings fixture!"
105+
);
106+
107+
const kvValue = await env.MY_KV.get("test-key");
108+
expect(kvValue).toEqual("remote-kv-value");
109+
110+
await dispose();
130111
});
131112

132-
const workerText = await (
133-
await env.MY_WORKER.fetch("http://example.com")
134-
).text();
135-
expect(workerText).toEqual(
136-
`[wrangler] Couldn\'t find \`wrangler dev\` session for service "${remoteWorkerName}" to proxy to`
137-
);
138-
139-
const kvValue = await env.MY_KV.get("test-key");
140-
expect(kvValue).toEqual(null);
141-
142-
await dispose();
113+
test("getPlatformProxy does not work with remote bindings if the experimental remoteBindings flag is not turned on", async () => {
114+
const { env, dispose } = await getPlatformProxy<{
115+
MY_WORKER: Fetcher;
116+
MY_KV: KVNamespace;
117+
}>({
118+
configPath: "./.tmp/wrangler.json",
119+
});
120+
121+
const workerText = await (
122+
await env.MY_WORKER.fetch("http://example.com")
123+
).text();
124+
expect(workerText).toEqual(
125+
`[wrangler] Couldn\'t find \`wrangler dev\` session for service "${remoteWorkerName}" to proxy to`
126+
);
127+
128+
const kvValue = await env.MY_KV.get("test-key");
129+
expect(kvValue).toEqual(null);
130+
131+
await dispose();
132+
});
143133
});
144-
});
134+
} else {
135+
test.skip("getPlatformProxy - remote bindings (no auth credentials)");
136+
}
137+
138+
/**
139+
* Gets an env object containing Cloudflare credentials or undefined if not authenticated.
140+
*
141+
* In the Github actions we convert the TEST_CLOUDFLARE_ACCOUNT_ID and TEST_CLOUDFLARE_API_TOKEN env variables.
142+
* In local development we can rely on CLOUDFLARE_ACCOUNT_ID and CLOUDFLARE_API_TOKEN env variables directly.
143+
*/
144+
function getAuthenticatedEnv() {
145+
const CLOUDFLARE_ACCOUNT_ID =
146+
process.env.TEST_CLOUDFLARE_ACCOUNT_ID || process.env.CLOUDFLARE_ACCOUNT_ID;
147+
const CLOUDFLARE_API_TOKEN =
148+
process.env.TEST_CLOUDFLARE_API_TOKEN || process.env.CLOUDFLARE_API_TOKEN;
149+
150+
if (CLOUDFLARE_ACCOUNT_ID && CLOUDFLARE_API_TOKEN) {
151+
return {
152+
CLOUDFLARE_API_TOKEN,
153+
CLOUDFLARE_ACCOUNT_ID,
154+
};
155+
}
156+
console.warn(
157+
"Skipping vitest-pool-workers remote bindings tests because the environment is not authenticated with Cloudflare."
158+
);
159+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "http://turbo.build/schema.json",
3+
"extends": ["//"],
4+
"tasks": {
5+
"test:ci": {
6+
"env": [
7+
"VITEST",
8+
"NODE_DEBUG",
9+
"MINIFLARE_WORKERD_PATH",
10+
"WRANGLER",
11+
"WRANGLER_IMPORT",
12+
"MINIFLARE_IMPORT",
13+
"CLOUDFLARE_ACCOUNT_ID",
14+
"CLOUDFLARE_API_TOKEN",
15+
"TEST_CLOUDFLARE_ACCOUNT_ID",
16+
"TEST_CLOUDFLARE_API_TOKEN",
17+
"WRANGLER_E2E_TEST_FILE"
18+
]
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)