mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-22 04:40:44 +02:00
The repo's first patchedDependencies entry. playwright-core's bundled process launcher (lib/coreBundle.js in the 1.62.x layout) spawns browser children without windowsHide — Node defaults it to FALSE for child_process.spawn — so Chromium children could flash a console window on Windows, and its force-kill path shells `taskkill /pid <pid> /T /F` through cmd.exe with the same omission. Both sites now pass windowsHide: true via patches/playwright-core@1.62.1.patch (generated with `bun patch` / `bun patch --commit`). Coherence verified end-to-end: rm -rf node_modules && bun install applies the patch cleanly (both sites present in the reinstalled tree), and a real chromium.launch() through the patched bundle works. browse/test/playwright-core-patch.test.ts pins the three-legged invariant statically — package.json's patchedDependencies key is VERSION-KEYED against the installed playwright-core, the patch file exists and carries both sites, bun.lock records the patch, and the installed bundle actually has it applied — so a future playwright bump that forgets to re-target the patch fails CI with the exact key to regenerate (revert pairing: dropping the c25 bump requires dropping this patch too). Tests: playwright-core-patch 4 pass, 0 fail. Fixes #2160, #1989. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
994b5f5502
commit
436adb72d3
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* #2160/#1989: playwright-core is bun-patched to pass windowsHide at its two
|
||||||
|
* Windows-visible child_process sites — the browser launch spawn (Node
|
||||||
|
* defaults windowsHide to FALSE for spawn, so browser children could flash a
|
||||||
|
* console window) and the force-kill taskkill spawnSync. This is the repo's
|
||||||
|
* first patchedDependencies entry; these static checks pin the three-legged
|
||||||
|
* coherence (patch file ↔ package.json ↔ installed tree) so a playwright
|
||||||
|
* bump that forgets to re-target the patch fails CI instead of silently
|
||||||
|
* dropping it. NOTE: bumping playwright (c25-style) REQUIRES regenerating
|
||||||
|
* this patch against the new version — see the revert pairing in the wave
|
||||||
|
* plan (reverting the bump means dropping the patch too).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, expect, test } from 'bun:test';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
const ROOT = path.resolve(import.meta.dir, '..', '..');
|
||||||
|
|
||||||
|
function installedPlaywrightCoreVersion(): string {
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(
|
||||||
|
path.join(ROOT, 'node_modules', 'playwright-core', 'package.json'), 'utf-8',
|
||||||
|
));
|
||||||
|
return pkg.version as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('playwright-core windowsHide patch (#2160, #1989)', () => {
|
||||||
|
test('package.json declares the patch for the installed version', () => {
|
||||||
|
const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf-8'));
|
||||||
|
const version = installedPlaywrightCoreVersion();
|
||||||
|
const key = `playwright-core@${version}`;
|
||||||
|
expect(pkg.patchedDependencies).toBeDefined();
|
||||||
|
// Version-keyed on purpose: if playwright is bumped without re-targeting
|
||||||
|
// the patch, this fails with the exact key that needs regenerating.
|
||||||
|
expect(pkg.patchedDependencies[key]).toBe(`patches/playwright-core@${version}.patch`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the patch file exists and carries both windowsHide sites', () => {
|
||||||
|
const version = installedPlaywrightCoreVersion();
|
||||||
|
const patchPath = path.join(ROOT, 'patches', `playwright-core@${version}.patch`);
|
||||||
|
expect(fs.existsSync(patchPath)).toBe(true);
|
||||||
|
const patch = fs.readFileSync(patchPath, 'utf-8');
|
||||||
|
// Launch spawnOptions site.
|
||||||
|
expect(patch).toContain('+ windowsHide: true,');
|
||||||
|
// taskkill force-kill site.
|
||||||
|
expect(patch).toContain('shell: true, windowsHide: true');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('bun.lock is coherent: the lockfile records the patched dependency', () => {
|
||||||
|
const lock = fs.readFileSync(path.join(ROOT, 'bun.lock'), 'utf-8');
|
||||||
|
const version = installedPlaywrightCoreVersion();
|
||||||
|
expect(lock).toContain(`patches/playwright-core@${version}.patch`);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the INSTALLED tree actually has the patch applied (bun install ran it)', () => {
|
||||||
|
const bundle = fs.readFileSync(
|
||||||
|
path.join(ROOT, 'node_modules', 'playwright-core', 'lib', 'coreBundle.js'), 'utf-8',
|
||||||
|
);
|
||||||
|
expect(bundle).toContain('gstack patch (#2160/#1989)');
|
||||||
|
expect(bundle).toContain('shell: true, windowsHide: true');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -23,6 +23,9 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"patchedDependencies": {
|
||||||
|
"playwright-core@1.62.1": "patches/playwright-core@1.62.1.patch",
|
||||||
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"basic-ftp": "5.3.1",
|
"basic-ftp": "5.3.1",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -82,5 +82,8 @@
|
|||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"basic-ftp": "5.3.1"
|
"basic-ftp": "5.3.1"
|
||||||
|
},
|
||||||
|
"patchedDependencies": {
|
||||||
|
"playwright-core@1.62.1": "patches/playwright-core@1.62.1.patch"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
diff --git a/lib/coreBundle.js b/lib/coreBundle.js
|
||||||
|
index d9041dd0f009072511a7d808dec83121ff29e127..e5c72c452c98f1c64038c5f24ac5805fbc99151f 100644
|
||||||
|
--- a/lib/coreBundle.js
|
||||||
|
+++ b/lib/coreBundle.js
|
||||||
|
@@ -8906,6 +8906,10 @@ async function launchProcess(options) {
|
||||||
|
env: options.env,
|
||||||
|
cwd: options.cwd,
|
||||||
|
shell: options.shell,
|
||||||
|
+ // gstack patch (#2160/#1989): Node defaults windowsHide to false for
|
||||||
|
+ // child_process.spawn, so browser children could flash a console window
|
||||||
|
+ // on Windows. Playwright never needs the child's window shown.
|
||||||
|
+ windowsHide: true,
|
||||||
|
stdio
|
||||||
|
};
|
||||||
|
const spawnedProcess = childProcess.spawn(options.command, options.args || [], spawnOptions);
|
||||||
|
@@ -8985,7 +8989,7 @@ async function launchProcess(options) {
|
||||||
|
options.log(`[pid=${spawnedProcess.pid}] <will force kill>`);
|
||||||
|
try {
|
||||||
|
if (process.platform === "win32") {
|
||||||
|
- const taskkillProcess = childProcess.spawnSync(`taskkill /pid ${spawnedProcess.pid} /T /F`, { shell: true });
|
||||||
|
+ const taskkillProcess = childProcess.spawnSync(`taskkill /pid ${spawnedProcess.pid} /T /F`, { shell: true, windowsHide: true });
|
||||||
|
const [stdout2, stderr2] = [taskkillProcess.stdout.toString(), taskkillProcess.stderr.toString()];
|
||||||
|
if (stdout2)
|
||||||
|
options.log(`[pid=${spawnedProcess.pid}] taskkill stdout: ${stdout2}`);
|
||||||
Reference in New Issue
Block a user