55 renderToolUse ,
66 renderToolResult ,
77 getToolSummary ,
8+ toolResultHasBody ,
89} from './registry.js' ;
10+ import { UNKNOWN_DISPATCH_KEY } from './constants.js' ;
911import { renderWebFetchUse } from './tool_use/web_fetch.js' ;
1012
1113const CORE_TOOL_USE = [ 'Bash' , 'Read' , 'Write' , 'Edit' , 'Glob' , 'Grep' , 'Task' , 'TodoWrite' , 'AskUserQuestion' , 'WebFetch' , 'WebSearch' ] ;
@@ -32,6 +34,10 @@ describe('TOOL_USE_RENDERERS', () => {
3234 }
3335 } ) ;
3436
37+ it ( 'does not register the unknown dispatch sentinel as a tool renderer' , ( ) => {
38+ expect ( Object . prototype . hasOwnProperty . call ( TOOL_USE_RENDERERS , UNKNOWN_DISPATCH_KEY ) ) . toBe ( false ) ;
39+ } ) ;
40+
3541 it ( 'renderBashUse escapes HTML in command' , ( ) => {
3642 const html = renderToolUse ( {
3743 name : 'Bash' ,
@@ -41,6 +47,11 @@ describe('TOOL_USE_RENDERERS', () => {
4147 expect ( html ) . toContain ( '<script>' ) ;
4248 } ) ;
4349
50+ it ( 'returns empty string for null or undefined tool' , ( ) => {
51+ expect ( renderToolUse ( null ) ) . toBe ( '' ) ;
52+ expect ( renderToolUse ( undefined ) ) . toBe ( '' ) ;
53+ } ) ;
54+
4455 it ( 'renderReadUse escapes file path in body and summary' , ( ) => {
4556 const html = renderToolUse ( {
4657 name : 'Read' ,
@@ -73,6 +84,41 @@ describe('TOOL_RESULT_RENDERERS', () => {
7384 expect ( html ) . toContain ( 'Bash Result (unknown)' ) ;
7485 expect ( html ) . not . toContain ( 'undefined' ) ;
7586 } ) ;
87+
88+ it ( 'returns empty string for null or undefined parsed' , ( ) => {
89+ expect ( renderToolResult ( null ) ) . toBe ( '' ) ;
90+ expect ( renderToolResult ( undefined ) ) . toBe ( '' ) ;
91+ } ) ;
92+ } ) ;
93+
94+ describe ( 'toolResultHasBody' , ( ) => {
95+ it ( 'returns false for null or undefined' , ( ) => {
96+ expect ( toolResultHasBody ( null ) ) . toBe ( false ) ;
97+ expect ( toolResultHasBody ( undefined ) ) . toBe ( false ) ;
98+ } ) ;
99+
100+ it ( 'returns true for bash with stdout or stderr' , ( ) => {
101+ expect ( toolResultHasBody ( { result_type : 'bash' , stdout : 'ok' } ) ) . toBe ( true ) ;
102+ expect ( toolResultHasBody ( { result_type : 'bash' , stderr : 'err' } ) ) . toBe ( true ) ;
103+ expect ( toolResultHasBody ( { result_type : 'bash' } ) ) . toBe ( false ) ;
104+ } ) ;
105+
106+ it ( 'returns false for summary-only result types' , ( ) => {
107+ expect ( toolResultHasBody ( { result_type : 'file_read' , file_path : '/a' } ) ) . toBe ( false ) ;
108+ expect ( toolResultHasBody ( { result_type : 'glob' , num_files : 3 } ) ) . toBe ( false ) ;
109+ } ) ;
110+
111+ it ( 'returns true for user_input and todo_write with todos' , ( ) => {
112+ expect ( toolResultHasBody ( { result_type : 'user_input' } ) ) . toBe ( true ) ;
113+ expect ( toolResultHasBody ( { result_type : 'todo_write' , todos : [ { content : 'x' } ] } ) ) . toBe ( true ) ;
114+ expect ( toolResultHasBody ( { result_type : 'todo_write' , todo_count : 1 } ) ) . toBe ( false ) ;
115+ } ) ;
116+
117+ it ( 'returns true for task when duration, retrieval, or description is set' , ( ) => {
118+ expect ( toolResultHasBody ( { result_type : 'task' , description : 'subagent' } ) ) . toBe ( true ) ;
119+ expect ( toolResultHasBody ( { result_type : 'task' , total_duration_ms : 100 } ) ) . toBe ( true ) ;
120+ expect ( toolResultHasBody ( { result_type : 'task' , status : 'completed' } ) ) . toBe ( false ) ;
121+ } ) ;
76122} ) ;
77123
78124describe ( 'getToolSummary' , ( ) => {
0 commit comments