Skip to content

Commit bb14da5

Browse files
backport: improve e2e testing approach to reduce flakiness (#10309)
* backport: improve e2e testing approach from main branch - Add retry mechanism for failed tests - Use environment variable isolation with WRANGLER_E2E_TEST_FILE - Implement glob-based test file discovery - Add better error handling and reporting - Include GitHub Actions console grouping This backports the improved e2e testing approach from main branch to reduce flakiness in e2e tests on v3-maintenance branch. Co-Authored-By: [email protected] <[email protected]> * add glob dependency to tools package The improved e2e runner imports glob directly, so it needs to be added as a dependency to the tools package.json. Co-Authored-By: [email protected] <[email protected]> * fix: update pnpm-lock.yaml after adding glob dependency This resolves the CI failure: ERR_PNPM_OUTDATED_LOCKFILE Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date with tools/package.json Co-Authored-By: [email protected] <[email protected]> * fix: backport turbo cache configuration to resolve E2E test timeouts - Add globalPassThroughEnv to root turbo.json with essential environment variables - Update packages/wrangler/turbo.json with WRANGLER_E2E_TEST_FILE and other missing env vars - Add passThroughEnv array to build task with comprehensive environment variable list - Update build inputs to use $TURBO_DEFAULT$ pattern from main branch - Add create-cloudflare#build dependency to test:e2e task These changes ensure the backported e2e runner can properly utilize turbo cache by recognizing the WRANGLER_E2E_TEST_FILE environment variable and other essential configuration, preventing cache misses that cause test timeouts. Co-Authored-By: [email protected] <[email protected]> * fix: remove non-existent create-cloudflare#build dependency from test:e2e task The create-cloudflare#build dependency doesn't exist in v3-maintenance branch, causing E2E tests to fail with 'Could not find package create-cloudflare from task create-cloudflare#build'. This fix removes the problematic dependency while keeping the essential WRANGLER_E2E_TEST_FILE environment variable that enables proper turbo caching for the backported e2e runner. Co-Authored-By: [email protected] <[email protected]> * fix: add dotenv prefix to test:e2e:wrangler script for consistent env handling This ensures the e2e test runner uses the same environment variable handling pattern as other turbo tasks, optimizing turbo cache behavior. Co-Authored-By: [email protected] <[email protected]> * fix: revert dotenv prefix from test:e2e:wrangler to resolve env var passing issues The dotenv prefix was causing the WRANGLER environment variable to not be passed through properly, causing E2E test validation failures. The core turbo cache optimizations (env var configuration, dependency fixes) remain in place and provide the intended performance improvements. Co-Authored-By: [email protected] <[email protected]> * fix: add missing WRANGLER_E2E_TEST_FILE support to vitest config Backport the vitest configuration from main branch to properly handle the WRANGLER_E2E_TEST_FILE environment variable for individual test file execution. This completes the e2e testing improvements backport. - Add retry: 1 configuration for automatic test retries - Add dynamic include pattern using WRANGLER_E2E_TEST_FILE env var - Fixes E2E test failures by enabling proper test file filtering Co-Authored-By: [email protected] <[email protected]> --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: [email protected] <[email protected]>
1 parent 951baa5 commit bb14da5

File tree

6 files changed

+123
-79
lines changed

6 files changed

+123
-79
lines changed

packages/wrangler/e2e/vitest.config.mts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ export default defineConfig({
99
singleThread: true,
1010
},
1111
},
12-
include: ["e2e/**/*.test.ts"],
12+
retry: 1,
13+
// eslint-disable-next-line turbo/no-undeclared-env-vars
14+
include: [process.env.WRANGLER_E2E_TEST_FILE || "e2e/**/*.test.ts"],
1315
// eslint-disable-next-line turbo/no-undeclared-env-vars
1416
outputFile: process.env.TEST_REPORT_PATH ?? ".e2e-test-report/index.html",
1517
globalSetup: path.resolve(__dirname, "./validate-environment.ts"),

packages/wrangler/turbo.json

Lines changed: 44 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -3,73 +3,76 @@
33
"extends": ["//"],
44
"tasks": {
55
"build": {
6-
"inputs": [
7-
"!*/**/__tests__/**",
8-
"!*/**/.wrangler/**",
9-
"bin/**",
10-
"src/**",
11-
"scripts/**",
12-
"templates/**",
13-
"*.json",
14-
"*.js",
15-
"*.ts"
16-
],
6+
"inputs": ["$TURBO_DEFAULT$", "!**/__tests__/**", "!e2e/**"],
177
"outputs": [
188
"miniflare-dist/**",
199
"emitted-types/**",
2010
"wrangler-dist/**",
2111
"config-schema.json"
2212
],
2313
"env": [
24-
"NODE_EXTRA_CA_CERTS",
25-
"CLOUDFLARE_ACCOUNT_ID",
26-
"SOURCEMAPS",
27-
"NODE_ENV",
28-
"SPARROW_SOURCE_KEY",
2914
"ALGOLIA_APP_ID",
3015
"ALGOLIA_PUBLIC_KEY",
31-
"CLOUDFLARE_API_TOKEN",
32-
"CLOUDFLARE_ACCOUNT_ID",
33-
"WRANGLER_AUTH_DOMAIN",
34-
"PATH",
35-
"WRANGLER_LOG",
36-
"EXPERIMENTAL_MIDDLEWARE",
37-
"FORMAT_WRANGLER_ERRORS",
16+
"NODE_ENV",
17+
"SOURCEMAPS",
18+
"SPARROW_SOURCE_KEY",
19+
"SENTRY_DSN",
20+
"WRANGLER_PRERELEASE_LABEL"
21+
],
22+
"passThroughEnv": [
23+
"CF_PAGES_UPLOAD_JWT",
3824
"CF_PAGES",
39-
"WORKERS_CI",
4025
"CI",
41-
"CF_PAGES_UPLOAD_JWT",
26+
"CLOUDFLARE_ACCOUNT_ID",
27+
"CLOUDFLARE_API_TOKEN",
28+
"CUSTOM_BUILD_VAR",
4229
"EXPERIMENTAL_MIDDLEWARE",
30+
"FORMAT_WRANGLER_ERRORS",
31+
"http_proxy",
32+
"HTTP_PROXY",
33+
"https_proxy",
34+
"HTTPS_PROXY",
35+
"HYPERDRIVE_DATABASE_URL",
36+
"WRANGLER_DOCKER_BIN",
37+
"WRANGLER_DOCKER_HOST",
38+
"LC_ALL",
4339
"NO_D1_WARNING",
4440
"NO_HYPERDRIVE_WARNING",
45-
"WRANGLER",
46-
"WRANGLER_IMPORT",
47-
"CUSTOM_BUILD_VAR",
41+
"PATH",
4842
"PWD",
49-
"LC_ALL",
50-
"WRANGLER_SEND_METRICS",
51-
"https_proxy",
52-
"HTTPS_PROXY",
53-
"http_proxy",
54-
"HTTP_PROXY",
55-
"CI_OS",
56-
"SENTRY_DSN",
5743
"SYSTEMROOT",
5844
"TZ",
45+
"WORKERS_CI",
46+
"WRANGLER_API_ENVIRONMENT",
47+
"WRANGLER_AUTH_DOMAIN",
48+
"WRANGLER_D1_EXTRA_LOCATION_CHOICES",
5949
"WRANGLER_DISABLE_EXPERIMENTAL_WARNING",
6050
"WRANGLER_DISABLE_REQUEST_BODY_DRAINING",
51+
"WRANGLER_LOG",
52+
"WRANGLER_SEND_METRICS",
6153
"WRANGLER_WORKER_REGISTRY_PORT",
62-
"WRANGLER_API_ENVIRONMENT",
63-
"HYPERDRIVE_DATABASE_URL"
54+
"DOCKER_HOST",
55+
"WRANGLER_DOCKER_HOST"
6456
]
6557
},
6658
"test:ci": {
67-
"inputs": ["!*/**/.wrangler/**", "**/__tests__/**"],
68-
"dependsOn": ["build"]
59+
"dependsOn": ["build"],
60+
"env": ["VITEST", "NODE_DEBUG", "MINIFLARE_WORKERD_PATH"]
6961
},
7062
"test:e2e": {
7163
"inputs": ["e2e/**"],
72-
"dependsOn": ["build"]
64+
"dependsOn": ["build"],
65+
"env": [
66+
"VITEST",
67+
"NODE_DEBUG",
68+
"MINIFLARE_WORKERD_PATH",
69+
"WRANGLER",
70+
"WRANGLER_IMPORT",
71+
"MINIFLARE_IMPORT",
72+
"CLOUDFLARE_ACCOUNT_ID",
73+
"CLOUDFLARE_API_TOKEN",
74+
"WRANGLER_E2E_TEST_FILE"
75+
]
7376
}
7477
}
7578
}

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.

