import { ProcessEventBuffer, RuntimeProcessEvent } from '../src/modules/netaclaw/runtime/process_events'; function event(input: Partial = {}): RuntimeProcessEvent { return { version: 1, operationId: 'tool-call-1', targetType: 'tool', source: 'tool', status: 'running', level: 'info', message: 'working', timestamp: '2026-05-06T00:00:00.000Z', ...input, }; } describe('ProcessEventBuffer', () => { beforeEach(() => { jest.useFakeTimers(); }); afterEach(() => { jest.useRealTimers(); }); it('coalesces repeated non-terminal events until throttle flush', () => { const emitted: RuntimeProcessEvent[] = []; const buffer = new ProcessEventBuffer(item => emitted.push(item), { throttleMs: 100 }); buffer.push(event({ current: 1, total: 3 })); buffer.push(event({ current: 2, total: 3 })); expect(emitted).toEqual([]); jest.advanceTimersByTime(100); expect(emitted).toEqual([ expect.objectContaining({ current: 2, payload: { repeatCount: 2 }, }), ]); }); it('flushes pending operation events before terminal events', () => { const emitted: RuntimeProcessEvent[] = []; const buffer = new ProcessEventBuffer(item => emitted.push(item), { throttleMs: 100 }); buffer.push(event({ current: 1, total: 2 })); buffer.push(event({ status: 'failed', level: 'error', message: 'failed' })); expect(emitted).toEqual([ expect.objectContaining({ current: 1 }), expect.objectContaining({ status: 'failed', message: 'failed' }), ]); }); });