@@ -34,6 +34,10 @@ describe('TOOL_USE_RENDERERS', () => {
3434 }
3535 } ) ;
3636
37+ it ( 'CORE_TOOL_USE stays in sync with registry keys' , ( ) => {
38+ expect ( new Set ( CORE_TOOL_USE ) ) . toEqual ( new Set ( Object . keys ( TOOL_USE_RENDERERS ) ) ) ;
39+ } ) ;
40+
3741 it ( 'does not register the unknown dispatch sentinel as a tool renderer' , ( ) => {
3842 expect ( Object . prototype . hasOwnProperty . call ( TOOL_USE_RENDERERS , UNKNOWN_DISPATCH_KEY ) ) . toBe ( false ) ;
3943 } ) ;
@@ -69,6 +73,10 @@ describe('TOOL_RESULT_RENDERERS', () => {
6973 }
7074 } ) ;
7175
76+ it ( 'CORE_TOOL_RESULT stays in sync with registry keys' , ( ) => {
77+ expect ( new Set ( CORE_TOOL_RESULT ) ) . toEqual ( new Set ( Object . keys ( TOOL_RESULT_RENDERERS ) ) ) ;
78+ } ) ;
79+
7280 it ( 'renderBashResult escapes stdout' , ( ) => {
7381 const html = renderToolResult ( {
7482 result_type : 'bash' ,
@@ -188,6 +196,56 @@ describe('renderTodoWriteResult', () => {
188196 } ) ;
189197} ) ;
190198
199+ /** Representative fixtures for registry-driven behavioral smoke tests. */
200+ const TOOL_USE_FIXTURES = {
201+ Bash : { input : { command : 'echo hi' , description : 'say hi' } } ,
202+ Read : { input : { file_path : 'README.md' } } ,
203+ Write : { input : { file_path : 'out.txt' , content : 'data' } } ,
204+ Edit : { input : { file_path : 'a.js' , old_string : 'x' , new_string : 'y' } } ,
205+ Glob : { input : { pattern : '*.js' , path : 'src' } } ,
206+ Grep : { input : { pattern : 'TODO' , path : 'lib' } } ,
207+ Task : { input : { subagent_type : 'explore' , description : 'scan' , prompt : 'go' } } ,
208+ TodoWrite : { input : { todos : [ { status : 'pending' , content : 'task' } ] } } ,
209+ AskUserQuestion : { input : { questions : [ { question : 'OK?' } ] } } ,
210+ WebFetch : { input : { url : 'https://example.com' } } ,
211+ WebSearch : { input : { query : 'vitest' } } ,
212+ } ;
213+
214+ const TOOL_RESULT_FIXTURES = {
215+ bash : { exit_code : 0 , stdout : 'ok' } ,
216+ file_read : { file_path : '/a.txt' , num_lines : 10 } ,
217+ file_edit : { file_path : 'b.js' } ,
218+ file_write : { file_path : 'c.txt' } ,
219+ glob : { num_files : 3 } ,
220+ grep : { num_files : 2 , num_lines : 5 } ,
221+ web_search : { query : 'test' , result_count : 1 } ,
222+ web_fetch : { url : 'https://x.com' , status_code : 200 } ,
223+ task : { status : 'completed' , total_duration_ms : 1000 } ,
224+ todo_write : { todos : [ { status : 'pending' , content : 'x' } ] } ,
225+ user_input : { questions : [ { question : 'Q' } ] , answers : { Q : 'A' } } ,
226+ plan : { file_path : 'plan.md' } ,
227+ } ;
228+
229+ describe ( 'registry behavioral smoke tests' , ( ) => {
230+ it ( 'every registered tool_use renderer produces non-empty HTML' , ( ) => {
231+ for ( const name of CORE_TOOL_USE ) {
232+ expect ( TOOL_USE_FIXTURES [ name ] , name ) . toBeDefined ( ) ;
233+ const html = renderToolUse ( { name, ...TOOL_USE_FIXTURES [ name ] } ) ;
234+ expect ( html , name ) . toContain ( 'tool-call' ) ;
235+ expect ( html . length , name ) . toBeGreaterThan ( 20 ) ;
236+ }
237+ } ) ;
238+
239+ it ( 'every registered tool_result renderer produces non-empty HTML' , ( ) => {
240+ for ( const rt of CORE_TOOL_RESULT ) {
241+ expect ( TOOL_RESULT_FIXTURES [ rt ] , rt ) . toBeDefined ( ) ;
242+ const html = renderToolResult ( { result_type : rt , ...TOOL_RESULT_FIXTURES [ rt ] } ) ;
243+ expect ( html , rt ) . toContain ( 'tool-result' ) ;
244+ expect ( html . length , rt ) . toBeGreaterThan ( 20 ) ;
245+ }
246+ } ) ;
247+ } ) ;
248+
191249describe ( 'renderToolResult fallback' , ( ) => {
192250 it ( 'renders raw result type and JSON payload for unknown result types' , ( ) => {
193251 const html = renderToolResult ( {
0 commit comments