tools/e2e/runIndividualE2EFiles.ts

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,68 @@
1-
/**
2-
* Turbo only supports caching on the individual task level, but for Wrangler's
3-
* e2e tests we want to support caching on a more granular basis—at the file level.
4-
*
5-
* As such, we run the `test:e2e` turbo task multiple times—once per e2e test file
6-
* with different arguments, ensuring that each file's tests can be cached individually.
7-
*
8-
* The intended flow here is that CI will run this file, which will trigger turbo to run
9-
* an individual task for each Wrangler e2e test file, using `execSync`.
10-
*/
1+
import assert from "assert";
112
import { execSync } from "child_process";
12-
import { readdirSync } from "fs";
3+
import { statSync } from "fs";
4+
import path from "path";
5+
import { globIterateSync } from "glob";
6+
import type { ExecSyncOptionsWithBufferEncoding } from "child_process";
137

14-
// Get a list of e2e test files, each of which should have an associated script
15-
const e2eTests = readdirSync("packages/wrangler/e2e");
8+
// Turbo only supports caching on the individual task level, but for Wrangler's
9+
// e2e tests we want to support caching on a more granular basis - at the file level.
10+
//
11+
// As such, we run the `test:e2e` turbo task multiple times — once per e2e test file so that each file's tests can be cached individually.
12+
// We use the `WRANGLER_E2E_TEST_FILE` environment variable to pass the specific test file to the e2e test runner so that it reuses the cached build tasks.
13+
// If you use a command line argument to do this turbo will create a different cache key for the build tasks.
14+
//
15+
// The intended flow here is that CI will run this file, which will trigger turbo to run
16+
// an individual task for each Wrangler e2e test file, using `execSync`.
17+
//
18+
// Any params after a `--` will be passed to the Vitest runner, so you can use this to configure the test run.
19+
// For example to update the snapshots for all Wrangler e2e tests, you can run:
20+
//
21+
// ```bash
22+
// pnpm test:e2e:wrangler -- -u
23+
// ```
1624

