test(aimlapi): drive polling retries with fake timers (#2393)

* test(aimlapi): drive polling retries with fake timers

* test(aimlapi): await rate-limit retry timer registration
This commit is contained in:
JATMN
2026-10-24 09:53:31 -07:00
committed by GitHub
parent 1a79295216
commit cd350528f6
+30 -5
View File
@@ -1,4 +1,4 @@
import { afterAll, afterEach, expect, mock, test } from 'bun:test'
import { afterAll, afterEach, expect, jest, mock, test } from 'bun:test'
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
@@ -78,6 +78,7 @@ afterAll(() => {
})
afterEach(() => {
jest.useRealTimers()
globalThis.fetch = originalFetch
lastSavedProfileEnv = undefined
setClaudeConfigHomeDirForTesting(undefined)
@@ -1950,6 +1951,7 @@ test('a terminal poll error awaits onSession before rejecting, not racing ahead
})
test('polling retries a transient transport failure', async () => {
jest.useFakeTimers()
process.env.AIMLAPI_APP_URL = 'https://app.example.test'
let attempts = 0
globalThis.fetch = mock(async () => {
@@ -1965,13 +1967,22 @@ test('polling retries a transient transport failure', async () => {
verificationBaseUrl: 'https://front.example.test',
})
await expect(pollUntilPaid(client, 'session')).resolves.toEqual(
const polling = pollUntilPaid(client, 'session')
// Let the failed request schedule its retry before advancing the poll timer.
await new Promise<void>(resolve => setImmediate(resolve))
jest.advanceTimersByTime(2999)
await new Promise<void>(resolve => setImmediate(resolve))
expect(attempts).toBe(1)
jest.advanceTimersByTime(1)
await expect(polling).resolves.toEqual(
expect.objectContaining({ status: 'paid' }),
)
expect(attempts).toBe(2)
})
test('polling retains and retries the same session after a rate limit', async () => {
jest.useFakeTimers()
process.env.AIMLAPI_APP_URL = 'https://app.example.test'
let attempts = 0
globalThis.fetch = mock(async () => {
@@ -1988,9 +1999,23 @@ test('polling retains and retries the same session after a rate limit', async ()
})
const sessions: string[] = []
await expect(
pollUntilPaid(client, 'session', undefined, value => { sessions.push(value) }),
).resolves.toEqual(expect.objectContaining({ status: 'paid' }))
const setTimeoutSpy = jest.spyOn(globalThis, 'setTimeout')
const polling = pollUntilPaid(client, 'session', undefined, value => { sessions.push(value) })
try {
// Reading the 429 body may take multiple turns before the retry is scheduled.
for (let tick = 0; tick < 100 && !setTimeoutSpy.mock.calls.some(call => call[1] === 3000); tick++) {
await new Promise<void>(resolve => setImmediate(resolve))
}
expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), 3000)
} finally {
setTimeoutSpy.mockRestore()
}
jest.advanceTimersByTime(2999)
await new Promise<void>(resolve => setImmediate(resolve))
expect(attempts).toBe(1)
jest.advanceTimersByTime(1)
await expect(polling).resolves.toEqual(expect.objectContaining({ status: 'paid' }))
expect(attempts).toBe(2)
expect(sessions).toEqual([])
})