test(native-chat): name the stalled step in the live-history watcher test (#34663)

* test(native-chat): name the stalled step in the live-history watcher test

A CI run hit the 30 s test timeout with no step named. Each wait now has its
own 8 s deadline that reports the stalled step with what the watcher had
delivered, and the file sets IS_REACT_ACT_ENVIRONMENT so act() flushes.

* test(native-chat): share one 27 s budget across the live-history waits

Per-step 8 s deadlines were stricter than the old 30 s test timeout; a shared
deadline keeps the total unchanged and only improves the failure message.

* test(native-chat): use an AbortSignal budget instead of the wall clock

Date.now trips the flaky-test wall-clock rule; AbortSignal.timeout gives the
same shared 27 s budget without reading the clock.
This commit is contained in:
Neil
2026-10-27 19:13:52 -07:00
committed by GitHub
parent ef6e661449
commit 2893d06533
@@ -67,6 +67,8 @@ describe('useNativeChatLiveSession — file watcher pagination composition', ()
}
beforeEach(() => {
// Without it React warns on every act() and may not flush updates inside it.
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true)
useAppStore.setState({ agentStatusByPaneKey: {} })
})
@@ -76,10 +78,13 @@ describe('useNativeChatLiveSession — file watcher pagination composition', ()
}
latest = null
vi.clearAllMocks()
vi.unstubAllGlobals()
resetTransport()
})
it('keeps the original watcher append after a real 300-to-500 loadEarlier', async () => {
// One budget shared by every step, just under the 30 s test timeout, so only the message changes.
const budget = AbortSignal.timeout(27_000)
const { mkdtemp, writeFile, appendFile, rm } = await import('node:fs/promises')
const { tmpdir } = await import('node:os')
const { join } = await import('node:path')
@@ -120,6 +125,28 @@ describe('useNativeChatLiveSession — file watcher pagination composition', ()
sessionId: SESSION,
runtimeEnvironmentId: 'env-history'
})
// A CI run hit the 30 s test timeout with no step named; each wait names its own stall.
const delivered: string[] = []
const within = <T>(step: string, promise: Promise<T>): Promise<T> =>
Promise.race([
promise,
new Promise<never>((_, reject) => {
const stalled = (): void => {
const rows = latest ? ids().length : null
const limits = transport.readSession.mock.calls.map((call) => call[2])
reject(
new Error(
`Stalled at ${step}: ${JSON.stringify({ delivered, rows, readSessionLimits: limits })}`
)
)
}
if (budget.aborted) {
stalled()
} else {
budget.addEventListener('abort', stalled, { once: true })
}
})
])
const initialSnapshotCommitted = Promise.withResolvers<void>()
const appendCommitted = Promise.withResolvers<void>()
const subscription = await subscribeNativeChatTranscript({
@@ -131,28 +158,34 @@ describe('useNativeChatLiveSession — file watcher pagination composition', ()
debounceMs: 5,
reconciliationIntervalMs: 20,
onInitialSnapshot: (messages, hasMore) => {
delivered.push(`snapshot:${messages.length}`)
void act(async () => {
transport.emit({ type: 'snapshot', messages, hasMore })
}).then(initialSnapshotCommitted.resolve, initialSnapshotCommitted.reject)
},
onAppend: (messages) => {
delivered.push(`append:${messages.length}`)
void act(async () => {
transport.emit({ type: 'appended', messages })
}).then(appendCommitted.resolve, appendCommitted.reject)
},
onReplace: (messages, hasMore) =>
act(() => transport.emit({ type: 'replacement', messages, hasMore }))
onReplace: (messages, hasMore) => {
delivered.push(`replace:${messages.length}`)
return act(() => transport.emit({ type: 'replacement', messages, hasMore }))
}
})
try {
await initialSnapshotCommitted.promise
await within('initial snapshot', initialSnapshotCommitted.promise)
expect(ids()).toEqual(Array.from({ length: 300 }, (_, i) => String(i + 201).padStart(4, '0')))
await act(async () => {
await expect(session().loadEarlier()).resolves.toBe('applied')
await expect(within('loadEarlier 300 to 500', session().loadEarlier())).resolves.toBe(
'applied'
)
})
expect(transport.readSession).toHaveBeenLastCalledWith(AGENT, SESSION, 500, undefined)
expect(ids()).toEqual(Array.from({ length: 500 }, (_, i) => String(i + 1).padStart(4, '0')))
await appendFile(filePath, line(501))
await appendCommitted.promise
await within('watcher append of line 501', appendCommitted.promise)
expect(ids()).toEqual(Array.from({ length: 501 }, (_, i) => String(i + 1).padStart(4, '0')))
expect(ids().at(-1)).toBe('0501')
expect(transport.subscribe).toHaveBeenCalledOnce()