60 lines
1.7 KiB
TypeScript
60 lines
1.7 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { streamRunEvents, type RunEvent } from '@/api/hermes/chat'
|
|
|
|
class MockEventSource {
|
|
static instances: MockEventSource[] = []
|
|
|
|
url: string
|
|
onmessage: ((event: { data: string }) => void) | null = null
|
|
onerror: (() => void) | null = null
|
|
close = vi.fn()
|
|
|
|
constructor(url: string) {
|
|
this.url = url
|
|
MockEventSource.instances.push(this)
|
|
}
|
|
|
|
emit(data: string) {
|
|
this.onmessage?.({ data })
|
|
}
|
|
|
|
fail() {
|
|
this.onerror?.()
|
|
}
|
|
}
|
|
|
|
describe('streamRunEvents', () => {
|
|
beforeEach(() => {
|
|
window.localStorage.clear()
|
|
MockEventSource.instances = []
|
|
vi.stubGlobal('EventSource', MockEventSource)
|
|
})
|
|
|
|
it('maps non-JSON EventSource data to message.delta so raw text is rendered', () => {
|
|
const events: RunEvent[] = []
|
|
|
|
streamRunEvents('run-raw', event => events.push(event), vi.fn(), vi.fn())
|
|
MockEventSource.instances[0].emit('原因:raw fallback')
|
|
|
|
expect(events).toEqual([{ event: 'message.delta', delta: '原因:raw fallback' }])
|
|
})
|
|
|
|
it('parses colon-containing JSON deltas and closes on completion', () => {
|
|
const events: RunEvent[] = []
|
|
const onDone = vi.fn()
|
|
|
|
streamRunEvents('run-json', event => events.push(event), onDone, vi.fn())
|
|
const source = MockEventSource.instances[0]
|
|
source.emit(JSON.stringify({ event: 'message.delta', delta: '让我直接读文件:A: B' }))
|
|
source.emit(JSON.stringify({ event: 'run.completed' }))
|
|
|
|
expect(events).toEqual([
|
|
{ event: 'message.delta', delta: '让我直接读文件:A: B' },
|
|
{ event: 'run.completed' },
|
|
])
|
|
expect(source.close).toHaveBeenCalledTimes(1)
|
|
expect(onDone).toHaveBeenCalledTimes(1)
|
|
})
|
|
})
|