Skip to content
File

Blob: tests/client/lib/ai/blocks.test.ts

typescript70 lines
1import { describe, expect, it } from "vitest";
2import { parseAiBlocksFromText, isSingleInlineParagraph, getInlineTextFromParagraph } from "@/client/lib/ai/blocks";
3 
4describe("parseAiBlocksFromText", () => {
5 it("returns no blocks for empty or whitespace-only input", () => {
6 expect(parseAiBlocksFromText("")).toEqual([]);
7 expect(parseAiBlocksFromText(" \n \n")).toEqual([]);
8 });
9 
10 it("collapses a single paragraph into one inline paragraph", () => {
11 const blocks = parseAiBlocksFromText("Hello world.");
12 expect(blocks).toHaveLength(1);
13 expect(isSingleInlineParagraph(blocks)).toBe(true);
14 expect(getInlineTextFromParagraph(blocks[0])).toBe("Hello world.");
15 });
16 
17 it("joins soft line breaks within a paragraph with spaces", () => {
18 const blocks = parseAiBlocksFromText("Line one\nLine two");
19 expect(blocks).toHaveLength(1);
20 expect(getInlineTextFromParagraph(blocks[0])).toBe("Line one Line two");
21 });
22 
23 it("splits paragraphs on double newline", () => {
24 const blocks = parseAiBlocksFromText("First paragraph.\n\nSecond paragraph.");
25 expect(blocks).toHaveLength(2);
26 expect(blocks[0]).toEqual({ type: "paragraph", content: [{ type: "text", text: "First paragraph." }] });
27 expect(blocks[1]).toEqual({ type: "paragraph", content: [{ type: "text", text: "Second paragraph." }] });
28 });
29 
30 it("groups adjacent bullet lines into a bulletList", () => {
31 const blocks = parseAiBlocksFromText("- First idea\n- Second idea\n- Third idea");
32 expect(blocks).toHaveLength(1);
33 expect(blocks[0]).toEqual({
34 type: "bulletList",
35 content: [
36 { type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "First idea" }] }] },
37 { type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "Second idea" }] }] },
38 { type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "Third idea" }] }] },
39 ],
40 });
41 });
42 
43 it("accepts asterisk bullet markers", () => {
44 const blocks = parseAiBlocksFromText("* alpha\n* beta");
45 expect(blocks[0]).toMatchObject({ type: "bulletList" });
46 if (blocks[0].type === "bulletList") {
47 expect(blocks[0].content).toHaveLength(2);
48 }
49 });
50 
51 it("preserves paragraph + bullet list mix", () => {
52 const blocks = parseAiBlocksFromText("Intro sentence.\n\n- one\n- two\n\nOutro sentence.");
53 expect(blocks).toHaveLength(3);
54 expect(blocks[0]).toMatchObject({ type: "paragraph" });
55 expect(blocks[1]).toMatchObject({ type: "bulletList" });
56 expect(blocks[2]).toMatchObject({ type: "paragraph" });
57 });
58 
59 it("does not treat mixed non-bullet lines as a bullet list", () => {
60 const blocks = parseAiBlocksFromText("- not a list\nregular text");
61 expect(blocks).toHaveLength(1);
62 expect(blocks[0]).toMatchObject({ type: "paragraph" });
63 });
64 
65 it("normalizes CRLF line endings", () => {
66 const blocks = parseAiBlocksFromText("First.\r\n\r\nSecond.");
67 expect(blocks).toHaveLength(2);
68 });
69});