11import { describe , it , expect , vi , beforeEach } from 'vitest'
22import { render , screen , fireEvent } from '@testing-library/react'
33import { MessageThread } from './MessageThread'
4+ import { useUIState } from '@/stores/uiStateStore'
45
56const mocks = vi . hoisted ( ( ) => ( {
67 useSessionStatus : vi . fn ( ) ,
78 useSessionTodos : vi . fn ( ) ,
89 useSettings : vi . fn ( ) ,
910 usePermissions : vi . fn ( ) ,
1011 useQuestions : vi . fn ( ) ,
12+ useRefreshMessage : vi . fn ( ) ,
13+ useSessionAgent : vi . fn ( ) ,
1114} ) )
1215
1316vi . mock ( '@/stores/sessionStatusStore' , ( ) => ( {
@@ -27,6 +30,14 @@ vi.mock('@/contexts/EventContext', () => ({
2730 useQuestions : ( ) => mocks . useQuestions ( ) ,
2831} ) )
2932
33+ vi . mock ( '@/hooks/useRemoveMessage' , ( ) => ( {
34+ useRefreshMessage : ( ) => mocks . useRefreshMessage ( ) ,
35+ } ) )
36+
37+ vi . mock ( '@/hooks/useSessionAgent' , ( ) => ( {
38+ useSessionAgent : ( ) => mocks . useSessionAgent ( ) ,
39+ } ) )
40+
3041interface MockSettingsReturn {
3142 preferences : {
3243 simpleChatMode : boolean
@@ -147,6 +158,12 @@ describe('MessageThread', () => {
147158 mocks . useQuestions . mockReturnValue ( {
148159 getForCallID : vi . fn ( ( ) => null ) ,
149160 } )
161+ mocks . useRefreshMessage . mockReturnValue ( {
162+ isPending : false ,
163+ mutate : vi . fn ( ) ,
164+ } )
165+ mocks . useSessionAgent . mockReturnValue ( { agent : 'test-agent' } )
166+ useUIState . getState ( ) . setIsEditingMessage ( false )
150167 } )
151168
152169 it ( 'renders assistant message with only subtask part as standalone row without header' , ( ) => {
@@ -397,4 +414,74 @@ describe('MessageThread', () => {
397414 expect ( screen . getByText ( 'Hello' ) ) . toBeInTheDocument ( )
398415 expect ( screen . getByText ( 'You' ) ) . toBeInTheDocument ( )
399416 } )
417+
418+ it ( 'keeps global editing state active when edit textarea blurs' , ( ) => {
419+ setupSettings ( {
420+ simpleChatMode : false ,
421+ showReasoning : false ,
422+ } )
423+
424+ const messages = [
425+ createUserMessage ( '1' , 'Hello' ) ,
426+ createAssistantMessage ( '2' , [ createTextPart ( 'This is a response' , '2' ) ] ) ,
427+ ]
428+
429+ const { unmount } = render (
430+ < MessageThread
431+ opcodeUrl = "http://localhost:5551"
432+ sessionID = "test-session"
433+ messages = { messages as any }
434+ />
435+ )
436+
437+ fireEvent . click ( screen . getByTitle ( 'Edit message' ) )
438+ const textarea = screen . getByPlaceholderText ( 'Edit your message...' )
439+ fireEvent . focus ( textarea )
440+ expect ( useUIState . getState ( ) . isEditingMessage ) . toBe ( true )
441+
442+ fireEvent . blur ( textarea )
443+ expect ( useUIState . getState ( ) . isEditingMessage ) . toBe ( true )
444+
445+ unmount ( )
446+ expect ( useUIState . getState ( ) . isEditingMessage ) . toBe ( false )
447+ } )
448+
449+ it ( 'resends an edited prompt after the edit textarea blurs' , ( ) => {
450+ setupSettings ( {
451+ simpleChatMode : false ,
452+ showReasoning : false ,
453+ } )
454+ const mutate = vi . fn ( )
455+ mocks . useRefreshMessage . mockReturnValue ( {
456+ isPending : false ,
457+ mutate,
458+ } )
459+
460+ const messages = [
461+ createUserMessage ( '1' , 'Hello' ) ,
462+ createAssistantMessage ( '2' , [ createTextPart ( 'This is a response' , '2' ) ] ) ,
463+ ]
464+
465+ render (
466+ < MessageThread
467+ opcodeUrl = "http://localhost:5551"
468+ sessionID = "test-session"
469+ messages = { messages as any }
470+ />
471+ )
472+
473+ fireEvent . click ( screen . getByTitle ( 'Edit message' ) )
474+ const textarea = screen . getByPlaceholderText ( 'Edit your message...' )
475+ fireEvent . change ( textarea , { target : { value : 'Updated prompt' } } )
476+ fireEvent . blur ( textarea )
477+ fireEvent . click ( screen . getByRole ( 'button' , { name : / r e s e n d / i } ) )
478+
479+ expect ( mutate ) . toHaveBeenCalledWith (
480+ expect . objectContaining ( {
481+ assistantMessageID : '2' ,
482+ userMessageContent : 'Updated prompt' ,
483+ } ) ,
484+ expect . any ( Object ) ,
485+ )
486+ } )
400487} )
0 commit comments