Files
Hermes-ui/tests/client/chat-api.test.ts
T

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)
})
})