Files
STCourses/packages/feature-ai/test/web.test.tsx
T

37 lines
1.8 KiB
TypeScript

import { expect, test } from "bun:test";
import { renderToString } from "react-dom/server";
import { readNdjson } from "../src/web/api";
import { MentorBanner, Markdown } from "../src/web/components";
import { aiWeb } from "../src/web";
test("readNdjson splits events across chunk boundaries", async () => {
const text = '{"type":"meta","n":1}\n{"type":"text","text":"héllo"}\n{"type":"done"}\n';
const bytes = new TextEncoder().encode(text);
const stream = new ReadableStream<Uint8Array>({
start(c) { for (let i = 0; i < bytes.length; i += 5) c.enqueue(bytes.slice(i, i + 5)); c.close(); },
});
const out: unknown[] = [];
for await (const ev of readNdjson(stream)) out.push(ev);
expect(out).toEqual([{ type: "meta", n: 1 }, { type: "text", text: "héllo" }, { type: "done" }]);
});
test("the mentor banner says so plainly when mentor mode is off", () => {
expect(renderToString(<MentorBanner on={false} available />)).toContain("Mentor mode off: I&#x27;ll give full answers");
expect(renderToString(<MentorBanner on available />)).toBe("");
expect(renderToString(<MentorBanner on={false} available={false} />)).toBe("");
});
test("markdown renders code and text without raw HTML", () => {
const html = renderToString(<Markdown text={"Use **this**:\n\n```js\nconst a = 1 < 2\n```\n\n- one `x`\n- <b>two</b>"} />);
expect(html).toContain("<strong>this</strong>");
expect(html).toContain('<pre class="code">');
expect(html).toContain("const a = 1 &lt; 2");
expect(html).toContain("<code>x</code>");
expect(html).toContain("&lt;b&gt;two&lt;/b&gt;");
});
test("web routes", () => {
expect(aiWeb.routes.map((r) => r.path)).toEqual(["/c/:courseId/assistant", "/admin/ai", "/account/ai", "/studio/generate"]);
expect(aiWeb.routes.find((r) => r.path === "/admin/ai")!.nav).toEqual({ label: "AI", area: "admin" });
});