From 0dd2bf11a0b9446874540d3228a52fe3e0411539 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Tue, 25 Aug 2026 10:59:06 +0100 Subject: [PATCH] chore: test on Node 20-26, use a recent yarn berry, bump typescript - 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) Claude-Session: https://claude.ai/code/session_019K5oVK8bNuHCvNVRauYieU --- .github/workflows/ci.yml | 12 ++- .gitignore | 3 +- package-lock.json | 129 +++++++++++++------------------- package.json | 8 +- playwright.config.ts | 3 + tests/component-testing.spec.ts | 2 +- tests/integration.spec.ts | 4 +- tsconfig.json | 4 +- 8 files changed, 75 insertions(+), 90 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8c4f8f..e2c17fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18.x, 20.x, 22.x, 24.x] + node-version: [20.x, 22.x, 24.x, 26.x] os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v4 @@ -26,6 +26,10 @@ jobs: - run: npm run build - run: npx tsc --noEmit - run: npx playwright test --grep-invert yarn-berry - - run: corepack enable - - run: corepack prepare yarn@4 --activate - - run: npx playwright test --grep yarn-berry + # Note: `yarn init` through corepack pins a stale yarn version into the generated project, + # so install yarn berry directly instead. + # Yarn PnP is broken on Node 22: its loader passes the CommonJS source to Node, and require.cache is undefined. + - if: matrix.node-version != '22.x' + run: npm i -g --force @yarnpkg/cli-dist@4 + - if: matrix.node-version != '22.x' + run: npx playwright test --grep yarn-berry diff --git a/.gitignore b/.gitignore index ef05e24..5ce1708 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ lib/ -test-results/ \ No newline at end of file +test-results/ +.vscode diff --git a/package-lock.json b/package-lock.json index 6994475..ed131ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,18 +12,18 @@ "create-playwright": "index.js" }, "devDependencies": { - "@playwright/test": "^1.59.0-alpha-1769819922000", + "@playwright/test": "1.63.0-alpha-2026-08-17", "@types/ini": "^4.1.1", - "@types/node": "^18.19.33", + "@types/node": "^20.19.43", "ansi-colors": "^4.1.1", "commander": "^14.0.1", "enquirer": "^2.3.6", "esbuild": "^0.25.0", "ini": "^4.1.3", - "typescript": "^5.4.5" + "typescript": "^6.0.3" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/@esbuild/aix-ppc64": { @@ -452,19 +452,19 @@ } }, "node_modules/@playwright/test": { - "version": "1.59.0-alpha-2026-01-31", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.0-alpha-2026-01-31.tgz", - "integrity": "sha512-pyQOCaCXMhFoAb16Y/dowVPdh6VV4G/MkOALZxSno0FSmqiKJKqpvl9EaCD1maUwVsxiHeDALtzOdXXJILR9IQ==", + "version": "1.63.0-alpha-2026-08-17", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0-alpha-2026-08-17.tgz", + "integrity": "sha512-w5xoMioML5gn7JWaM4nR5o9TU0jiQUeF9V6qm5VKTLZxXncqREOwaLpR/rOHdaMUXiQTcNXTRwC6Cl7Ld1BzBg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.59.0-alpha-2026-01-31" + "playwright": "1.63.0-alpha-2026-08-17" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/@types/ini": { @@ -474,12 +474,13 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.19.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.33.tgz", - "integrity": "sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==", + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", "dev": true, + "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "node_modules/ansi-colors": { @@ -554,21 +555,6 @@ "@esbuild/win32-x64": "0.25.0" } }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/ini": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", @@ -579,42 +565,40 @@ } }, "node_modules/playwright": { - "version": "1.59.0-alpha-2026-01-31", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0-alpha-2026-01-31.tgz", - "integrity": "sha512-EcHFxMpFVJVJPD8NGsBZhMRKKy3ZcxEO9+T4pLGZ03KVFfM1CHJoeLrARWf8OaH8RV6odT4jrDXajx819EKHpQ==", + "version": "1.63.0-alpha-2026-08-17", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0-alpha-2026-08-17.tgz", + "integrity": "sha512-oJv7tE/BRTZnxtcXOd6nWN6g3M8IfuQ/Lqhi+aT8fwFaFK44StxAMaD3BpFyUoQHCXX/bLcnfyXgQGVl7nT4ag==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.59.0-alpha-2026-01-31" + "playwright-core": "1.63.0-alpha-2026-08-17" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" + "node": ">=20" } }, "node_modules/playwright-core": { - "version": "1.59.0-alpha-2026-01-31", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0-alpha-2026-01-31.tgz", - "integrity": "sha512-uHHr+P5cCe1XPhnp+amcc8/LNKe/2gCCVCibrBJy6eQOgxMm6/CeGesMs6132ve0zhyFxIMgMVd/AvOaypEX8A==", + "version": "1.63.0-alpha-2026-08-17", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0-alpha-2026-08-17.tgz", + "integrity": "sha512-RvR21sa98NnWzh62HLzSUrlAiC8cNpJLunB69dy7c+/WAQyP4qKBjz060vwz9tLcybsWFLnoM3hXRTxHwwNwcw==", "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -624,10 +608,11 @@ } }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" } }, "dependencies": { @@ -807,12 +792,12 @@ "optional": true }, "@playwright/test": { - "version": "1.59.0-alpha-2026-01-31", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.59.0-alpha-2026-01-31.tgz", - "integrity": "sha512-pyQOCaCXMhFoAb16Y/dowVPdh6VV4G/MkOALZxSno0FSmqiKJKqpvl9EaCD1maUwVsxiHeDALtzOdXXJILR9IQ==", + "version": "1.63.0-alpha-2026-08-17", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0-alpha-2026-08-17.tgz", + "integrity": "sha512-w5xoMioML5gn7JWaM4nR5o9TU0jiQUeF9V6qm5VKTLZxXncqREOwaLpR/rOHdaMUXiQTcNXTRwC6Cl7Ld1BzBg==", "dev": true, "requires": { - "playwright": "1.59.0-alpha-2026-01-31" + "playwright": "1.63.0-alpha-2026-08-17" } }, "@types/ini": { @@ -822,12 +807,12 @@ "dev": true }, "@types/node": { - "version": "18.19.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.33.tgz", - "integrity": "sha512-NR9+KrpSajr2qBVp/Yt5TU/rp+b5Mayi3+OlMlcg2cVCfRmcG5PWZ7S4+MG9PZ5gWBoc9Pd0BKSRViuBCRPu0A==", + "version": "20.19.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.43.tgz", + "integrity": "sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==", "dev": true, "requires": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "ansi-colors": { @@ -884,13 +869,6 @@ "@esbuild/win32-x64": "0.25.0" } }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, "ini": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", @@ -898,31 +876,30 @@ "dev": true }, "playwright": { - "version": "1.59.0-alpha-2026-01-31", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0-alpha-2026-01-31.tgz", - "integrity": "sha512-EcHFxMpFVJVJPD8NGsBZhMRKKy3ZcxEO9+T4pLGZ03KVFfM1CHJoeLrARWf8OaH8RV6odT4jrDXajx819EKHpQ==", + "version": "1.63.0-alpha-2026-08-17", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0-alpha-2026-08-17.tgz", + "integrity": "sha512-oJv7tE/BRTZnxtcXOd6nWN6g3M8IfuQ/Lqhi+aT8fwFaFK44StxAMaD3BpFyUoQHCXX/bLcnfyXgQGVl7nT4ag==", "dev": true, "requires": { - "fsevents": "2.3.2", - "playwright-core": "1.59.0-alpha-2026-01-31" + "playwright-core": "1.63.0-alpha-2026-08-17" } }, "playwright-core": { - "version": "1.59.0-alpha-2026-01-31", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0-alpha-2026-01-31.tgz", - "integrity": "sha512-uHHr+P5cCe1XPhnp+amcc8/LNKe/2gCCVCibrBJy6eQOgxMm6/CeGesMs6132ve0zhyFxIMgMVd/AvOaypEX8A==", + "version": "1.63.0-alpha-2026-08-17", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0-alpha-2026-08-17.tgz", + "integrity": "sha512-RvR21sa98NnWzh62HLzSUrlAiC8cNpJLunB69dy7c+/WAQyP4qKBjz060vwz9tLcybsWFLnoM3hXRTxHwwNwcw==", "dev": true }, "typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true }, "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true } } diff --git a/package.json b/package.json index 7766963..a8a7d66 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "name": "Microsoft Corporation" }, "engines": { - "node": ">=18" + "node": ">=20" }, "main": "index.js", "bin": { @@ -26,14 +26,14 @@ "prepublish": "npm run build" }, "devDependencies": { - "@playwright/test": "^1.59.0-alpha-1769819922000", + "@playwright/test": "1.63.0-alpha-2026-08-17", "@types/ini": "^4.1.1", - "@types/node": "^18.19.33", + "@types/node": "^20.19.43", "ansi-colors": "^4.1.1", "commander": "^14.0.1", "enquirer": "^2.3.6", "esbuild": "^0.25.0", "ini": "^4.1.3", - "typescript": "^5.4.5" + "typescript": "^6.0.3" } } diff --git a/playwright.config.ts b/playwright.config.ts index f8c26ad..15f42da 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -21,6 +21,7 @@ import os from 'node:os'; export default defineConfig({ timeout: 120 * 1000, + fullyParallel: true, testDir: './tests', reporter: 'list', outputDir: fs.mkdtempSync(path.join(os.tmpdir(), 'create-playwright-test-')), // place test dir outside to prevent influece from `yarn.lock` or `package.json` in repo @@ -33,6 +34,8 @@ export default defineConfig({ }, { name: 'yarn-classic', + // Yarn classic does not support concurrent access to its global cache. + workers: 1, use: { packageManager: 'yarn-classic' } diff --git a/tests/component-testing.spec.ts b/tests/component-testing.spec.ts index 4430aef..c228550 100644 --- a/tests/component-testing.spec.ts +++ b/tests/component-testing.spec.ts @@ -17,7 +17,7 @@ import { test, expect, assertLockFilesExist, packageManagerToNpxCommand } from ' import path from 'path'; import fs from 'fs'; -test('should be able to generate and run a CT React project', async ({ run, dir, exec, packageManager }) => { +test('should be able to generate and run a CT React project', { lock: 'apt-get' }, async ({ run, dir, exec, packageManager }) => { test.skip(packageManager === 'yarn-classic' || packageManager === 'yarn-berry'); test.slow(); await run(['--ct'], { installGitHubActions: true, testDir: 'tests', language: 'TypeScript', installPlaywrightDependencies: false, installPlaywrightBrowsers: true, framework: 'react' }); diff --git a/tests/integration.spec.ts b/tests/integration.spec.ts index ff0843d..09da0e5 100644 --- a/tests/integration.spec.ts +++ b/tests/integration.spec.ts @@ -77,7 +77,7 @@ test('should generate a project with JavaScript and without GHA', async ({ run, expect(fs.existsSync(path.join(dir, '.github/workflows/playwright.yml'))).toBeFalsy(); }); -test('should generate be able to run TS examples successfully', async ({ run, dir, exec, packageManager }) => { +test('should generate be able to run TS examples successfully', { lock: 'apt-get' }, async ({ run, dir, exec, packageManager }) => { test.slow(); await run([], { installGitHubActions: false, testDir: 'tests', language: 'TypeScript', installPlaywrightDependencies: false, installPlaywrightBrowsers: true }); expect(fs.existsSync(path.join(dir, 'tsconfig.json'))).toBeTruthy(); @@ -89,7 +89,7 @@ test('should generate be able to run TS examples successfully', async ({ run, di await exec(packageManagerToNpxCommand(packageManager), ['playwright', 'test']); }); -test('should generate be able to run JS examples successfully', async ({ run, dir, exec, packageManager }) => { +test('should generate be able to run JS examples successfully', { lock: 'apt-get' }, async ({ run, dir, exec, packageManager }) => { test.slow(); await run([], { installGitHubActions: false, testDir: 'tests', language: 'JavaScript', installPlaywrightDependencies: false, installPlaywrightBrowsers: true }); expect(fs.existsSync(path.join(dir, 'tests/example.spec.js'))).toBeTruthy(); diff --git a/tsconfig.json b/tsconfig.json index fdd794e..c83e81d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "target": "ES2019", + "types": ["node"], "module": "commonjs", "esModuleInterop": true, "strict": true, @@ -13,6 +14,5 @@ "noUncheckedIndexedAccess": true }, "compileOnSave": true, - "include": ["src", "tests", "assets"], - "exclude": ["assets/playwright-ct.config.ts", "assets/playwright-ct.config.js"] + "exclude": ["node_modules", "lib", "test-results", "assets/playwright-ct.config.ts", "assets/playwright-ct.config.js"] } \ No newline at end of file