Repository navigation
test: make the generator and dev server tests stable - #4885
Conversation
The `create-webpack-app` tests install real packages, and a registry hiccup made npm fail, which the tests only reported as a missing line in stdout. npm now prefers its cache and retries requests more, without the audit, fund and update-notifier requests, and a failed install fails the test with npm's error. The dev server tests took ports from the ephemeral range, where outgoing connections or another Jest worker could take them before the server listened. Each worker now takes ports from its own range below the ephemeral ones. Claude-Session: https://claude.ai/code/session_013FhutRFjuQemBzekJMYcqL
More retries made a failing install outlast the test timeout, which then hid npm's error. Claude-Session: https://claude.ai/code/session_013FhutRFjuQemBzekJMYcqL
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4885 +/- ##
==========================================
+ Coverage 94.85% 94.87% +0.01%
==========================================
Files 14 14
Lines 5637 5637
Branches 846 846
==========================================
+ Hits 5347 5348 +1
+ Misses 289 288 -1
Partials 1 1 see 1 file with indirect coverage changes Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
|
This PR is packaged and the instant preview is available (b32b0c9). Install it locally:
npm i -D create-webpack-app@https://pkg.pr.new/create-webpack-app@b32b0c9 webpack-cli@https://pkg.pr.new/webpack-cli@b32b0c9
yarn add -D create-webpack-app@https://pkg.pr.new/create-webpack-app@b32b0c9 webpack-cli@https://pkg.pr.new/webpack-cli@b32b0c9
pnpm add -D create-webpack-app@https://pkg.pr.new/create-webpack-app@b32b0c9 webpack-cli@https://pkg.pr.new/webpack-cli@b32b0c9 |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the
Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review.
|
There was a problem hiding this comment.
Actionable comments posted: 2

Review info
-
Run configuration-
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Organization UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
4a2bafbc-f35f-440b-b65c-cfebf31cd929
Files selected for processing: 6-
test/create-webpack-app/test.utils.jstest/serve/basic/multi-dev-server.config.jstest/serve/basic/serve-basic.test.jstest/serve/serve-variable/serve-variable.test.jstest/serve/with-custom-port/serve-custom-config.test.jstest/utils/test-utils.js
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.
-
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

