This commit is contained in:
Wim van den Heijkant 2026-07-17 11:59:28 +02:00 committed by GitHub
commit a45088acd9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 0 deletions

View File

@ -75,6 +75,10 @@ globalThis.Bun = {
timeout: options.timeout,
env: options.env,
cwd: options.cwd,
// Node defaults windowsHide to false, so every child opens a console
// window on Windows. Bun.spawnSync has no such behaviour, so the
// polyfill has to opt in to stay faithful to the API it's emulating.
windowsHide: options.windowsHide !== false,
});
return {
@ -91,6 +95,10 @@ globalThis.Bun = {
stdio,
env: options.env,
cwd: options.cwd,
// See spawnSync above. This one is the visible offender: the detached
// terminal-agent the browse watchdog respawns every 60s left an empty
// console window on screen each time.
windowsHide: options.windowsHide !== false,
});
return {

View File

@ -48,6 +48,44 @@ describe('bun-polyfill', () => {
expect(lines[2]).toBe('HAS_UNREF');
});
// Regression: Node defaults windowsHide to false, so before this the browse
// server flashed an empty console window on Windows for every child it
// spawned -- most visibly the terminal-agent the watchdog respawns on a 60s
// tick. Asserts the option reaches child_process rather than trying to
// observe a window, so it is meaningful on every platform.
test('Bun.spawn/spawnSync pass windowsHide to child_process', () => {
const result = Bun.spawnSync(['node', '-e', `
const cp = require('child_process');
const realSpawn = cp.spawn, realSpawnSync = cp.spawnSync;
const seen = {};
cp.spawn = (c, a, o) => { seen.spawn = o.windowsHide; return realSpawn(c, a, o); };
cp.spawnSync = (c, a, o) => { seen.spawnSync = o.windowsHide; return realSpawnSync(c, a, o); };
require('${polyfillPath}');
Bun.spawnSync([process.execPath, '-e', ''], { stdout: 'pipe' });
Bun.spawn([process.execPath, '-e', ''], { stdio: ['ignore', 'ignore', 'ignore'] });
console.log('spawnSync:' + seen.spawnSync);
console.log('spawn:' + seen.spawn);
`], { stdout: 'pipe', stderr: 'pipe' });
const lines = result.stdout.toString().trim().split('\n');
expect(lines[0]).toBe('spawnSync:true');
expect(lines[1]).toBe('spawn:true');
});
// An explicit windowsHide: false must still win, so a caller that genuinely
// wants a visible console (e.g. debugging a child) keeps that escape hatch.
test('Bun.spawn honours an explicit windowsHide: false', () => {
const result = Bun.spawnSync(['node', '-e', `
const cp = require('child_process');
const realSpawn = cp.spawn;
const seen = {};
cp.spawn = (c, a, o) => { seen.spawn = o.windowsHide; return realSpawn(c, a, o); };
require('${polyfillPath}');
Bun.spawn([process.execPath, '-e', ''], { stdio: ['ignore', 'ignore', 'ignore'], windowsHide: false });
console.log('spawn:' + seen.spawn);
`], { stdout: 'pipe', stderr: 'pipe' });
expect(result.stdout.toString().trim()).toBe('spawn:false');
});
test('Bun.serve creates an HTTP server that responds', async () => {
const result = Bun.spawnSync(['node', '-e', `
require('${polyfillPath}');