@@ -5,12 +5,17 @@ import type { MessagePart as MessagePartType } from '@/api/types'
55
66const mocks = vi . hoisted ( ( ) => ( {
77 useTTS : vi . fn ( ) ,
8+ useSettings : vi . fn ( ) ,
89} ) )
910
1011vi . mock ( '@/hooks/useTTS' , ( ) => ( {
1112 useTTS : mocks . useTTS ,
1213} ) )
1314
15+ vi . mock ( '@/hooks/useSettings' , ( ) => ( {
16+ useSettings : mocks . useSettings ,
17+ } ) )
18+
1419interface MockTTSReturn {
1520 speakMessage : ReturnType < typeof vi . fn >
1621 stop : ReturnType < typeof vi . fn >
@@ -20,13 +25,42 @@ interface MockTTSReturn {
2025 isEnabled : boolean
2126}
2227
28+ interface MockSettingsReturn {
29+ preferences : {
30+ simpleChatMode : boolean
31+ showReasoning : boolean
32+ expandToolCalls : boolean
33+ expandDiffs : boolean
34+ autoScroll : boolean
35+ theme : 'dark' | 'light' | 'system'
36+ mode : 'plan' | 'build'
37+ } | undefined
38+ isLoading : boolean
39+ updateSettings : ReturnType < typeof vi . fn >
40+ isUpdating : boolean
41+ }
42+
2343describe ( 'MessagePart' , ( ) => {
2444 const mockSpeakMessage = vi . fn ( )
2545 const mockStop = vi . fn ( )
2646
2747 beforeEach ( ( ) => {
2848 mockSpeakMessage . mockClear ( )
2949 mockStop . mockClear ( )
50+ mocks . useSettings . mockReturnValue ( {
51+ preferences : {
52+ simpleChatMode : false ,
53+ showReasoning : false ,
54+ expandToolCalls : false ,
55+ expandDiffs : true ,
56+ autoScroll : true ,
57+ theme : 'dark' as const ,
58+ mode : 'build' as const ,
59+ } ,
60+ isLoading : false ,
61+ updateSettings : vi . fn ( ) ,
62+ isUpdating : false ,
63+ } )
3064 } )
3165
3266 const setup = ( options : {
@@ -47,6 +81,15 @@ describe('MessagePart', () => {
4781 mocks . useTTS . mockReturnValue ( mockTTS )
4882 }
4983
84+ const setupSettings = ( preferences : MockSettingsReturn [ 'preferences' ] ) => {
85+ mocks . useSettings . mockReturnValue ( {
86+ preferences,
87+ isLoading : false ,
88+ updateSettings : vi . fn ( ) ,
89+ isUpdating : false ,
90+ } )
91+ }
92+
5093 const createStepFinishPart = ( messageID : string ) : MessagePartType => ( {
5194 type : 'step-finish' ,
5295 messageID,
@@ -223,4 +266,261 @@ describe('MessagePart', () => {
223266
224267 expect ( screen . getByRole ( 'button' ) ) . not . toHaveClass ( 'bg-red-500/20' )
225268 } )
269+
270+ describe ( 'simpleChatMode' , ( ) => {
271+ const createToolPart = ( ) : MessagePartType => ( {
272+ type : 'tool' ,
273+ tool : 'edit' ,
274+ sessionID : 'test-session' ,
275+ state : {
276+ status : 'completed' ,
277+ input : { filePath : '/test/file.txt' } ,
278+ time : { start : Date . now ( ) , end : Date . now ( ) + 100 } ,
279+ } ,
280+ } )
281+
282+ const createPatchPart = ( ) : MessagePartType => ( {
283+ type : 'patch' ,
284+ hash : 'abc123' ,
285+ files : [ '/test/file.txt' ] ,
286+ sessionID : 'test-session' ,
287+ } )
288+
289+ const createReasoningPart = ( ) : MessagePartType => ( {
290+ type : 'reasoning' ,
291+ text : 'This is the reasoning text' ,
292+ sessionID : 'test-session' ,
293+ } )
294+
295+ const createSnapshotPart = ( ) : MessagePartType => ( {
296+ type : 'snapshot' ,
297+ snapshot : 'snapshot-data' ,
298+ sessionID : 'test-session' ,
299+ } )
300+
301+ const createAgentPart = ( ) : MessagePartType => ( {
302+ type : 'agent' ,
303+ name : 'test-agent' ,
304+ sessionID : 'test-session' ,
305+ } )
306+
307+ const createTextPart = ( ) : MessagePartType => ( {
308+ type : 'text' ,
309+ text : 'Hello, this is a text message' ,
310+ sessionID : 'test-session' ,
311+ } )
312+
313+ it ( 'renders null for tool part when simpleChatMode is true' , ( ) => {
314+ setupSettings ( {
315+ simpleChatMode : true ,
316+ showReasoning : false ,
317+ expandToolCalls : false ,
318+ expandDiffs : true ,
319+ autoScroll : true ,
320+ theme : 'dark' ,
321+ mode : 'build' ,
322+ } )
323+
324+ const part = createToolPart ( )
325+ const { container } = render ( < MessagePart part = { part } /> )
326+
327+ expect ( container . firstChild ) . toBeNull ( )
328+ } )
329+
330+ it ( 'renders null for patch part when simpleChatMode is true' , ( ) => {
331+ setupSettings ( {
332+ simpleChatMode : true ,
333+ showReasoning : false ,
334+ expandToolCalls : false ,
335+ expandDiffs : true ,
336+ autoScroll : true ,
337+ theme : 'dark' ,
338+ mode : 'build' ,
339+ } )
340+
341+ const part = createPatchPart ( )
342+ const { container } = render ( < MessagePart part = { part } /> )
343+
344+ expect ( container . firstChild ) . toBeNull ( )
345+ } )
346+
347+ it ( 'renders null for reasoning part when simpleChatMode is true' , ( ) => {
348+ setupSettings ( {
349+ simpleChatMode : true ,
350+ showReasoning : true ,
351+ expandToolCalls : false ,
352+ expandDiffs : true ,
353+ autoScroll : true ,
354+ theme : 'dark' ,
355+ mode : 'build' ,
356+ } )
357+
358+ const part = createReasoningPart ( )
359+ const { container } = render ( < MessagePart part = { part } /> )
360+
361+ expect ( container . firstChild ) . toBeNull ( )
362+ } )
363+
364+ it ( 'renders null for snapshot part when simpleChatMode is true' , ( ) => {
365+ setupSettings ( {
366+ simpleChatMode : true ,
367+ showReasoning : false ,
368+ expandToolCalls : false ,
369+ expandDiffs : true ,
370+ autoScroll : true ,
371+ theme : 'dark' ,
372+ mode : 'build' ,
373+ } )
374+
375+ const part = createSnapshotPart ( )
376+ const { container } = render ( < MessagePart part = { part } /> )
377+
378+ expect ( container . firstChild ) . toBeNull ( )
379+ } )
380+
381+ it ( 'renders null for agent part when simpleChatMode is true' , ( ) => {
382+ setupSettings ( {
383+ simpleChatMode : true ,
384+ showReasoning : false ,
385+ expandToolCalls : false ,
386+ expandDiffs : true ,
387+ autoScroll : true ,
388+ theme : 'dark' ,
389+ mode : 'build' ,
390+ } )
391+
392+ const part = createAgentPart ( )
393+ const { container } = render ( < MessagePart part = { part } /> )
394+
395+ expect ( container . firstChild ) . toBeNull ( )
396+ } )
397+
398+ it ( 'renders text part when simpleChatMode is true' , ( ) => {
399+ setupSettings ( {
400+ simpleChatMode : true ,
401+ showReasoning : false ,
402+ expandToolCalls : false ,
403+ expandDiffs : true ,
404+ autoScroll : true ,
405+ theme : 'dark' ,
406+ mode : 'build' ,
407+ } )
408+
409+ const part = createTextPart ( )
410+ render ( < MessagePart part = { part } /> )
411+
412+ expect ( screen . getByText ( 'Hello, this is a text message' ) ) . toBeInTheDocument ( )
413+ } )
414+
415+ it ( 'renders tool part when simpleChatMode is false' , ( ) => {
416+ setupSettings ( {
417+ simpleChatMode : false ,
418+ showReasoning : false ,
419+ expandToolCalls : false ,
420+ expandDiffs : true ,
421+ autoScroll : true ,
422+ theme : 'dark' ,
423+ mode : 'build' ,
424+ } )
425+
426+ const part = createToolPart ( )
427+ const { container } = render ( < MessagePart part = { part } /> )
428+
429+ expect ( container . firstChild ) . not . toBeNull ( )
430+ } )
431+
432+ it ( 'renders patch part when simpleChatMode is false' , ( ) => {
433+ setupSettings ( {
434+ simpleChatMode : false ,
435+ showReasoning : false ,
436+ expandToolCalls : false ,
437+ expandDiffs : true ,
438+ autoScroll : true ,
439+ theme : 'dark' ,
440+ mode : 'build' ,
441+ } )
442+
443+ const part = createPatchPart ( )
444+ const { container } = render ( < MessagePart part = { part } /> )
445+
446+ expect ( container . firstChild ) . not . toBeNull ( )
447+ } )
448+
449+ it ( 'renders snapshot part when simpleChatMode is false' , ( ) => {
450+ setupSettings ( {
451+ simpleChatMode : false ,
452+ showReasoning : false ,
453+ expandToolCalls : false ,
454+ expandDiffs : true ,
455+ autoScroll : true ,
456+ theme : 'dark' ,
457+ mode : 'build' ,
458+ } )
459+
460+ const part = createSnapshotPart ( )
461+ const { container } = render ( < MessagePart part = { part } /> )
462+
463+ expect ( container . firstChild ) . not . toBeNull ( )
464+ } )
465+
466+ it ( 'renders agent part when simpleChatMode is false' , ( ) => {
467+ setupSettings ( {
468+ simpleChatMode : false ,
469+ showReasoning : false ,
470+ expandToolCalls : false ,
471+ expandDiffs : true ,
472+ autoScroll : true ,
473+ theme : 'dark' ,
474+ mode : 'build' ,
475+ } )
476+
477+ const part = createAgentPart ( )
478+ const { container } = render ( < MessagePart part = { part } /> )
479+
480+ expect ( container . firstChild ) . not . toBeNull ( )
481+ } )
482+ } )
483+
484+ describe ( 'showReasoning' , ( ) => {
485+ const createReasoningPart = ( ) : MessagePartType => ( {
486+ type : 'reasoning' ,
487+ text : 'This is the reasoning text' ,
488+ sessionID : 'test-session' ,
489+ } )
490+
491+ it ( 'renders null for reasoning part when showReasoning is false' , ( ) => {
492+ setupSettings ( {
493+ simpleChatMode : false ,
494+ showReasoning : false ,
495+ expandToolCalls : false ,
496+ expandDiffs : true ,
497+ autoScroll : true ,
498+ theme : 'dark' ,
499+ mode : 'build' ,
500+ } )
501+
502+ const part = createReasoningPart ( )
503+ const { container } = render ( < MessagePart part = { part } /> )
504+
505+ expect ( container . firstChild ) . toBeNull ( )
506+ } )
507+
508+ it ( 'renders reasoning part when showReasoning is true' , ( ) => {
509+ setupSettings ( {
510+ simpleChatMode : false ,
511+ showReasoning : true ,
512+ expandToolCalls : false ,
513+ expandDiffs : true ,
514+ autoScroll : true ,
515+ theme : 'dark' ,
516+ mode : 'build' ,
517+ } )
518+
519+ const part = createReasoningPart ( )
520+ render ( < MessagePart part = { part } /> )
521+
522+ expect ( screen . getByText ( 'This is the reasoning text' ) ) . toBeInTheDocument ( )
523+ expect ( screen . getByText ( 'Reasoning' ) ) . toBeInTheDocument ( )
524+ } )
525+ } )
226526} )
0 commit comments