import { describe, expect, it } from 'vitest'; import { parseSseChunk } from '../../src/api/sse'; describe('parseSseChunk', () => { it('parses named SSE events with JSON data and preserves remainder', () => { const result = parseSseChunk('', 'event: message_delta\ndata: {"text":"好的"}\n\npartial'); expect(result.events).toEqual([{ type: 'message_delta', data: { text: '好的' } }]); expect(result.remainder).toBe('partial'); }); it('accumulates across multiple chunks', () => { const first = parseSseChunk('', 'event: message_delta\ndata: {"text":"好'); expect(first.events).toEqual([]); expect(first.remainder).toBe('event: message_delta\ndata: {"text":"好'); const second = parseSseChunk(first.remainder, '的"}\n\n'); expect(second.events).toEqual([{ type: 'message_delta', data: { text: '好的' } }]); expect(second.remainder).toBe(''); }); it('handles multiple events in one chunk', () => { const result = parseSseChunk('', 'event: task_updated\ndata: {"taskId":"1"}\n\nevent: card_created\ndata: {"cardId":"c1"}\n\n'); expect(result.events).toHaveLength(2); expect(result.events[0]).toEqual({ type: 'task_updated', data: { taskId: '1' } }); expect(result.events[1]).toEqual({ type: 'card_created', data: { cardId: 'c1' } }); }); it('ignores malformed data events without throwing', () => { const result = parseSseChunk('', 'event: error\ndata: not-json\n\n'); expect(result.events).toEqual([{ type: 'error', data: { message: 'SSE 数据解析失败' } }]); }); it('skips events without both event and data lines', () => { const result = parseSseChunk('', 'event: something\n\n'); expect(result.events).toEqual([]); expect(result.remainder).toBe(''); }); it('handles all six SSE event types', () => { const types = ['task_updated', 'message_delta', 'message_completed', 'card_created', 'error', 'completed']; for (const type of types) { const result = parseSseChunk('', `event: ${type}\ndata: {"key":"val"}\n\n`); expect(result.events[0].type).toBe(type); } }); });