Skip to content

chore: test on Node 20-26, use a recent yarn berry, bump typescript - #178

Merged
Dmitry Gozman (dgozman) merged 1 commit into
microsoft:mainfrom
dgozman:ci-node-versions
Aug 25, 2026
Merged

chore: test on Node 20-26, use a recent yarn berry, bump typescript#178
Dmitry Gozman (dgozman) merged 1 commit into
microsoft:mainfrom
dgozman:ci-node-versions

Conversation

@dgozman

@dgozmanDmitry Gozman (dgozman) commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Node matrix: drop 18, add 26

Playwright now requires Node >=20, so all 18.x jobs were failing while the generated projects installed @playwright/test:

error playwright@1.62.1: The engine "node" is incompatible with this module. Expected version ">=20". Got "18.20.8"

engines.node is bumped to >=20 to match.

Install yarn berry from npm instead of corepack

yarn init, which the generator runs, is a corepack transparent command: in a project without a packageManager field, corepack runs its own hardcoded default (4.14.1 with corepack 0.35.0) and pins that version into the generated project — regardless of what corepack prepare yarn@4 --activate selected. Installing @yarnpkg/cli-dist directly means the generated projects run the yarn we actually installed (verified: the generated package.json now says yarn@4.18.0).

--force is needed because yarn@1, installed earlier for the yarn-classic tests, already owns the global yarn bin.

Skip the yarn-berry step on the Node 22 bots

On Node versions with a broken fstat for zip fds, the yarn PnP loader hands the CommonJS source to Node instead of letting the CJS loader read the file out of the zip. Node then loads Playwright through the ESM loader's CommonJS translator, where the injected require has no cache property, and loading a test file fails:

TypeError: Cannot read properties of undefined (reading '.../tests/example.spec.ts')

Which Node versions are affected moves with each yarn release (HAS_BROKEN_FSTAT_FOR_ZIP_FDS in .pnp.loader.mjs); Node 22 is in the window for the current yarn, which is why the bug shows up here now and on Node 24 with the older pinned yarn. A fix for requireOrImport is on the way in @playwright/test — the if: condition on the two yarn-berry steps should go away with it.

Serialize the tests that share a resource

Three tests shell out to playwright install-deps, which runs apt-get. When two of them run concurrently in different projects, one loses:

Failed to install browser dependencies
Error: Installation process exited with code: 100
E: Could not get lock /var/lib/apt/lists/lock. It is held by process 8121 (apt-get)

This is an old flake — the same failure is on main from June. Those tests now declare { lock: 'apt-get' }, so they never run at the same time while everything else stays parallel. Locks are held per job, and a job is a whole file unless tests run in parallel mode, so fullyParallel is turned on to make the lock per test. @playwright/test is bumped to 1.63.0-alpha-2026-08-17 for the lock support.

fullyParallel in turn lets two installs of the same project run at once, which yarn classic does not survive — its global cache tears with EPERM/ENOENT on the .yarn-tarball.tgz files on Windows. The yarn-classic project is therefore limited to workers: 1.

Verified with the JSON reporter on the non-berry suite: zero overlapping runs among the locked tests, zero among yarn-classic tests, 142 overlapping pairs elsewhere, 49.7s wall time (51s before).

Bump typescript to 6.0.3 and @types/node to 20.19.43

TypeScript 6 no longer includes @types/* automatically, so types: ["node"] is now explicit — without it npx tsc --noEmit reports 143 errors (Cannot find name 'process', Cannot find namespace 'NodeJS', …). Dropping include puts the root playwright.config.ts into the project too, so it is type checked rather than falling back to an inferred config in the editor. node_modules and lib now have to be listed in exclude, since specifying exclude replaces TypeScript's defaults.

Verification

Ran locally on macOS with the same setup as the bots (yarn 4.18 as the global yarn):

Node 20Node 22Node 24Node 26
--grep yarn-berry7 passedskipped on CI7 passed7 passed
--grep-invert yarn-berry35 passed, 21 skipped

npx tsc --noEmit and npm run build are clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_019K5oVK8bNuHCvNVRauYieU

@dgozman
Dmitry Gozman (dgozman)force-pushed the ci-node-versions branch 3 times, most recently from 4a6cfd8 to 2e8f632CompareAugust 25, 2026 11:20
- Replace the Node 18 bots with Node 26. Playwright requires Node >=20,
so every 18.x job was failing while installing `@playwright/test`.
`engines.node` is bumped to >=20 accordingly.
- Install yarn berry from npm instead of corepack. `yarn init`, which the
generator runs, is a corepack "transparent command": in a project without a
`packageManager` field corepack runs its own hardcoded default (4.14.1 today)
and pins that into the generated project, no matter what
`corepack prepare yarn@4 --activate` selected. Installing @yarnpkg/cli-dist
directly makes the generated projects use the yarn we actually installed.
- Skip the yarn-berry step on the Node 22 bots. On Node versions with a broken
fstat for zip fds, the yarn PnP loader passes the CommonJS source to Node,
which then loads Playwright through the ESM loader's CommonJS translator,
where `require.cache` is undefined and loading test files fails with
"TypeError: Cannot read properties of undefined". Node 22 is in that window
for the current yarn. To be removed once the fix ships in @playwright/test.
- Take a named lock in the tests that run `playwright install-deps`. Two of
them running at the same time in different projects fight over the apt-get
lock and fail with "Could not get lock /var/lib/apt/lists/lock". Requires a
newer @playwright/test, and `fullyParallel` so that the lock is taken per
test rather than per file.
- Limit the yarn-classic project to a single worker. Yarn classic does not
support concurrent access to its global cache and fails with EPERM/ENOENT on
the `.yarn-tarball.tgz` files on Windows, now that `fullyParallel` lets two
installs of the same project run at the same time.
- Bump typescript to 6.0.3 and @types/node to 20.19.43. TypeScript 6 does not
include @types/* automatically anymore, hence `types: ["node"]`. Dropping
`include` puts the root playwright.config.ts into the project as well, so it
is type checked instead of falling back to an inferred config in the editor.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019K5oVK8bNuHCvNVRauYieU
@dgozman
Dmitry Gozman (dgozman) merged commit 819b827 into microsoft:mainAug 25, 2026
13 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@dgozman@yury-s