From 21c99d05748513674de7bdea5eea465450822c11 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:34:13 -0700 Subject: [PATCH] fix(bin): script path, exit codes, and integration suite handling (#5973) ## Summary Improves reliability and correctness of `bin/` maintenance scripts used for local development and CI. ## Behavioral fixes - **Exit codes**: `test_integration.js` exits with code 1 when `--suite` names an unknown suite; `test_unit.js` uses a non-zero fallback (`-1`) when the coverage or mocha child process has no status; `esbuild_all.mjs` exits non-zero if any parallel esbuild child fails. - **Repo root**: `setup-full.mjs` resolves the repository root one directory above `bin/` (was incorrectly using `bin/` as root). - **esbuild_all**: Propagates child build failures instead of always exiting 0. - **Integration suites**: When `--suite` is omitted, all configured Playwright suites (core + addons) run; when provided, only the matching suite runs. - **test_unit.js**: Declares the `files` filter variable so file arguments from `npm run test-unit` work without a ReferenceError. - **test_mousemodes.js**: Uses the correct cursor-home CSI (`ESC [ H`) when clearing the menu screen. - **Cleanup**: Removes debug logging from the test-unit coverage path; adds a missing semicolon after the suite regex match. ## Affected scripts - `bin/test_integration.js` - `bin/test_unit.js` - `bin/esbuild_all.mjs` - `bin/setup-full.mjs` - `bin/test_mousemodes.js` ## Testing - Syntax-checked affected scripts with `node --check` - Verified `node bin/test_integration.js --suite=unknown` exits 1 with an error message - `npm run lint-changes` (no TypeScript files changed)
Open in Web Open in Cursor 
--- bin/esbuild_all.mjs | 7 +++++-- bin/setup-full.mjs | 4 ++-- bin/test_integration.js | 15 ++++++++++++--- bin/test_mousemodes.js | 2 +- bin/test_unit.js | 6 ++---- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/bin/esbuild_all.mjs b/bin/esbuild_all.mjs index 1a3aadea5..789cb5df0 100644 --- a/bin/esbuild_all.mjs +++ b/bin/esbuild_all.mjs @@ -19,14 +19,17 @@ for (const addon of addons) { // Demo job - This requires the others to be built so it's not included when building all // jobs.push(createJob('demo-client', [`--demo-client`])); -await Promise.all(jobs.map((job, i) => { +const codes = await Promise.all(jobs.map(job => { return new Promise(r => { job.cp.on('exit', code => { log(`Finished \x1b[32m${job.name}\x1b[0m${code ? ' \x1b[31mwith errors\x1b[0m' : ''}`); - r(code); + r(code ?? 1); }); }); })); +if (codes.some(code => code !== 0)) { + process.exit(1); +} /** * @param {string} message diff --git a/bin/setup-full.mjs b/bin/setup-full.mjs index 2db85d87a..35a62cbd7 100644 --- a/bin/setup-full.mjs +++ b/bin/setup-full.mjs @@ -5,7 +5,7 @@ import { spawnSync } from 'node:child_process'; import { basename, dirname, resolve, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; -const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const nodeModulesPath = resolve(repoRoot, 'node_modules'); const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm'; @@ -13,7 +13,7 @@ const npmExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm'; /** @param {string} message */ function log(message) { - console.info(`[setup-fast] ${message}`); + console.info(`[setup-full] ${message}`); } /** @param {string[]} args */ diff --git a/bin/test_integration.js b/bin/test_integration.js index 37e6aca7c..0a2531e23 100644 --- a/bin/test_integration.js +++ b/bin/test_integration.js @@ -12,7 +12,7 @@ let argv = process.argv.slice(2); let suiteFilter = undefined; while (argv.some(e => e.startsWith('--suite='))) { const i = argv.findIndex(e => e.startsWith('--suite=')); - const match = argv[i].match(/--suite=(?.+)/) + const match = argv[i].match(/--suite=(?.+)/); suiteFilter = match?.groups?.suitename ?? undefined; argv.splice(i, 1); } @@ -42,12 +42,18 @@ if (suiteFilter) { configs = configs.filter(e => e.name === suiteFilter); } +if (suiteFilter && configs.length === 0) { + console.error(`Unknown suite: ${suiteFilter}`); + process.exit(1); +} + function npmBinScript(script) { return path.resolve(__dirname, `../node_modules/.bin/` + (process.platform === 'win32' ? `${script}.cmd` : script)); } async function run() { + let exitCode = 0; for (const config of configs) { const command = npmBinScript('playwright'); const args = ['test', '-c', config.path, ...argv]; @@ -62,10 +68,13 @@ async function run() { if (run.error) { console.error(run.error); - process.exit(run.status ?? -1); + process.exit(run.status ?? 1); } - process.exit(run.status); + if (run.status) { + exitCode = run.status; + } } + process.exit(exitCode); } run(); diff --git a/bin/test_mousemodes.js b/bin/test_mousemodes.js index 0f12d208b..8954c1d77 100644 --- a/bin/test_mousemodes.js +++ b/bin/test_mousemodes.js @@ -177,7 +177,7 @@ const ENC = { } function printMenu() { - console.log('\x1b[2J\x1b\[HTest mouse reports [Ctrl-C to exit]'); + console.log('\x1b[2J\x1b[HTest mouse reports [Ctrl-C to exit]'); console.log(); console.log(' Selected protocol [Ctrl-A to switch]'); const protocols = Object.keys(PROTOCOLS); diff --git a/bin/test_unit.js b/bin/test_unit.js index 58fdd9a32..2ff7f6250 100644 --- a/bin/test_unit.js +++ b/bin/test_unit.js @@ -21,7 +21,7 @@ if (process.argv.length > 2) { flagArgs = args.filter(e => e.startsWith('--')); // ability to inject particular test files via // npm run test [testFileA testFileB ...] - files = args.filter(e => !e.startsWith('--')); + const files = args.filter(e => !e.startsWith('--')); if (files.length) { testFiles = files; } @@ -39,8 +39,6 @@ if (checkCoverage) { ...testFiles, ...flagArgs ]; - console.info('executable', executable); - console.info('args', args); const run = cp.spawnSync( executable, args, @@ -51,7 +49,7 @@ if (checkCoverage) { stdio: 'inherit' } ); - process.exit(run.status); + process.exit(run.status ?? -1); } const run = cp.spawnSync(