Why: Full execution history must retain outputs after the 500-event API page boundary. Evidence: Ordered 502-event replay and nonadvancing-cursor rejection tests pass. Impact: Add regression coverage only; production source is unchanged. Refs: feature/workbench-flow-completion review testing gap
27 lines
1.5 KiB
TypeScript
27 lines
1.5 KiB
TypeScript
import { afterEach, expect, it, vi } from 'vitest'
|
|
import { api } from '../src/api'
|
|
import { loadRunEvents } from '../src/runEvents'
|
|
import type { StreamEvent } from '../src/contracts'
|
|
|
|
afterEach(() => vi.restoreAllMocks())
|
|
function event(seq: number): StreamEvent {
|
|
return { seq, type: 'message.delta', runId: 'run', conversationId: 'conversation', ts: '2026-10-15T07:00:00Z', v: 1, payload: { index: 0, text: `已保存输出${seq}` } }
|
|
}
|
|
|
|
it('reads a complete saved record across the 500-event boundary in order', async () => {
|
|
const query = vi.spyOn(api, 'runEventsPage')
|
|
.mockResolvedValueOnce({ events: Array.from({ length: 500 }, (_, i) => event(i + 1)) })
|
|
.mockResolvedValueOnce({ events: [event(501), event(502)] })
|
|
const controller = new AbortController()
|
|
const result = await loadRunEvents('conversation', 'run', controller.signal)
|
|
expect(result.map(item => item.seq)).toEqual(Array.from({ length: 502 }, (_, i) => i + 1))
|
|
expect(query).toHaveBeenNthCalledWith(1, 'conversation', 'run', 0, controller.signal)
|
|
expect(query).toHaveBeenNthCalledWith(2, 'conversation', 'run', 500, controller.signal)
|
|
})
|
|
|
|
it('stops an invalid nonadvancing record cursor instead of fetching forever', async () => {
|
|
const query = vi.spyOn(api, 'runEventsPage').mockResolvedValue({ events: Array.from({ length: 500 }, (_, i) => event(i + 1)) })
|
|
await expect(loadRunEvents('conversation', 'run', new AbortController().signal)).rejects.toThrow('cursor did not advance')
|
|
expect(query).toHaveBeenCalledTimes(2)
|
|
})
|