From 9126909bebe509c9568c9cddc12450820bb1cd2a Mon Sep 17 00:00:00 2001 From: chen Date: Wed, 8 Jul 2026 07:01:21 +0800 Subject: [PATCH 1/2] test: add vitest coverage for tool render modules Add per-renderer vitest coverage with XSS escaping assertions, a shared test helper, registry-driven smoke tests, and raised coverage thresholds. --- static/js/render/registry.test.js | 48 +++++++++++++++++++ static/js/render/test_helpers.js | 36 ++++++++++++++ static/js/render/tool_result/bash.test.js | 45 +++++++++++++++++ static/js/render/tool_result/fallback.test.js | 32 +++++++++++++ .../js/render/tool_result/file_edit.test.js | 28 +++++++++++ .../js/render/tool_result/file_write.test.js | 28 +++++++++++ static/js/render/tool_result/glob.test.js | 27 +++++++++++ static/js/render/tool_result/grep.test.js | 19 ++++++++ static/js/render/tool_result/plan.test.js | 28 +++++++++++ static/js/render/tool_result/task.test.js | 46 ++++++++++++++++++ .../js/render/tool_result/todo_write.test.js | 38 +++++++++++++++ .../js/render/tool_result/user_input.test.js | 36 ++++++++++++++ .../js/render/tool_result/web_fetch.test.js | 33 +++++++++++++ .../js/render/tool_result/web_search.test.js | 31 ++++++++++++ .../render/tool_use/ask_user_question.test.js | 39 +++++++++++++++ static/js/render/tool_use/fallback.test.js | 31 ++++++++++++ static/js/render/tool_use/glob.test.js | 32 +++++++++++++ static/js/render/tool_use/grep.test.js | 32 +++++++++++++ static/js/render/tool_use/read.test.js | 29 +++++++++++ static/js/render/tool_use/task.test.js | 42 ++++++++++++++++ static/js/render/tool_use/todo_write.test.js | 40 ++++++++++++++++ static/js/render/tool_use/write.test.js | 34 +++++++++++++ vitest.config.js | 8 ++-- 23 files changed, 758 insertions(+), 4 deletions(-) create mode 100644 static/js/render/test_helpers.js create mode 100644 static/js/render/tool_result/bash.test.js create mode 100644 static/js/render/tool_result/fallback.test.js create mode 100644 static/js/render/tool_result/file_edit.test.js create mode 100644 static/js/render/tool_result/file_write.test.js create mode 100644 static/js/render/tool_result/glob.test.js create mode 100644 static/js/render/tool_result/grep.test.js create mode 100644 static/js/render/tool_result/plan.test.js create mode 100644 static/js/render/tool_result/task.test.js create mode 100644 static/js/render/tool_result/todo_write.test.js create mode 100644 static/js/render/tool_result/user_input.test.js create mode 100644 static/js/render/tool_result/web_fetch.test.js create mode 100644 static/js/render/tool_result/web_search.test.js create mode 100644 static/js/render/tool_use/ask_user_question.test.js create mode 100644 static/js/render/tool_use/fallback.test.js create mode 100644 static/js/render/tool_use/glob.test.js create mode 100644 static/js/render/tool_use/grep.test.js create mode 100644 static/js/render/tool_use/read.test.js create mode 100644 static/js/render/tool_use/task.test.js create mode 100644 static/js/render/tool_use/todo_write.test.js create mode 100644 static/js/render/tool_use/write.test.js diff --git a/static/js/render/registry.test.js b/static/js/render/registry.test.js index 28ee6b8..ec77295 100644 --- a/static/js/render/registry.test.js +++ b/static/js/render/registry.test.js @@ -188,6 +188,54 @@ describe('renderTodoWriteResult', () => { }); }); +/** Representative fixtures for registry-driven behavioral smoke tests. */ +const TOOL_USE_FIXTURES = { + Bash: { input: { command: 'echo hi', description: 'say hi' } }, + Read: { input: { file_path: 'README.md' } }, + Write: { input: { file_path: 'out.txt', content: 'data' } }, + Edit: { input: { file_path: 'a.js', old_string: 'x', new_string: 'y' } }, + Glob: { input: { pattern: '*.js', path: 'src' } }, + Grep: { input: { pattern: 'TODO', path: 'lib' } }, + Task: { input: { subagent_type: 'explore', description: 'scan', prompt: 'go' } }, + TodoWrite: { input: { todos: [{ status: 'pending', content: 'task' }] } }, + AskUserQuestion: { input: { questions: [{ question: 'OK?' }] } }, + WebFetch: { input: { url: 'https://example.com' } }, + WebSearch: { input: { query: 'vitest' } }, +}; + +const TOOL_RESULT_FIXTURES = { + bash: { exit_code: 0, stdout: 'ok' }, + file_read: { file_path: '/a.txt', num_lines: 10 }, + file_edit: { file_path: 'b.js' }, + file_write: { file_path: 'c.txt' }, + glob: { num_files: 3 }, + grep: { num_files: 2, num_lines: 5 }, + web_search: { query: 'test', result_count: 1 }, + web_fetch: { url: 'https://x.com', status_code: 200 }, + task: { status: 'completed', total_duration_ms: 1000 }, + todo_write: { todos: [{ status: 'pending', content: 'x' }] }, + user_input: { questions: [{ question: 'Q' }], answers: { Q: 'A' } }, + plan: { file_path: 'plan.md' }, +}; + +describe('registry behavioral smoke tests', () => { + it('every registered tool_use renderer produces non-empty HTML', () => { + for (const name of CORE_TOOL_USE) { + const html = renderToolUse({ name, ...TOOL_USE_FIXTURES[name] }); + expect(html, name).toContain('tool-call'); + expect(html.length, name).toBeGreaterThan(20); + } + }); + + it('every registered tool_result renderer produces non-empty HTML', () => { + for (const rt of CORE_TOOL_RESULT) { + const html = renderToolResult({ result_type: rt, ...TOOL_RESULT_FIXTURES[rt] }); + expect(html, rt).toContain('tool-result'); + expect(html.length, rt).toBeGreaterThan(20); + } + }); +}); + describe('renderToolResult fallback', () => { it('renders raw result type and JSON payload for unknown result types', () => { const html = renderToolResult({ diff --git a/static/js/render/test_helpers.js b/static/js/render/test_helpers.js new file mode 100644 index 0000000..8b50472 --- /dev/null +++ b/static/js/render/test_helpers.js @@ -0,0 +1,36 @@ +import { expect } from 'vitest'; +import { renderToolUse, renderToolResult } from './registry.js'; + +/** Common XSS payloads for renderer escaping assertions. */ +export const XSS_SCRIPT = ''; +export const XSS_IMG = ''; + +/** + * Render a tool-use card via the registry and return the HTML string. + */ +export function mountToolUse(tool) { + return renderToolUse(tool); +} + +/** + * Render a tool-result card via the registry and return the HTML string. + */ +export function mountToolResult(parsed) { + return renderToolResult(parsed); +} + +/** + * Assert raw HTML fragments are escaped (not present verbatim). + */ +export function expectNoRawHtml(html, rawFragments) { + for (const frag of rawFragments) { + expect(html).not.toContain(frag); + } +} + +/** + * Assert an HTML-escaped fragment appears in output. + */ +export function expectEscaped(html, escapedFragment) { + expect(html).toContain(escapedFragment); +} diff --git a/static/js/render/tool_result/bash.test.js b/static/js/render/tool_result/bash.test.js new file mode 100644 index 0000000..087ad55 --- /dev/null +++ b/static/js/render/tool_result/bash.test.js @@ -0,0 +1,45 @@ +import { describe, expect, it } from 'vitest'; +import { renderBashResult } from './bash.js'; +import { mountToolResult, expectNoRawHtml, XSS_IMG } from '../test_helpers.js'; + +describe('renderBashResult', () => { + it('renders success status with stdout', () => { + const html = renderBashResult({ + result_type: 'bash', + exit_code: 0, + stdout: 'hello\nworld', + }); + expect(html).toContain('Bash Result (success)'); + expect(html).toContain('hello'); + expect(html).toContain('stdout'); + expect(html).toContain('tool-result'); + }); + + it('renders error status with stderr', () => { + const html = renderBashResult({ + result_type: 'bash', + exit_code: 1, + is_error: true, + stderr: 'command failed', + }); + expect(html).toContain('error (exit 1)'); + expect(html).toContain('command failed'); + expect(html).toContain('stderr'); + }); + + it('renders interrupted status', () => { + const html = renderBashResult({ result_type: 'bash', interrupted: true }); + expect(html).toContain('Bash Result (interrupted)'); + }); + + it('escapes HTML in stdout and stderr', () => { + const html = mountToolResult({ + result_type: 'bash', + exit_code: 0, + stdout: XSS_IMG, + stderr: '', + }); + expectNoRawHtml(html, [XSS_IMG, '', + }, + }); + expectNoRawHtml(html, [XSS_SCRIPT, '', ''; export const XSS_IMG = ''; -/** - * Render a tool-use card via the registry and return the HTML string. - */ -export function mountToolUse(tool) { - return renderToolUse(tool); -} - -/** - * Render a tool-result card via the registry and return the HTML string. - */ -export function mountToolResult(parsed) { - return renderToolResult(parsed); -} - /** * Assert raw HTML fragments are escaped (not present verbatim). */ @@ -34,3 +20,33 @@ export function expectNoRawHtml(html, rawFragments) { export function expectEscaped(html, escapedFragment) { expect(html).toContain(escapedFragment); } + +/** + * Shared behavioral tests for summary-only tool_result renderers (Edited/Plan/Wrote). + */ +export function describeSummaryOnlyResult( + render, + { suiteName, resultType, label, samplePath }, +) { + describe(suiteName, () => { + it(`renders ${label.toLowerCase()} file path in summary`, () => { + const html = render({ result_type: resultType, file_path: samplePath }); + expect(html).toContain(`${label}: ${samplePath}`); + expect(html).toContain('tool-result'); + }); + + it('handles missing file path', () => { + const html = render({ result_type: resultType }); + expect(html).toContain(`${label}:`); + expect(html).not.toContain('undefined'); + }); + + it('escapes HTML in file path via registry', () => { + const html = renderToolResult({ + result_type: resultType, + file_path: XSS_SCRIPT, + }); + expectNoRawHtml(html, [XSS_SCRIPT]); + }); + }); +} diff --git a/static/js/render/tool_result/bash.test.js b/static/js/render/tool_result/bash.test.js index 087ad55..75a0ec7 100644 --- a/static/js/render/tool_result/bash.test.js +++ b/static/js/render/tool_result/bash.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderBashResult } from './bash.js'; -import { mountToolResult, expectNoRawHtml, XSS_IMG } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_IMG } from '../test_helpers.js'; describe('renderBashResult', () => { it('renders success status with stdout', () => { @@ -33,7 +34,7 @@ describe('renderBashResult', () => { }); it('escapes HTML in stdout and stderr', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'bash', exit_code: 0, stdout: XSS_IMG, diff --git a/static/js/render/tool_result/fallback.test.js b/static/js/render/tool_result/fallback.test.js index 4f7cac3..f5bf066 100644 --- a/static/js/render/tool_result/fallback.test.js +++ b/static/js/render/tool_result/fallback.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderToolResultFallback } from './fallback.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderToolResultFallback', () => { it('renders unknown result type and JSON payload', () => { @@ -22,7 +23,7 @@ describe('renderToolResultFallback', () => { }); it('escapes HTML in JSON fallback body', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'mystery', content: XSS_SCRIPT, }); diff --git a/static/js/render/tool_result/file_edit.test.js b/static/js/render/tool_result/file_edit.test.js index f8db923..bcafb0a 100644 --- a/static/js/render/tool_result/file_edit.test.js +++ b/static/js/render/tool_result/file_edit.test.js @@ -1,28 +1,9 @@ -import { describe, expect, it } from 'vitest'; import { renderFileEditResult } from './file_edit.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { describeSummaryOnlyResult } from '../test_helpers.js'; -describe('renderFileEditResult', () => { - it('renders edited file path in summary', () => { - const html = renderFileEditResult({ - result_type: 'file_edit', - file_path: 'src/app.js', - }); - expect(html).toContain('Edited: src/app.js'); - expect(html).toContain('tool-result'); - }); - - it('handles missing file path', () => { - const html = renderFileEditResult({ result_type: 'file_edit' }); - expect(html).toContain('Edited:'); - expect(html).not.toContain('undefined'); - }); - - it('escapes HTML in file path via registry', () => { - const html = mountToolResult({ - result_type: 'file_edit', - file_path: XSS_SCRIPT, - }); - expectNoRawHtml(html, [XSS_SCRIPT]); - }); +describeSummaryOnlyResult(renderFileEditResult, { + suiteName: 'renderFileEditResult', + resultType: 'file_edit', + label: 'Edited', + samplePath: 'src/app.js', }); diff --git a/static/js/render/tool_result/file_write.test.js b/static/js/render/tool_result/file_write.test.js index 3cd4f65..0d901d4 100644 --- a/static/js/render/tool_result/file_write.test.js +++ b/static/js/render/tool_result/file_write.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderFileWriteResult } from './file_write.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderFileWriteResult', () => { it('renders written file path in summary', () => { @@ -19,7 +20,7 @@ describe('renderFileWriteResult', () => { }); it('escapes HTML in file path via registry', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'file_write', file_path: XSS_SCRIPT, }); diff --git a/static/js/render/tool_result/plan.test.js b/static/js/render/tool_result/plan.test.js index 8251b20..d975fbb 100644 --- a/static/js/render/tool_result/plan.test.js +++ b/static/js/render/tool_result/plan.test.js @@ -1,28 +1,9 @@ -import { describe, expect, it } from 'vitest'; import { renderPlanResult } from './plan.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { describeSummaryOnlyResult } from '../test_helpers.js'; -describe('renderPlanResult', () => { - it('renders plan file path in summary', () => { - const html = renderPlanResult({ - result_type: 'plan', - file_path: '.cursor/plans/sprint.md', - }); - expect(html).toContain('Plan: .cursor/plans/sprint.md'); - expect(html).toContain('tool-result'); - }); - - it('handles missing file path', () => { - const html = renderPlanResult({ result_type: 'plan' }); - expect(html).toContain('Plan:'); - expect(html).not.toContain('undefined'); - }); - - it('escapes HTML in file path via registry', () => { - const html = mountToolResult({ - result_type: 'plan', - file_path: XSS_SCRIPT, - }); - expectNoRawHtml(html, [XSS_SCRIPT]); - }); +describeSummaryOnlyResult(renderPlanResult, { + suiteName: 'renderPlanResult', + resultType: 'plan', + label: 'Plan', + samplePath: '.cursor/plans/sprint.md', }); diff --git a/static/js/render/tool_result/task.test.js b/static/js/render/tool_result/task.test.js index 6d00775..09c89f2 100644 --- a/static/js/render/tool_result/task.test.js +++ b/static/js/render/tool_result/task.test.js @@ -1,19 +1,21 @@ import { describe, expect, it } from 'vitest'; import { renderTaskResult } from './task.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderTaskResult', () => { it('renders completed task with duration and token stats', () => { + const totalTokens = 1500; const html = renderTaskResult({ result_type: 'task', status: 'completed', total_duration_ms: 2500, - total_tokens: 1500, + total_tokens: totalTokens, total_tool_use_count: 3, }); expect(html).toContain('Task completed'); expect(html).toContain('2.5s'); - expect(html).toContain('1,500 tokens'); + expect(html).toContain(`${totalTokens.toLocaleString()} tokens`); expect(html).toContain('3 tool calls'); expect(html).toContain('tool-result'); }); @@ -37,7 +39,7 @@ describe('renderTaskResult', () => { }); it('escapes HTML in description via registry', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'task', description: XSS_SCRIPT, }); diff --git a/static/js/render/tool_result/todo_write.test.js b/static/js/render/tool_result/todo_write.test.js index df09cfa..d29208c 100644 --- a/static/js/render/tool_result/todo_write.test.js +++ b/static/js/render/tool_result/todo_write.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderTodoWriteResult } from './todo_write.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderTodoWriteResult', () => { it('renders todo items with emoji status icons', () => { @@ -28,7 +29,7 @@ describe('renderTodoWriteResult', () => { }); it('escapes HTML in todo content', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'todo_write', todos: [{ status: 'pending', content: XSS_SCRIPT }], }); diff --git a/static/js/render/tool_result/user_input.test.js b/static/js/render/tool_result/user_input.test.js index 4bec667..daa0a13 100644 --- a/static/js/render/tool_result/user_input.test.js +++ b/static/js/render/tool_result/user_input.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderUserInputResult } from './user_input.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderUserInputResult', () => { it('renders questions and answers', () => { @@ -25,7 +26,7 @@ describe('renderUserInputResult', () => { }); it('escapes HTML in questions and answers', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'user_input', questions: [{ question: XSS_SCRIPT }], answers: { key: 'answer' }, diff --git a/static/js/render/tool_result/web_fetch.test.js b/static/js/render/tool_result/web_fetch.test.js index f2134a6..5bcd9e9 100644 --- a/static/js/render/tool_result/web_fetch.test.js +++ b/static/js/render/tool_result/web_fetch.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderWebFetchResult } from './web_fetch.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderWebFetchResult', () => { it('renders url and status code in summary', () => { @@ -23,7 +24,7 @@ describe('renderWebFetchResult', () => { }); it('escapes HTML in url via registry', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'web_fetch', url: XSS_SCRIPT, status_code: 404, diff --git a/static/js/render/tool_result/web_search.test.js b/static/js/render/tool_result/web_search.test.js index 81bb74b..b427200 100644 --- a/static/js/render/tool_result/web_search.test.js +++ b/static/js/render/tool_result/web_search.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderWebSearchResult } from './web_search.js'; -import { mountToolResult, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolResult } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderWebSearchResult', () => { it('renders query and result count in summary', () => { @@ -21,7 +22,7 @@ describe('renderWebSearchResult', () => { }); it('escapes HTML in query via registry', () => { - const html = mountToolResult({ + const html = renderToolResult({ result_type: 'web_search', query: XSS_SCRIPT, result_count: 1, diff --git a/static/js/render/tool_use/ask_user_question.test.js b/static/js/render/tool_use/ask_user_question.test.js index 2f3947b..d5f5fb6 100644 --- a/static/js/render/tool_use/ask_user_question.test.js +++ b/static/js/render/tool_use/ask_user_question.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderAskUserQuestionUse } from './ask_user_question.js'; -import { mountToolUse, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderAskUserQuestionUse', () => { it('renders questions in the body', () => { @@ -29,7 +30,7 @@ describe('renderAskUserQuestionUse', () => { }); it('escapes HTML in question text', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'AskUserQuestion', input: { questions: [{ question: XSS_SCRIPT }] }, }); diff --git a/static/js/render/tool_use/fallback.test.js b/static/js/render/tool_use/fallback.test.js index ce9bd4e..410dadf 100644 --- a/static/js/render/tool_use/fallback.test.js +++ b/static/js/render/tool_use/fallback.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderToolUseFallback } from './fallback.js'; -import { mountToolUse, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderToolUseFallback', () => { it('renders unknown tool name and JSON input', () => { @@ -21,7 +22,7 @@ describe('renderToolUseFallback', () => { }); it('escapes HTML in JSON fallback body', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'MysteryTool', input: { payload: XSS_SCRIPT }, }); diff --git a/static/js/render/tool_use/glob.test.js b/static/js/render/tool_use/glob.test.js index d2e257c..28a9552 100644 --- a/static/js/render/tool_use/glob.test.js +++ b/static/js/render/tool_use/glob.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderGlobUse } from './glob.js'; -import { mountToolUse, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderGlobUse', () => { it('renders pattern and optional path', () => { @@ -23,7 +24,7 @@ describe('renderGlobUse', () => { }); it('escapes HTML in pattern and path', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'Glob', input: { pattern: XSS_SCRIPT, path: '/' }, }); diff --git a/static/js/render/tool_use/grep.test.js b/static/js/render/tool_use/grep.test.js index 39b7fe3..aa1dc66 100644 --- a/static/js/render/tool_use/grep.test.js +++ b/static/js/render/tool_use/grep.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderGrepUse } from './grep.js'; -import { mountToolUse, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderGrepUse', () => { it('renders pattern and optional path', () => { @@ -23,7 +24,7 @@ describe('renderGrepUse', () => { }); it('escapes HTML in pattern and path', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'Grep', input: { pattern: XSS_SCRIPT, path: '' }, }); diff --git a/static/js/render/tool_use/read.test.js b/static/js/render/tool_use/read.test.js index 76576cb..bdcf44a 100644 --- a/static/js/render/tool_use/read.test.js +++ b/static/js/render/tool_use/read.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderReadUse } from './read.js'; -import { mountToolUse, expectNoRawHtml, expectEscaped, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, expectEscaped, XSS_SCRIPT } from '../test_helpers.js'; describe('renderReadUse', () => { it('renders file path in summary and body', () => { @@ -19,7 +20,7 @@ describe('renderReadUse', () => { }); it('escapes HTML in file path', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'Read', input: { file_path: XSS_SCRIPT }, }); diff --git a/static/js/render/tool_use/task.test.js b/static/js/render/tool_use/task.test.js index 7c6f505..8c28c77 100644 --- a/static/js/render/tool_use/task.test.js +++ b/static/js/render/tool_use/task.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderTaskUse } from './task.js'; -import { mountToolUse, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderTaskUse', () => { it('renders subagent type, description, and prompt', () => { @@ -29,7 +30,7 @@ describe('renderTaskUse', () => { }); it('escapes HTML in task fields', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'Task', input: { subagent_type: XSS_SCRIPT, diff --git a/static/js/render/tool_use/todo_write.test.js b/static/js/render/tool_use/todo_write.test.js index 6618776..fe23b16 100644 --- a/static/js/render/tool_use/todo_write.test.js +++ b/static/js/render/tool_use/todo_write.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderTodoWriteUse } from './todo_write.js'; -import { mountToolUse, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderTodoWriteUse', () => { it('renders todo items with status icons', () => { @@ -30,7 +31,7 @@ describe('renderTodoWriteUse', () => { }); it('escapes HTML in todo content', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'TodoWrite', input: { todos: [{ status: 'pending', content: XSS_SCRIPT }] }, }); diff --git a/static/js/render/tool_use/write.test.js b/static/js/render/tool_use/write.test.js index 6c85cfa..add8300 100644 --- a/static/js/render/tool_use/write.test.js +++ b/static/js/render/tool_use/write.test.js @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { renderWriteUse } from './write.js'; -import { mountToolUse, expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; +import { renderToolUse } from '../registry.js'; +import { expectNoRawHtml, XSS_SCRIPT } from '../test_helpers.js'; describe('renderWriteUse', () => { it('renders file path and content preview', () => { @@ -24,7 +25,7 @@ describe('renderWriteUse', () => { }); it('escapes HTML in file path and content', () => { - const html = mountToolUse({ + const html = renderToolUse({ name: 'Write', input: { file_path: XSS_SCRIPT, content: 'payload' }, });