File size: 4,618 Bytes
f778c12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Tests exported tool output lines across plain and highlighted preview limits.
import { describe, expect, it } from "vitest";
import {
  now,
  renderTemplate,
  requireElement,
  type SessionEntry,
} from "../../../../test/helpers/export-html-template.js";

describe("export html tool output lines", () => {
  it.each([
    { name: "bash", filePath: "", maxLines: 5, code: false },
    { name: "custom", filePath: "", maxLines: 10, code: false },
    { name: "bashExecution", filePath: "", maxLines: 10, code: false },
    { name: "read", filePath: "sample.ts", maxLines: 10, code: true },
    { name: "write", filePath: "sample.ts", maxLines: 10, code: true },
    { name: "read", filePath: "Dockerfile", maxLines: 10, code: true },
    { name: "read", filePath: "sample.html", maxLines: 10, code: true },
  ])(
    "preserves $name $filePath output around its preview limit",
    async ({ name, filePath, maxLines, code }) => {
      for (const lineCount of [maxLines - 1, maxLines, maxLines + 1]) {
        const lines = Array.from({ length: lineCount }, (_, index) =>
          filePath.endsWith(".html")
            ? `<p>line ${index} & text</p>\tend`
            : `const value${index} = "<&>";\t// line`,
        );
        if (lineCount > maxLines && name !== "bash") {
          lines[lineCount - 1] = "";
        }
        const text = lines.join("\n");
        const entries: SessionEntry[] =
          name === "bashExecution"
            ? [
                {
                  id: "1",
                  parentId: null,
                  timestamp: now(),
                  type: "message",
                  message: { role: name, command: "echo output", output: text, exitCode: 0 },
                },
              ]
            : [
                {
                  id: "1",
                  parentId: null,
                  timestamp: now(),
                  type: "message",
                  message: {
                    role: "assistant",
                    content: [
                      {
                        type: "toolCall",
                        id: "call-output",
                        name,
                        arguments: { command: "echo output", path: filePath, content: text },
                      },
                    ],
                  },
                },
                {
                  id: "2",
                  parentId: "1",
                  timestamp: now(),
                  type: "message",
                  message: {
                    role: "toolResult",
                    toolCallId: "call-output",
                    content: name === "write" ? "" : text,
                  },
                },
              ];
        const { document } = await renderTemplate({
          header: { id: "session-output-lines", timestamp: now() },
          entries,
          leafId: name === "bashExecution" ? "1" : "2",
          systemPrompt: "",
          tools: [],
        });
        const outputs = document.querySelectorAll(".tool-execution > .tool-output");
        const output = requireElement(outputs.item(outputs.length - 1), "tool output missing");
        const expanded = lineCount > maxLines;
        expect(output.classList.contains("expandable")).toBe(expanded);
        const full = expanded
          ? requireElement(output.querySelector(".output-full"), "full output missing")
          : output;
        const assertLines = (element: Element, expected: string[]) => {
          if (code) {
            expect(
              requireElement(element.querySelector("code.hljs"), "code missing").textContent,
            ).toBe(expected.join("\n"));
          } else {
            expect(
              Array.from(element.children)
                .filter((child) => !child.classList.contains("expand-hint"))
                .map((child) => child.textContent),
            ).toEqual(expected);
          }
          expect(element.querySelector("p")).toBeNull();
        };
        const expected = lines.map((line) => line.replace(/\t/g, "   "));
        assertLines(full, expected);
        if (expanded) {
          assertLines(
            requireElement(output.querySelector(".output-preview"), "preview missing"),
            expected.slice(0, maxLines),
          );
          expect(output.querySelector(".expand-hint")?.textContent).toBe("... (1 more lines)");
        }
        if (filePath === "Dockerfile") {
          expect(full.querySelector("span")).toBeNull();
        } else if (code) {
          expect(full.querySelector(".hljs-keyword, .hljs-tag")).not.toBeNull();
        }
      }
    },
  );
});