Minor · Cap maxWorkers at 24 so worker IDs 1 and 25 cannot share a port range. · test-utils.js:413-418
test/utils/test-utils.js:413-418
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winCap
maxWorkersat 24 so worker IDs 1 and 25 cannot share a port range.
getFreePort()mapsJEST_WORKER_IDwith% 24, so worker 25 uses the same range as worker 1 (20000–20499). The parent mapping(workerId - 1) * 500gave each worker a distinct range through worker 25.Two workers in one run can call
getFreePort()at overlapping times. The helper returns a port number and does not reserve it. If worker 1 has not started its dev server yet, worker 25 can receive the same port. The second dev server then fails withEADDRINUSE.This requires at least 25 concurrent workers.
jest.config.jsdoes not setmaxWorkers, so the default worker count applies. Runs with fewer than 25 workers are not affected. An explicit-wor--maxWorkersvalue overrides the config setting.Setting
maxWorkersto 24 keeps worker IDs in the range 1–24, so the modulo never wraps in a default run.Suggested fix
module.exports = { testEnvironment: "node", + maxWorkers: 24, coverageProvider: "v8",

Review info
-
Run configuration-
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Organization UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
0b8b75ad-7338-450c-92d0-659108955100
Files selected for processing: 1-
test/utils/test-utils.js
Files skipped from review as they are similar to previous changes: 1-
- test/utils/test-utils.js
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
-
|
@coderabbitai the finding outside the diff (worker 25 sharing worker 1's port range) is fixed in 9bbf4a6. I shrank each range instead of capping Generated by Claude Code |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

Minor · Check the exit status when ENABLE_PIPE=1. · test.utils.js:27-33
test/create-webpack-app/test.utils.js:27-33
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winCheck the exit status when
ENABLE_PIPE=1.When
ENABLE_PIPE=1,createProcessuses inherited stdio andreject: false. The create-webpack-app install can exit with code 2, butcheckInstallonly checks capturedstderr, so it returns the failed result without reporting the install error.Check the nonzero exit status, while preserving the existing stderr check.
Suggested fix
- * @template {{ stderr: string }} T + * @template {{ stderr?: string, exitCode?: number }} T ... const checkInstall = (result) => { - if (result.stderr && result.stderr.includes("Error occurred while installing packages")) { - throw new Error(`Installing packages failed:\n${result.stderr}`); + const failedExit = + typeof result.exitCode === "number" && result.exitCode !== 0; + const failedInstall = + result.stderr?.includes("Error occurred while installing packages") ?? false; + + if (failedExit || failedInstall) { + const details = result.stderr ?? `Process exited with code ${result.exitCode}`; + throw new Error(`Installing packages failed:\n${details}`); }

Review info
-
Run configuration-
- Source mode: Auto
- Repository: Unavailable
- Branch: Unavailable
- File: No configuration file from this repository applied
- Commit: Unavailable
- Layers: Organization UI
- Review profile: CHILL
- Plan: Advanced
- Run ID:
aea60134-6702-4b04-bac1-bdf7a50f4f66
Files selected for processing: 1-
test/utils/test-utils.js
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.
-
|
@coderabbitai the The other remaining port-collision risk is the cross-run one. I answered that on its thread: CI runs one Jest process per job. Generated by Claude Code |
|
Tip For best results, initiate chat on the files or code changes. @alexander-akait You're right. In The cross-run port-collision concern does not apply to the CI setup you described, with one Jest process per job. No change is needed for either concern. You are interacting with an AI system. |
|
Tip For best results, initiate chat on the files or code changes. @alexander-akait Thanks for fixing this in If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! You are interacting with an AI system. |
On Windows, `envinfo` starts the browsers themselves to get their versions, which can hang, e.g. the `info` tests time out on Windows CI runners. Claude-Session: https://claude.ai/code/session_013FhutRFjuQemBzekJMYcqL
With `prefer-offline`, npm used cached metadata that lacked a version a freshly fetched package depended on, and the install failed with ETARGET (`@babel/generator@^8.0.10`) on Windows CI. Also add a changeset for not detecting browsers in `webpack info` on Windows. Claude-Session: https://claude.ai/code/session_013FhutRFjuQemBzekJMYcqL
|
I dont think we need a changeset for test changes |
|
Agreed. The changeset wasn't for the test changes. It was for the Generated by Claude Code |
The `info` tests time out on Windows only at random, so keep detecting browsers there. Claude-Session: https://claude.ai/code/session_013FhutRFjuQemBzekJMYcqL
The init, loader and plugin tests install with Yarn in parallel Jest workers. Yarn 1 can't fill one cache from two installs at the same time, and an install failed on macOS CI reading a half-written package.json from the shared cache. Claude-Session: https://claude.ai/code/session_013FhutRFjuQemBzekJMYcqL
Summary
Flaky CI runs in the generator and dev server tests, fixed without skipping anything. This PR changes only tests.
create-webpack-apptests: realnpm installfailuresThe init, loader and plugin tests install real packages. A failed install made the CLI exit with code 2 and print the reason on stderr. The tests only check stdout, so CI showed a misleading "Expected substring: Project has been initialised with webpack!", with stdout ending right after the generated files. Examples:
main, run 40124087314 (vue template)Forcing an install failure locally gives the same output.
Installing packages failed: npm error ..., instead of a missing line in stdout.prefer-offlineis not used. An earlier commit of this PR tried it, and CI then failed withETARGET: No matching version found for @babel/generator@^8.0.10: npm's cached metadata lacked a version that a freshly fetched package already depended on.create-webpack-apptests: shared Yarn cacheThe init, loader and plugin tests also install with Yarn, in parallel Jest workers. Yarn 1 can't fill one cache from two installs at the same time: on macOS CI an install failed with
SyntaxError: .../Caches/Yarn/v6/npm-path-exists-3.0.0-.../package.json: Unexpected end of JSON input. Each Jest worker now uses its own Yarn cache throughYARN_CACHE_FOLDER.Dev server tests: port already in use
get-port()with no options takes a port from the OS ephemeral range. Outgoing connections, such as the parallel installs above, use the same range and can take the port before the dev server listens. Parallel Jest workers can also get the same port.A shared
getFreePort()helper intest/utils/test-utils.jsgives each Jest worker its own 100-port range. There are 120 such ranges between 20000 and 31999, below the ephemeral ranges of Linux, macOS and Windows. Theserve-basic,serve-variableandwith-custom-porttests andmulti-dev-server.config.jsuse it.Testing
test/serve/basic,test/serve/serve-variableandtest/serve/with-custom-port: 41 passed, 1 skipped.test/create-webpack-app: 6 suites, 77 tests passed, with the three Yarn tests in different workers each using their own cache.🤖 Generated with Claude Code
https://claude.ai/code/session_013FhutRFjuQemBzekJMYcqL
Summary by CodeRabbit