fix(serve): keep owned Xvfb alive through Electron teardown

This commit is contained in:
Jinwoo-H
2026-08-13 15:50:29 -04:00
parent 0824ed39ea
commit 28962ec448
2 changed files with 12 additions and 4 deletions
@@ -42,7 +42,11 @@ describe('ensureVirtualDisplayForHeadlessServe', () => {
delete process.env.DISPLAY
})
afterEach(() => {
afterEach(async () => {
const { stopVirtualDisplay } = await import('./ensure-virtual-display')
process.removeListener('exit', stopVirtualDisplay)
stopVirtualDisplay()
vi.restoreAllMocks()
setPlatform(ORIGINAL_PLATFORM)
if (ORIGINAL_DISPLAY === undefined) {
delete process.env.DISPLAY
@@ -97,7 +101,9 @@ describe('ensureVirtualDisplayForHeadlessServe', () => {
// First existsSync (stale-socket check) false; later (socket-ready poll) true.
existsSyncMock.mockReturnValueOnce(false).mockReturnValue(true)
spawnMock.mockReturnValue({ once: vi.fn(), kill: vi.fn(), killed: false })
const { ensureVirtualDisplayForHeadlessServe } = await import('./ensure-virtual-display')
const processOnceSpy = vi.spyOn(process, 'once')
const { ensureVirtualDisplayForHeadlessServe, stopVirtualDisplay } =
await import('./ensure-virtual-display')
expect(ensureVirtualDisplayForHeadlessServe({ isServeMode: true })).toBe(true)
expect(spawnMock).toHaveBeenCalledWith(
@@ -109,6 +115,8 @@ describe('ensureVirtualDisplayForHeadlessServe', () => {
expect(appMock.disableHardwareAcceleration).toHaveBeenCalled()
expect(appMock.commandLine.appendSwitch).toHaveBeenCalledWith('disable-dev-shm-usage')
expect(appMock.commandLine.appendSwitch).toHaveBeenCalledWith('disable-gpu')
expect(processOnceSpy).toHaveBeenCalledWith('exit', stopVirtualDisplay)
expect(appMock.once).not.toHaveBeenCalledWith('will-quit', stopVirtualDisplay)
})
it('reuses an existing virtual display only when its X server is alive', async () => {
+2 -2
View File
@@ -163,8 +163,8 @@ export function ensureVirtualDisplayForHeadlessServe(options: { isServeMode: boo
process.env.DISPLAY = VIRTUAL_DISPLAY
// Why: don't leave a stray Xvfb process behind when serve exits.
app.once('will-quit', stopVirtualDisplay)
// Why: Electron can cancel will-quit for async teardown and still needs X11 until its event loop stops.
process.once('exit', stopVirtualDisplay)
return true
}