import { EventEmitter } from 'node:events'
import { mkdir, mkdtemp, readFile, rename, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { encodePairingOffer, PAIRING_OFFER_VERSION } from '../../shared/pairing'
import {
getServeUpdateHandoffPath,
parseServeUpdateHandoffState
} from '../../shared/serve-update-handoff'
import {
readServeUpdateHandoff,
SERVE_REPLACEMENT_READY_TIMEOUT_MS
} from './serve-update-supervisor'
const { spawnMock, spawnSyncMock } = vi.hoisted(() => ({
spawnMock: vi.fn(),
spawnSyncMock: vi.fn()
}))
vi.mock('child_process', () => ({
spawn: spawnMock,
spawnSync: spawnSyncMock
}))
import { launchOrcaApp, serveOrcaApp } from './launch'
class FakeChildProcess extends EventEmitter {
stdout = new EventEmitter()
kill = vi.fn()
unref = vi.fn()
pid = 4101
}
const RECIPE_JSON = JSON.stringify({
schemaVersion: 1,
pairingCode: encodePairingOffer({
v: PAIRING_OFFER_VERSION,
endpoint: 'wss://sandbox.example.com',
deviceToken: 'token',
publicKeyB64: 'public-key'
}),
projectRoot: '/workspace/repo'
})
const SERVE_INSTALL_STATUS = '[serve] orca CLI install: installed'
const SSH_PRIVATE_KEY = 'TOP-SECRET-PRIVATE-KEY'
const SSH_AUTHORIZATION = 'Bearer TOP-SECRET-AUTHORIZATION'
const SSH_PASSPHRASE = 'TOP-SECRET-PASSPHRASE'
const SSH_COOKIE = 'session=TOP-SECRET-COOKIE'
const SSH_RECIPE_JSON = JSON.stringify({
schemaVersion: 1,
connection: {
type: 'ssh',
target: {
label: 'Sandbox',
host: 'sandbox.example.com',
port: 22,
username: 'root'
},
projectRoot: '/workspace/repo'
},
userData: {
credentials: {
privateKey: SSH_PRIVATE_KEY,
authorization: SSH_AUTHORIZATION,
passphrase: SSH_PASSPHRASE,
cookie: SSH_COOKIE
}
}
})
const INVALID_SSH_RECIPE_JSON = SSH_RECIPE_JSON.replace('/workspace/repo', 'relative/repo')
const IGNORED_NON_RECIPE_STDOUT = '[serve] ignored non-recipe stdout'
function startRecipeJsonServer() {
const child = new FakeChildProcess()
spawnMock.mockReturnValue(child)
const stdoutSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true)
const stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true)
const result = serveOrcaApp({
recipeJson: true,
projectRoot: '/workspace/repo'
})
return { child, result, stdoutSpy, stderrSpy }
}
describe('serveOrcaApp', () => {
const temporaryDirectories: string[] = []
beforeEach(() => {
spawnMock.mockReset()
spawnSyncMock.mockReset()
process.env.ORCA_APP_EXECUTABLE = '/Applications/Orca.app/Contents/MacOS/Orca'
})
afterEach(() => {
vi.restoreAllMocks()
delete process.env.ORCA_APP_EXECUTABLE
delete process.env.ORCA_APP_EXECUTABLE_NEEDS_APP_ROOT
delete process.env.ORCA_USER_DATA_PATH
return Promise.all(
temporaryDirectories.splice(0).map((directory) => rm(directory, { recursive: true }))
)
})
it.runIf(process.platform === 'darwin')(
'keeps the serve supervisor alive until the installed target version can take ownership',
async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-serve-update-'))
temporaryDirectories.push(root)
const appPath = join(root, 'Orca.app')
const executable = join(appPath, 'Contents', 'MacOS', 'Orca')
const infoPlistPath = join(appPath, 'Contents', 'Info.plist')
const userDataPath = join(root, 'user-data')
await mkdir(join(appPath, 'Contents', 'MacOS'), { recursive: true })
await mkdir(userDataPath, { recursive: true })
await writeFile(
infoPlistPath,
'CFBundleShortVersionString1.0.51'
)
process.env.ORCA_APP_EXECUTABLE = executable
process.env.ORCA_USER_DATA_PATH = userDataPath
const oldOwner = new FakeChildProcess()
const replacementOwner = new FakeChildProcess()
replacementOwner.pid = 4102
spawnMock.mockReturnValueOnce(oldOwner).mockReturnValueOnce(replacementOwner)
let supervisorExited = false
const supervisor = serveOrcaApp({ json: true }).then((code) => {
supervisorExited = true
return code
})
const childEnv = spawnMock.mock.calls[0]?.[2]?.env as NodeJS.ProcessEnv | undefined
const handoffPath = childEnv?.ORCA_SERVE_UPDATE_HANDOFF_PATH
expect(handoffPath).toBeTruthy()
await writeFile(
handoffPath!,
JSON.stringify({
schemaVersion: 1,
phase: 'install-requested',
fromVersion: '1.0.51',
targetVersion: '1.0.61',
servingPid: oldOwner.pid
})
)
oldOwner.emit('exit', 0, null)
await Promise.resolve()
expect(supervisorExited).toBe(false)
expect(spawnMock).toHaveBeenCalledTimes(1)
const updateAppPath = join(root, 'Update.app')
await mkdir(join(updateAppPath, 'Contents'), { recursive: true })
await writeFile(
join(updateAppPath, 'Contents', 'Info.plist'),
'CFBundleShortVersionString1.0.61'
)
await rename(appPath, join(root, 'Previous.app'))
await rename(updateAppPath, appPath)
await vi.waitFor(() => expect(spawnMock).toHaveBeenCalledTimes(2))
replacementOwner.emit('message', {
type: 'orca:serve-ready',
version: '1.0.61',
runtimeId: 'runtime-new'
})
expect(supervisorExited).toBe(false)
await vi.waitFor(async () => expect(await readServeUpdateHandoff(handoffPath!)).toBeNull())
replacementOwner.emit('exit', 0, null)
await expect(supervisor).resolves.toBe(0)
}
)
it.runIf(process.platform === 'darwin')(
'records a replacement version mismatch without starting a retry loop',
async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-serve-update-mismatch-'))
temporaryDirectories.push(root)
const appPath = join(root, 'Orca.app')
const executable = join(appPath, 'Contents', 'MacOS', 'Orca')
const userDataPath = join(root, 'user-data')
await mkdir(join(appPath, 'Contents', 'MacOS'), { recursive: true })
await mkdir(userDataPath, { recursive: true })
await writeFile(
join(appPath, 'Contents', 'Info.plist'),
'CFBundleShortVersionString1.0.61'
)
const handoffPath = getServeUpdateHandoffPath(userDataPath)
await writeFile(
handoffPath,
JSON.stringify({
schemaVersion: 1,
phase: 'install-requested',
fromVersion: '1.0.51',
targetVersion: '1.0.61',
servingPid: 4101
})
)
process.env.ORCA_APP_EXECUTABLE = executable
process.env.ORCA_USER_DATA_PATH = userDataPath
const replacementOwner = new FakeChildProcess()
replacementOwner.pid = 4102
spawnMock.mockReturnValue(replacementOwner)
vi.spyOn(process.stderr, 'write').mockImplementation(() => true)
const supervisor = serveOrcaApp({ json: true })
await vi.waitFor(() => expect(spawnMock).toHaveBeenCalledOnce())
replacementOwner.emit('message', {
type: 'orca:serve-ready',
version: '1.0.51',
runtimeId: 'runtime-old'
})
await vi.waitFor(() => expect(replacementOwner.kill).toHaveBeenCalledWith('SIGTERM'))
replacementOwner.emit('exit', 0, null)
await expect(supervisor).resolves.toBe(1)
expect(spawnMock).toHaveBeenCalledOnce()
expect(parseServeUpdateHandoffState(JSON.parse(await readFile(handoffPath, 'utf8')))).toEqual(
expect.objectContaining({
phase: 'failed',
targetVersion: '1.0.61',
reason: expect.stringContaining('reported version 1.0.51')
})
)
}
)
it.runIf(process.platform === 'darwin')(
'records replacement spawn failure before rejecting without a retry loop',
async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-serve-update-spawn-failure-'))
temporaryDirectories.push(root)
const appPath = join(root, 'Orca.app')
const executable = join(appPath, 'Contents', 'MacOS', 'Orca')
const userDataPath = join(root, 'user-data')
await mkdir(join(appPath, 'Contents', 'MacOS'), { recursive: true })
await mkdir(userDataPath, { recursive: true })
await writeFile(
join(appPath, 'Contents', 'Info.plist'),
'CFBundleShortVersionString1.0.61'
)
const handoffPath = getServeUpdateHandoffPath(userDataPath)
await writeFile(
handoffPath,
JSON.stringify({
schemaVersion: 1,
phase: 'install-requested',
fromVersion: '1.0.51',
targetVersion: '1.0.61',
servingPid: 4101
})
)
process.env.ORCA_APP_EXECUTABLE = executable
process.env.ORCA_USER_DATA_PATH = userDataPath
const replacementOwner = new FakeChildProcess()
spawnMock.mockReturnValue(replacementOwner)
vi.spyOn(process.stderr, 'write').mockImplementation(() => true)
const supervisor = serveOrcaApp({ json: true })
await vi.waitFor(() => expect(spawnMock).toHaveBeenCalledOnce())
replacementOwner.emit('error', new Error('spawn ENOENT'))
await expect(supervisor).rejects.toThrow('spawn ENOENT')
expect(spawnMock).toHaveBeenCalledOnce()
expect(parseServeUpdateHandoffState(JSON.parse(await readFile(handoffPath, 'utf8')))).toEqual(
expect.objectContaining({
phase: 'failed',
targetVersion: '1.0.61',
reason: expect.stringContaining('spawn ENOENT')
})
)
}
)
it.runIf(process.platform === 'darwin')(
'fails a replacement that never reports runtime readiness without retrying it',
async () => {
vi.useFakeTimers()
const root = await mkdtemp(join(tmpdir(), 'orca-serve-update-no-readiness-'))
temporaryDirectories.push(root)
const appPath = join(root, 'Orca.app')
const executable = join(appPath, 'Contents', 'MacOS', 'Orca')
const userDataPath = join(root, 'user-data')
await mkdir(join(appPath, 'Contents', 'MacOS'), { recursive: true })
await mkdir(userDataPath, { recursive: true })
await writeFile(
join(appPath, 'Contents', 'Info.plist'),
'CFBundleShortVersionString1.0.61'
)
const handoffPath = getServeUpdateHandoffPath(userDataPath)
await writeFile(
handoffPath,
JSON.stringify({
schemaVersion: 1,
phase: 'install-requested',
fromVersion: '1.0.51',
targetVersion: '1.0.61',
servingPid: 4101
})
)
process.env.ORCA_APP_EXECUTABLE = executable
process.env.ORCA_USER_DATA_PATH = userDataPath
const replacementOwner = new FakeChildProcess()
spawnMock.mockReturnValue(replacementOwner)
vi.spyOn(process.stderr, 'write').mockImplementation(() => true)
try {
const supervisor = serveOrcaApp({ json: true })
await vi.waitFor(() => expect(spawnMock).toHaveBeenCalledOnce())
await vi.advanceTimersByTimeAsync(SERVE_REPLACEMENT_READY_TIMEOUT_MS)
expect(replacementOwner.kill).toHaveBeenCalledWith('SIGTERM')
replacementOwner.emit('exit', 0, null)
await expect(supervisor).resolves.toBe(1)
expect(spawnMock).toHaveBeenCalledOnce()
expect(
parseServeUpdateHandoffState(JSON.parse(await readFile(handoffPath, 'utf8')))
).toEqual(
expect.objectContaining({
phase: 'failed',
reason: expect.stringContaining('did not report serving version')
})
)
} finally {
vi.useRealTimers()
}
}
)
it('pins the Electron child cwd to the app root instead of the caller cwd', async () => {
const child = {
kill: vi.fn(),
once: vi.fn(
(event: string, handler: (code: number | null, signal: string | null) => void) => {
if (event === 'exit') {
queueMicrotask(() => handler(0, null))
}
return child
}
)
}
spawnMock.mockReturnValue(child)
await expect(serveOrcaApp({ json: true })).resolves.toBe(0)
expect(spawnMock).toHaveBeenCalledWith(
'/Applications/Orca.app/Contents/MacOS/Orca',
['--serve', '--serve-json'],
expect.objectContaining({
cwd: resolve(__dirname, '../../..')
})
)
})
it('passes mobile pairing through to the foreground server child', async () => {
const child = {
kill: vi.fn(),
once: vi.fn(
(event: string, handler: (code: number | null, signal: string | null) => void) => {
if (event === 'exit') {
queueMicrotask(() => handler(0, null))
}
return child
}
)
}
spawnMock.mockReturnValue(child)
await expect(
serveOrcaApp({
json: true,
port: '6768',
pairingAddress: '100.64.1.20',
mobilePairing: true
})
).resolves.toBe(0)
expect(spawnMock).toHaveBeenCalledWith(
'/Applications/Orca.app/Contents/MacOS/Orca',
[
'--serve',
'--serve-json',
'--serve-port',
'6768',
'--serve-pairing-address',
'100.64.1.20',
'--serve-mobile-pairing'
],
expect.objectContaining({
cwd: resolve(__dirname, '../../..')
})
)
})
it('passes the app root before serve flags for dev Electron executables', async () => {
process.env.ORCA_APP_EXECUTABLE = '/repo/node_modules/.bin/electron'
process.env.ORCA_APP_EXECUTABLE_NEEDS_APP_ROOT = '1'
const child = {
kill: vi.fn(),
once: vi.fn(
(event: string, handler: (code: number | null, signal: string | null) => void) => {
if (event === 'exit') {
queueMicrotask(() => handler(0, null))
}
return child
}
)
}
spawnMock.mockReturnValue(child)
await expect(serveOrcaApp({ json: true, port: '6768' })).resolves.toBe(0)
expect(spawnMock).toHaveBeenCalledWith(
'/repo/node_modules/.bin/electron',
[resolve(__dirname, '../../..'), '--serve', '--serve-json', '--serve-port', '6768'],
expect.objectContaining({
cwd: resolve(__dirname, '../../..')
})
)
})
it.each([
{ probe: 'exits nonzero', result: { status: 1 }, expectedPrefix: ['--no-sandbox'] },
{ probe: 'succeeds', result: { status: 0 }, expectedPrefix: [] },
{
probe: 'times out',
result: {
status: null,
error: Object.assign(new Error('timed out'), { code: 'ETIMEDOUT' })
},
expectedPrefix: ['--no-sandbox']
},
{
probe: 'cannot start',
result: { status: null, error: Object.assign(new Error('missing'), { code: 'ENOENT' }) },
expectedPrefix: ['--no-sandbox']
}
])(
'uses the extracted AppImage sandbox fallback when the userns probe $probe',
async ({ result: userNamespaceResult, expectedPrefix }) => {
const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform')
const getuidDescriptor = Object.getOwnPropertyDescriptor(process, 'getuid')
const root = await mkdtemp(join(tmpdir(), 'orca-extracted-appimage-'))
temporaryDirectories.push(root)
const executable = join(root, 'orca-ide')
await writeFile(join(root, 'AppRun'), '', { mode: 0o755 })
process.env.ORCA_APP_EXECUTABLE = executable
Object.defineProperty(process, 'platform', { value: 'linux' })
Object.defineProperty(process, 'getuid', { configurable: true, value: () => 1000 })
spawnSyncMock.mockReturnValue(userNamespaceResult)
const child = new FakeChildProcess()
spawnMock.mockReturnValue(child)
try {
const result = serveOrcaApp({ json: true })
queueMicrotask(() => child.emit('exit', 0, null))
await expect(result).resolves.toBe(0)
expect(spawnSyncMock).toHaveBeenCalledWith(
'unshare',
['-Ur', 'true'],
expect.objectContaining({ stdio: 'ignore', timeout: 2_000 })
)
expect(spawnMock).toHaveBeenCalledWith(
executable,
[...expectedPrefix, '--serve', '--serve-json'],
// Foreground serve must share POSIX job-control signals with its CLI supervisor.
expect.objectContaining({ detached: false })
)
} finally {
if (platformDescriptor) {
Object.defineProperty(process, 'platform', platformDescriptor)
}
if (getuidDescriptor) {
Object.defineProperty(process, 'getuid', getuidDescriptor)
} else {
Reflect.deleteProperty(process, 'getuid')
}
}
}
)
it('prints recipe JSON from a detached server child and exits', async () => {
const child = new FakeChildProcess()
spawnMock.mockReturnValue(child)
const writeSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true)
const result = serveOrcaApp({
pairingAddress: 'wss://sandbox.example.com',
recipeJson: true,
projectRoot: '/workspace/repo'
})
queueMicrotask(() => {
child.stdout.emit('data', `${RECIPE_JSON}\n`)
})
await expect(result).resolves.toBe(0)
expect(spawnMock).toHaveBeenCalledWith(
'/Applications/Orca.app/Contents/MacOS/Orca',
[
'--serve',
'--serve-pairing-address',
'wss://sandbox.example.com',
'--serve-recipe-json',
'--serve-project-root',
'/workspace/repo'
],
expect.objectContaining({
cwd: resolve(__dirname, '../../..'),
detached: true,
stdio: ['ignore', 'pipe', 'inherit']
})
)
expect(writeSpy).toHaveBeenCalledWith(`${RECIPE_JSON}\n`)
expect(child.unref).toHaveBeenCalled()
})
it('waits past startup status lines for valid recipe JSON', async () => {
const { child, result, stdoutSpy, stderrSpy } = startRecipeJsonServer()
queueMicrotask(() => {
child.stdout.emit(
'data',
`${SERVE_INSTALL_STATUS}\n${INVALID_SSH_RECIPE_JSON}\n${SSH_RECIPE_JSON}\n${RECIPE_JSON.slice(0, 40)}`
)
child.stdout.emit('data', `${RECIPE_JSON.slice(40)}\n`)
})
await expect(result).resolves.toBe(0)
expect(stderrSpy).toHaveBeenNthCalledWith(1, `${IGNORED_NON_RECIPE_STDOUT}\n`)
expect(stderrSpy).toHaveBeenNthCalledWith(2, `${IGNORED_NON_RECIPE_STDOUT}\n`)
expect(stderrSpy).toHaveBeenNthCalledWith(3, `${IGNORED_NON_RECIPE_STDOUT}\n`)
for (const secret of [SSH_PRIVATE_KEY, SSH_AUTHORIZATION, SSH_PASSPHRASE, SSH_COOKIE]) {
expect(stderrSpy).not.toHaveBeenCalledWith(expect.stringContaining(secret))
}
expect(stdoutSpy).toHaveBeenCalledTimes(1)
expect(stdoutSpy).toHaveBeenCalledWith(`${RECIPE_JSON}\n`)
expect(child.unref).toHaveBeenCalledOnce()
})
it('preserves UTF-8 recipe JSON split across Buffer chunks', async () => {
const { child, result, stdoutSpy } = startRecipeJsonServer()
const unicodeRecipeJson = RECIPE_JSON.replace('/workspace/repo', '/workspace/café')
const recipeBuffer = Buffer.from(`${unicodeRecipeJson}\n`)
const splitIndex = recipeBuffer.indexOf(Buffer.from('é')) + 1
queueMicrotask(() => {
child.stdout.emit('data', recipeBuffer.subarray(0, splitIndex))
child.stdout.emit('data', recipeBuffer.subarray(splitIndex))
})
await expect(result).resolves.toBe(0)
expect(stdoutSpy).toHaveBeenCalledWith(`${unicodeRecipeJson}\n`)
expect(child.unref).toHaveBeenCalledOnce()
})
it('rejects when the server exits without valid recipe JSON', async () => {
const { child, result, stdoutSpy, stderrSpy } = startRecipeJsonServer()
const secrets = ['UPPER-SECRET', 'SLASH-SECRET', 'LEGACY-SECRET', 'PRIVATE-SECRET']
const untrustedLines = [
'ORCA://pair?code=UPPER-SECRET',
'orca://pair/?code=SLASH-SECRET',
'orca://pair#LEGACY-SECRET',
'"embedded privateKey PRIVATE-SECRET"',
'{privateKey:"PRIVATE-SECRET"}'
].join('\n')
queueMicrotask(() => {
child.stdout.emit('data', `${untrustedLines}\n`)
child.emit('exit', 0, null)
child.emit('close', 0, null)
})
await expect(result).rejects.toMatchObject({
code: 'runtime_serve_failed',
message: 'Orca serve exited before printing valid recipe JSON with code 0.'
})
expect(stdoutSpy).not.toHaveBeenCalled()
expect(stderrSpy).toHaveBeenCalledTimes(5)
expect(stderrSpy).toHaveBeenCalledWith(`${IGNORED_NON_RECIPE_STDOUT}\n`)
for (const secret of secrets) {
expect(stderrSpy).not.toHaveBeenCalledWith(expect.stringContaining(secret))
}
expect(child.unref).not.toHaveBeenCalled()
})
it('accepts valid recipe JSON at exit without a trailing newline', async () => {
const { child, result, stdoutSpy } = startRecipeJsonServer()
queueMicrotask(() => {
child.emit('exit', 0, null)
child.stdout.emit('data', RECIPE_JSON)
child.emit('close', 0, null)
})
await expect(result).resolves.toBe(0)
expect(stdoutSpy).toHaveBeenCalledWith(`${RECIPE_JSON}\n`)
expect(child.unref).toHaveBeenCalledOnce()
})
it('uses a shell when a Windows npm command shim is the Electron executable', async () => {
const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform')
Object.defineProperty(process, 'platform', { value: 'win32' })
process.env.ORCA_APP_EXECUTABLE = 'C:\\repo\\node_modules\\.bin\\electron.cmd'
const child = {
kill: vi.fn(),
once: vi.fn(
(event: string, handler: (code: number | null, signal: string | null) => void) => {
if (event === 'exit') {
queueMicrotask(() => handler(0, null))
}
return child
}
)
}
spawnMock.mockReturnValue(child)
try {
await expect(serveOrcaApp({ json: true })).resolves.toBe(0)
expect(spawnMock).toHaveBeenCalledWith(
'C:\\repo\\node_modules\\.bin\\electron.cmd',
['--serve', '--serve-json'],
expect.objectContaining({
shell: true
})
)
} finally {
if (platformDescriptor) {
Object.defineProperty(process, 'platform', platformDescriptor)
}
}
})
})
describe('launchOrcaApp', () => {
beforeEach(() => {
spawnMock.mockReset()
spawnSyncMock.mockReset()
})
afterEach(() => {
delete process.env.ORCA_OPEN_COMMAND
delete process.env.ORCA_APP_EXECUTABLE
delete process.env.ORCA_APP_EXECUTABLE_NEEDS_APP_ROOT
})
it('handles asynchronous detached spawn errors without throwing', async () => {
process.env.ORCA_APP_EXECUTABLE = '/missing/Orca'
const child = new FakeChildProcess()
spawnMock.mockReturnValue(child)
launchOrcaApp()
child.emit('error', new Error('ENOENT'))
await Promise.resolve()
expect(child.unref).toHaveBeenCalled()
})
it('adds the extracted-AppImage sandbox fallback for open launches', async () => {
const platformDescriptor = Object.getOwnPropertyDescriptor(process, 'platform')
const getuidDescriptor = Object.getOwnPropertyDescriptor(process, 'getuid')
const root = await mkdtemp(join(tmpdir(), 'orca-open-extracted-appimage-'))
const executable = join(root, 'orca-ide')
try {
await writeFile(join(root, 'AppRun'), '')
process.env.ORCA_APP_EXECUTABLE = executable
process.env.ELECTRON_RUN_AS_NODE = '1'
Object.defineProperty(process, 'platform', { configurable: true, value: 'linux' })
Object.defineProperty(process, 'getuid', { configurable: true, value: () => 1000 })
spawnSyncMock.mockReturnValue({ status: 1 })
const child = new FakeChildProcess()
spawnMock.mockReturnValue(child)
launchOrcaApp()
expect(spawnSyncMock).toHaveBeenCalledWith(
'unshare',
['-Ur', 'true'],
expect.objectContaining({ stdio: 'ignore', timeout: 2_000 })
)
expect(spawnMock).toHaveBeenCalledWith(
executable,
['--no-sandbox'],
expect.objectContaining({
detached: true,
stdio: 'ignore',
env: expect.not.objectContaining({ ELECTRON_RUN_AS_NODE: '1' })
})
)
expect(child.unref).toHaveBeenCalledOnce()
} finally {
await rm(root, { recursive: true, force: true })
delete process.env.ELECTRON_RUN_AS_NODE
if (platformDescriptor) {
Object.defineProperty(process, 'platform', platformDescriptor)
}
if (getuidDescriptor) {
Object.defineProperty(process, 'getuid', getuidDescriptor)
} else {
Reflect.deleteProperty(process, 'getuid')
}
}
})
})