diff --git a/scripts/openclaude-bin-heap.test.ts b/scripts/openclaude-bin-heap.test.ts index 51a008455..65b8cceb5 100644 --- a/scripts/openclaude-bin-heap.test.ts +++ b/scripts/openclaude-bin-heap.test.ts @@ -72,6 +72,7 @@ describe('openclaude launcher heap guard', () => { expect(source).not.toMatch(/import\s*\{[^}]*enableCompileCache[^}]*\}\s*from\s*['"]node:module['"]/s) }) + // Real CLI startup has an 8s child deadline; allow time to assert its result. test('strips launcher-only percentage before Commander when native heap and expose-gc are present', () => { const env = { ...process.env, @@ -98,8 +99,9 @@ describe('openclaude launcher heap guard', () => { expect(output).not.toContain( "unknown option '--max-old-space-size-percentage=50'", ) - }) + }, 10_000) + // Real CLI startup has an 8s child deadline; allow time to assert its result. test('strips launcher-only percentage before Commander when heap relaunch is disabled', () => { const env = { ...process.env, @@ -120,8 +122,9 @@ describe('openclaude launcher heap guard', () => { expect(output).not.toContain( "unknown option '--max-old-space-size-percentage=50'", ) - }) + }, 10_000) + // Real CLI startup has an 8s child deadline; allow time to assert its result. test('strips launcher-only percentage when OPENCLAUDE_HEAP_RELAUNCHED is already set', () => { const env = { ...process.env, @@ -142,7 +145,7 @@ describe('openclaude launcher heap guard', () => { expect(output).not.toContain( "unknown option '--max-old-space-size-percentage=50'", ) - }) + }, 10_000) }) describe('heap-limit percentage resolution', () => { diff --git a/src/cli/bgFinalizer.test.ts b/src/cli/bgFinalizer.test.ts index fdc51937a..5c1679648 100644 --- a/src/cli/bgFinalizer.test.ts +++ b/src/cli/bgFinalizer.test.ts @@ -633,8 +633,8 @@ describe('background session finalizer', () => { return { id, child, readyPath } } - async function waitForFile(path: string): Promise { - for (let attempt = 0; attempt < 500; attempt += 1) { + async function waitForFile(path: string, attempts: number = 500): Promise { + for (let attempt = 0; attempt < attempts; attempt += 1) { if (await Bun.file(path).exists()) return await new Promise(resolve => setTimeout(resolve, 10)) } @@ -967,6 +967,7 @@ describe('background session finalizer', () => { async function runWaitingDetachedLaunch( name: string, fixtureEnv: NodeJS.ProcessEnv = {}, + readinessAttempts?: number, ): Promise<{ id: string; childPid: number; readyPath: string }> { const readyPath = join(configDir, `${name}.ready`) const launcher = spawn( @@ -1017,7 +1018,7 @@ describe('background session finalizer', () => { if (!id || childPid === undefined) { throw new Error('detached wait launch omitted its session identity') } - await waitForFile(readyPath) + await waitForFile(readyPath, readinessAttempts) ownershipTransferred = true return { id, childPid, readyPath } } finally { @@ -1044,6 +1045,9 @@ describe('background session finalizer', () => { env: { OPENCLAUDE_BG_FINALIZER_FIXTURE_SKIP_READY: '1', }, + // Readiness is deliberately suppressed; only exercise the failure path. + readinessAttempts: 25, + expectedError: 'fixture readiness file was not created', }, ]) { it( @@ -1051,8 +1055,8 @@ describe('background session finalizer', () => { async () => { const name = `failed-handoff-${scenario.label.replaceAll(' ', '-')}` await expect( - runWaitingDetachedLaunch(name, scenario.env), - ).rejects.toThrow() + runWaitingDetachedLaunch(name, scenario.env, scenario.readinessAttempts), + ).rejects.toThrow(scenario.expectedError) const session = (await listBackgroundSessions()).find( candidate => candidate.name === name, ) diff --git a/src/cli/printMaxTurns.test.ts b/src/cli/printMaxTurns.test.ts index a18bc682b..8f1855e1a 100644 --- a/src/cli/printMaxTurns.test.ts +++ b/src/cli/printMaxTurns.test.ts @@ -135,18 +135,6 @@ function createHeadlessRunOptions(maxTurns: number | undefined) { } } -async function waitForAskCall( - askSpy: ReturnType>, -): Promise { - const deadline = Date.now() + 15_000 - while (askSpy.mock.calls.length === 0) { - if (Date.now() >= deadline) { - throw new Error('Timed out waiting for runHeadless to call ask()') - } - await new Promise(resolve => setTimeout(resolve, 25)) - } -} - describe('headless --print max-turns', () => { const savedSimple = process.env.CLAUDE_CODE_SIMPLE @@ -213,9 +201,8 @@ describe('headless --print max-turns', () => { createHeadlessRunOptions(0), ) - await waitForAskCall(askSpy) - expect(askSpy.mock.calls[0]?.[0]?.maxTurns).toBe(0) await runPromise + expect(askSpy.mock.calls[0]?.[0]?.maxTurns).toBe(0) expect(shutdownSpy).toHaveBeenCalledWith(0) } finally { await runPromise?.catch(() => {}) diff --git a/src/components/PromptInput/utils.test.ts b/src/components/PromptInput/utils.test.ts index 39f35d630..0b078c629 100644 --- a/src/components/PromptInput/utils.test.ts +++ b/src/components/PromptInput/utils.test.ts @@ -119,7 +119,7 @@ test.each([ /** Observes the real hook after mounting its AppState provider. */ function HookProbe() { observedBanner = useSwarmBanner() - React.useEffect(() => { notifyRendered() }, []) + React.useLayoutEffect(() => { notifyRendered() }, []) return null }