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({ 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()).toContain("Mentor mode off: I'll give full answers"); expect(renderToString()).toBe(""); expect(renderToString()).toBe(""); }); test("markdown renders code and text without raw HTML", () => { const html = renderToString(two"} />); expect(html).toContain("this"); expect(html).toContain('
');
  expect(html).toContain("const a = 1 < 2");
  expect(html).toContain("x");
  expect(html).toContain("<b>two</b>");
});

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

test("lesson links go through one builder", async () => {
  const { lessonUrl, courseUrl } = await import("../src/web/urls");
  expect(lessonUrl("sample", "m2-ex-add")).toBe("/c/sample/m2-ex-add");
  expect(lessonUrl("S08 - Docker", "l 1/x")).toBe("/c/S08%20-%20Docker/l%201%2Fx");
  expect(courseUrl("sample")).toBe("/c/sample");
  const src = await Bun.file(new URL("../src/web/AssistantPage.tsx", import.meta.url)).text();
  expect(src).toContain("lessonUrl(courseId, c.lessonId)");
  expect(src).not.toMatch(/`\/c\//);
});