theo-agent-dashboard

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

ToolResultRenderer.test.tsx (6249B)


      1 import { describe, it, expect, beforeAll } from "vitest";
      2 import { render } from "@testing-library/react";
      3 import { detectContentType, extractPreamble, getOperationCategory, ToolResultRenderer } from "./ToolResultRenderer";
      4 
      5 // Mock canvas for @git-diff-view/react
      6 beforeAll(() => {
      7   HTMLCanvasElement.prototype.getContext = vi.fn(() => ({
      8     measureText: vi.fn(() => ({ width: 0 })),
      9     fillText: vi.fn(),
     10     fillRect: vi.fn(),
     11     clearRect: vi.fn(),
     12     createImageData: vi.fn(),
     13     putImageData: vi.fn(),
     14     getImageData: vi.fn(() => ({ data: [] })),
     15     setTransform: vi.fn(),
     16     resetTransform: vi.fn(),
     17     drawImage: vi.fn(),
     18     save: vi.fn(),
     19     restore: vi.fn(),
     20     beginPath: vi.fn(),
     21     closePath: vi.fn(),
     22     moveTo: vi.fn(),
     23     lineTo: vi.fn(),
     24     clip: vi.fn(),
     25     stroke: vi.fn(),
     26     fill: vi.fn(),
     27     rect: vi.fn(),
     28     arc: vi.fn(),
     29     font: "",
     30     fillStyle: "",
     31     strokeStyle: "",
     32     lineWidth: 1,
     33     globalAlpha: 1,
     34     textAlign: "start" as CanvasTextAlign,
     35     textBaseline: "alphabetic" as CanvasTextBaseline,
     36   })) as any;
     37 });
     38 
     39 describe("detectContentType", () => {
     40   it("detects pure JSON object", () => {
     41     expect(detectContentType('{"key": "value", "count": 42}')).toBe("json");
     42   });
     43 
     44   it("detects pure JSON array", () => {
     45     expect(detectContentType("[1, 2, 3]")).toBe("json");
     46   });
     47 
     48   it("detects JSON with short preamble", () => {
     49     const content = 'Here are the results:\n{"status": "ok", "count": 5}';
     50     expect(detectContentType(content)).toBe("json");
     51   });
     52 
     53   it("detects unified diff", () => {
     54     const diff = `--- a/file.ts
     55 +++ b/file.ts
     56 @@ -1,3 +1,4 @@
     57  line1
     58 +added line
     59  line2
     60  line3`;
     61     expect(detectContentType(diff)).toBe("diff");
     62   });
     63 
     64   it("detects diff even with curly braces in code", () => {
     65     const diff = `--- a/file.ts
     66 +++ b/file.ts
     67 @@ -1,3 +1,4 @@
     68  const x = {
     69    key: "value"
     70  };
     71 +// new comment`;
     72     expect(detectContentType(diff)).toBe("diff");
     73   });
     74 
     75   it("returns markdown for plain text", () => {
     76     expect(detectContentType("Hello world, this is plain text.")).toBe("markdown");
     77   });
     78 
     79   it("returns markdown for malformed JSON", () => {
     80     expect(detectContentType("{not valid json")).toBe("markdown");
     81   });
     82 
     83   it("returns markdown for empty string", () => {
     84     expect(detectContentType("")).toBe("markdown");
     85   });
     86 
     87   it("returns markdown for fenced code blocks", () => {
     88     const content = '```javascript\nconst x = 1;\n```';
     89     expect(detectContentType(content)).toBe("markdown");
     90   });
     91 
     92   it("handles JSON with nested objects", () => {
     93     const json = '{"outer": {"inner": {"deep": true}}}';
     94     expect(detectContentType(json)).toBe("json");
     95   });
     96 
     97   it("handles JSON with preamble text containing newlines", () => {
     98     const content = 'Ran the health check.\nResults:\n{"status": "healthy", "uptime": 999}';
     99     expect(detectContentType(content)).toBe("json");
    100   });
    101 });
    102 
    103 describe("extractPreamble", () => {
    104   it("returns empty string when content is pure JSON", () => {
    105     const result = extractPreamble('{"key": "value"}');
    106     expect(result.preamble).toBe("");
    107     expect(result.jsonContent).toBe('{"key": "value"}');
    108   });
    109 
    110   it("extracts preamble before JSON", () => {
    111     const content = 'Here are the results:\n{"status": "ok"}';
    112     const result = extractPreamble(content);
    113     expect(result.preamble).toBe("Here are the results:");
    114     expect(result.jsonContent).toBe('{"status": "ok"}');
    115   });
    116 
    117   it("returns full content as preamble when no JSON found", () => {
    118     const result = extractPreamble("Just plain text");
    119     expect(result.preamble).toBe("Just plain text");
    120     expect(result.jsonContent).toBeNull();
    121   });
    122 
    123   it("handles empty string", () => {
    124     const result = extractPreamble("");
    125     expect(result.preamble).toBe("");
    126     expect(result.jsonContent).toBeNull();
    127   });
    128 });
    129 
    130 describe("getOperationCategory", () => {
    131   it("returns READ for read_file", () => {
    132     const result = getOperationCategory("read_file");
    133     expect(result.label).toBe("READ");
    134     expect(result.color).toBe("blue");
    135   });
    136 
    137   it("returns WRITE for write_file", () => {
    138     const result = getOperationCategory("write_file");
    139     expect(result.label).toBe("WRITE");
    140     expect(result.color).toBe("green");
    141   });
    142 
    143   it("returns PATCH for patch", () => {
    144     const result = getOperationCategory("patch");
    145     expect(result.label).toBe("PATCH");
    146     expect(result.color).toBe("yellow");
    147   });
    148 
    149   it("returns SEARCH for search_files", () => {
    150     const result = getOperationCategory("search_files");
    151     expect(result.label).toBe("SEARCH");
    152     expect(result.color).toBe("purple");
    153   });
    154 
    155   it("returns EXEC for terminal", () => {
    156     const result = getOperationCategory("terminal");
    157     expect(result.label).toBe("EXEC");
    158     expect(result.color).toBe("orange");
    159   });
    160 
    161   it("returns gray with tool name for unknown tools", () => {
    162     const result = getOperationCategory("custom_tool");
    163     expect(result.label).toBe("custom_tool");
    164     expect(result.color).toBe("gray");
    165   });
    166 });
    167 
    168 describe("ToolResultRenderer", () => {
    169   it("renders JSON content with JsonView", () => {
    170     const { container } = render(<ToolResultRenderer content='{"key": "value"}' />);
    171     expect(container.querySelector("[data-testid='json-tree']")).toBeTruthy();
    172   });
    173 
    174   it("renders JSON with preamble", () => {
    175     const { container } = render(<ToolResultRenderer content='Results:\n{"key": "value"}' />);
    176     expect(container.textContent).toContain("Results:");
    177     expect(container.querySelector("[data-testid='json-tree']")).toBeTruthy();
    178   });
    179 
    180   it("renders diff content with DiffView", () => {
    181     const diff = `--- a/file.ts\n+++ b/file.ts\n@@ -1,3 +1,4 @@\n line1\n+added\n line2\n line3`;
    182     const { container } = render(<ToolResultRenderer content={diff} />);
    183     expect(container.querySelector("[data-testid='diff-view']")).toBeTruthy();
    184   });
    185 
    186   it("renders plain text with MarkdownRenderer", () => {
    187     const { container } = render(<ToolResultRenderer content="Hello world" />);
    188     expect(container.textContent).toContain("Hello world");
    189   });
    190 
    191   it("passes toolName prop through", () => {
    192     const { container } = render(<ToolResultRenderer content="test" toolName="read_file" />);
    193     expect(container.textContent).toContain("test");
    194   });
    195 });