54 lines
2.2 KiB
TypeScript
54 lines
2.2 KiB
TypeScript
// 不自动运行(需要 npm install 后执行 node --test app.test.ts)
|
||
import assert from "node:assert/strict";
|
||
import type { AddressInfo } from "node:net";
|
||
import { after, before, test } from "node:test";
|
||
import { createApp } from "./app.ts";
|
||
|
||
let base = "";
|
||
let close: () => void = () => {};
|
||
|
||
before(async () => {
|
||
const app = createApp({
|
||
async *askLLM(q) {
|
||
if (q === "boom") throw new Error("upstream down");
|
||
yield "你好";
|
||
yield q;
|
||
},
|
||
findOrder: async (id) => (id === "A001" ? { id, status: "paid" } : null),
|
||
});
|
||
const server = app.listen(0);
|
||
await new Promise((r) => server.once("listening", r));
|
||
base = `http://127.0.0.1:${(server.address() as AddressInfo).port}`;
|
||
close = () => server.close();
|
||
});
|
||
after(() => close());
|
||
|
||
test("查询订单:正常 / 格式错误 / 不存在", async () => {
|
||
assert.deepEqual(await (await fetch(`${base}/orders/A001`)).json(), { id: "A001", status: "paid" });
|
||
const bad = await fetch(`${base}/orders/xx`);
|
||
assert.equal(bad.status, 400);
|
||
assert.equal((await bad.json()).code, "BAD_ORDER_ID");
|
||
const missing = await fetch(`${base}/orders/A999`);
|
||
assert.equal(missing.status, 404);
|
||
assert.ok(missing.headers.get("x-request-id"));
|
||
});
|
||
|
||
test("请求体不是合法 JSON 时返回 400 而不是 500", async () => {
|
||
const r = await fetch(`${base}/chat`, { method: "POST", headers: { "content-type": "application/json" }, body: "{bad" });
|
||
assert.equal(r.status, 400);
|
||
});
|
||
|
||
test("流式对话:逐条 SSE 事件,最后是 done", async () => {
|
||
const r = await fetch(`${base}/chat`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ question: "退货" }) });
|
||
assert.match(r.headers.get("content-type") ?? "", /^text\/event-stream/); // express 会追加 charset
|
||
const text = await r.text();
|
||
assert.match(text, /data: \{"token":"你好"\}/);
|
||
assert.match(text, /data: \{"token":"退货"\}/);
|
||
assert.match(text, /event: done/);
|
||
});
|
||
|
||
test("上游失败:用 error 事件通知,而不是挂起连接", async () => {
|
||
const r = await fetch(`${base}/chat`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ question: "boom" }) });
|
||
assert.match(await r.text(), /event: error/);
|
||
});
|