17-
const tasks = new Set<string>();
25+
const extraParamsIndex = process.argv.indexOf("--");
26+
const extraParams =
27+
extraParamsIndex === -1 ? [] : process.argv.slice(extraParamsIndex);
28+
const command =
29+
`pnpm test:e2e --log-order=stream --output-logs=new-only --summarize --filter wrangler ` +
30+
extraParams.join(" ");
1831

19-
for (const file of e2eTests) {
20-
// Ignore other files in the e2e directory (the README, for instance)
21-
if (file.endsWith(".test.ts")) {
22-
tasks.add(
23-
`pnpm test:e2e --log-order=stream --output-logs=new-only --summarize --filter wrangler --concurrency 1 -- run ./e2e/${file}`
24-
);
32+
const failed: string[] = [];
33+
34+
const wranglerPath = path.join(__dirname, "../../packages/wrangler");
35+
assert(statSync(wranglerPath).isDirectory());
36+
37+
for (const testFile of globIterateSync("e2e/**/*.test.ts", {
38+
cwd: wranglerPath,
39+
// Return `/` delimited paths, even on Windows.
40+
posix: true,
41+
})) {
42+
const options: ExecSyncOptionsWithBufferEncoding = {
43+
stdio: "inherit",
44+
env: { ...process.env, WRANGLER_E2E_TEST_FILE: testFile },
45+
};
46+
47+
console.log(`::group::Testing: ${testFile}`);
48+
49+
try {
50+
execSync(command, options);
51+
} catch {
52+
console.error("Task failed - retrying");
53+
try {
54+
execSync(command, options);
55+
} catch {
56+
console.error("Still failed, moving on");
57+
failed.push(testFile);
58+
}
2559
}
60+
console.log("::endgroup::");
2661
}
2762

28-
for (const task of tasks.values()) {
29-
execSync(task, {
30-
stdio: "inherit",
31-
});
63+
if (failed.length > 0) {
64+
throw new Error(
65+
"At least one task failed (even on retry):" +
66+
failed.map((file) => `\n - ${file}`)
67+
);
3268
}

tools/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@typescript-eslint/eslint-plugin": "^6.9.0",
1515
"@typescript-eslint/parser": "^6.9.0",
1616
"find-up": "^6.3.0",
17+
"glob": "^10.4.5",
1718
"ts-dedent": "^2.2.0",
1819
"undici": "catalog:default"
1920
}

turbo.json

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
"remoteCache": {
44
"signature": true
55
},
6-
"globalEnv": [
6+
"globalEnv": ["CI_OS", "NODE_VERSION"],
7+
"globalPassThroughEnv": [
8+
"NODE_EXTRA_CA_CERTS",
79
"CI",
8-
"CI_OS",
9-
"NODE_VERSION",
10-
"VITEST",
11-
"NODE_DEBUG",
12-
"NODE_EXTRA_CA_CERTS"
10+
"VSCODE_INSPECTOR_OPTIONS",
11+
"WRANGLER_LOG_PATH",
12+
"TEST_REPORT_PATH",
13+
"CLOUDFLARE_CONTAINER_REGISTRY",
14+
"DOCKER_HOST",
15+
"WRANGLER_DOCKER_HOST"
1316
],
1417
"tasks": {
1518
"dev": {
@@ -27,24 +30,20 @@
2730
"persistent": true,
2831
"cache": false
2932
},
30-
"topological": {
31-
"dependsOn": ["^topological"]
32-
},
3333
"check:lint": {
34-
"dependsOn": ["topological"]
34+
"dependsOn": ["^check:lint"]
3535
},
3636
"check:type": {
37-
"dependsOn": ["topological"]
37+
"dependsOn": ["build"]
3838
},
3939
"type:tests": {
40-
"dependsOn": ["topological"]
40+
"dependsOn": ["build"]
4141
},
4242
"test:ci": {
4343
"dependsOn": ["build"],
4444
"outputLogs": "new-only"
4545
},
4646
"test:e2e": {
47-
"env": ["WRANGLER", "CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_TOKEN"],
4847
"dependsOn": ["build"],
4948
"outputLogs": "new-only"
5049
},

0 commit comments

Comments
 (0)