import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test" import type { Server } from "bun" import { app } from "../src/app" import { config } from "../src/config" import { all } from "../src/db" import { upgrade, websocket, type WsData } from "../src/ws" import { client, freshDb, makeTask, makeUser } from "./helpers" // 假的模型接口:每段之间停一下,方便测试中途断开 const PIECES = ["好的", "```html\n
hi
\n```"] const llm = Bun.serve({ port: 0, fetch() { const enc = new TextEncoder() const stream = new ReadableStream({ async start(ctrl) { for (const piece of PIECES) { ctrl.enqueue(enc.encode(`data: ${JSON.stringify({ choices: [{ delta: { content: piece } }] })}\n\n`)) await Bun.sleep(150) } ctrl.enqueue(enc.encode("data: [DONE]\n\n")) ctrl.close() }, }) return new Response(stream, { headers: { "content-type": "text/event-stream" } }) }, }) let server: Serverhi
") const streamed = c.msgs.filter((m) => m.type === "stream").map((m) => m.content).join("") expect(streamed).toBe(PIECES.join("")) expect(all(`SELECT role FROM prompt_message ORDER BY id`).map((m) => m.role)).toEqual(["user", "assistant"]) c.ws.close() }) test("AI 回复中再发消息会被拒绝", async () => { const { task, token } = await setup() const c = (await connect(`/ws/prompt/${task}/?token=${token}`))! await c.next("init") c.ws.send(JSON.stringify({ type: "message", content: "第一条" })) c.ws.send(JSON.stringify({ type: "message", content: "第二条" })) expect((await c.next("error")).content).toContain("上一条消息还在处理") await c.next("complete") expect(all(`SELECT content FROM prompt_message WHERE role = 'user'`)).toEqual([{ content: "第一条" }]) c.ws.close() }) test("中途断开:删掉没有回复的提问", async () => { const { task, token } = await setup() const c = (await connect(`/ws/prompt/${task}/?token=${token}`))! await c.next("init") c.ws.send(JSON.stringify({ type: "message", content: "做个页面" })) await c.next("stream") c.ws.close() await Bun.sleep(400) expect(all(`SELECT * FROM prompt_message`)).toEqual([]) }) test("token 无效或任务不存在时握手失败", async () => { const { task, token } = await setup() expect(await connect(`/ws/prompt/${task}/?token=bad`)).toBeNull() expect(await connect(`/ws/prompt/9999/?token=${token}`)).toBeNull() }) })