@@ -59,6 +59,9 @@ jest.mock('vscode', () => ({
5959 joinPath : jest . fn ( ) ,
6060 file : jest . fn ( )
6161 } ,
62+ window : {
63+ showInformationMessage : jest . fn ( ) ,
64+ } ,
6265 workspace : {
6366 getConfiguration : jest . fn ( ) . mockReturnValue ( {
6467 get : jest . fn ( ) . mockReturnValue ( [ ] ) ,
@@ -123,7 +126,11 @@ jest.mock('../../Cline', () => {
123126 Cline : jest . fn ( ) . mockImplementation ( ( ) => ( {
124127 abortTask : jest . fn ( ) ,
125128 handleWebviewAskResponse : jest . fn ( ) ,
126- clineMessages : [ ]
129+ clineMessages : [ ] ,
130+ apiConversationHistory : [ ] ,
131+ overwriteClineMessages : jest . fn ( ) ,
132+ overwriteApiConversationHistory : jest . fn ( ) ,
133+ taskId : 'test-task-id'
127134 } ) )
128135 }
129136} )
@@ -380,4 +387,149 @@ describe('ClineProvider', () => {
380387 const result = await extractTextFromFile ( 'test.js' )
381388 expect ( result ) . toBe ( '1 | const x = 1;\n2 | const y = 2;\n3 | const z = 3;' )
382389 } )
390+
391+ describe ( 'deleteMessage' , ( ) => {
392+ beforeEach ( ( ) => {
393+ // Mock window.showInformationMessage
394+ ; ( vscode . window . showInformationMessage as jest . Mock ) = jest . fn ( )
395+ provider . resolveWebviewView ( mockWebviewView )
396+ } )
397+
398+ test ( 'handles "Just this message" deletion correctly' , async ( ) => {
399+ // Mock user selecting "Just this message"
400+ ; ( vscode . window . showInformationMessage as jest . Mock ) . mockResolvedValue ( 'Just this message' )
401+
402+ // Setup mock messages
403+ const mockMessages = [
404+ { ts : 1000 , type : 'say' , say : 'user_feedback' } , // User message 1
405+ { ts : 2000 , type : 'say' , say : 'tool' } , // Tool message
406+ { ts : 3000 , type : 'say' , say : 'text' , value : 4000 } , // Message to delete
407+ { ts : 4000 , type : 'say' , say : 'browser_action' } , // Response to delete
408+ { ts : 5000 , type : 'say' , say : 'user_feedback' } , // Next user message
409+ { ts : 6000 , type : 'say' , say : 'user_feedback' } // Final message
410+ ]
411+
412+ const mockApiHistory = [
413+ { ts : 1000 } ,
414+ { ts : 2000 } ,
415+ { ts : 3000 } ,
416+ { ts : 4000 } ,
417+ { ts : 5000 } ,
418+ { ts : 6000 }
419+ ]
420+
421+ // Setup Cline instance with mock data
422+ const mockCline = {
423+ clineMessages : mockMessages ,
424+ apiConversationHistory : mockApiHistory ,
425+ overwriteClineMessages : jest . fn ( ) ,
426+ overwriteApiConversationHistory : jest . fn ( ) ,
427+ taskId : 'test-task-id' ,
428+ abortTask : jest . fn ( ) ,
429+ handleWebviewAskResponse : jest . fn ( )
430+ }
431+ // @ts -ignore - accessing private property for testing
432+ provider . cline = mockCline
433+
434+ // Mock getTaskWithId
435+ ; ( provider as any ) . getTaskWithId = jest . fn ( ) . mockResolvedValue ( {
436+ historyItem : { id : 'test-task-id' }
437+ } )
438+
439+ // Trigger message deletion
440+ const messageHandler = ( mockWebviewView . webview . onDidReceiveMessage as jest . Mock ) . mock . calls [ 0 ] [ 0 ]
441+ await messageHandler ( { type : 'deleteMessage' , value : 4000 } )
442+
443+ // Verify correct messages were kept
444+ expect ( mockCline . overwriteClineMessages ) . toHaveBeenCalledWith ( [
445+ mockMessages [ 0 ] ,
446+ mockMessages [ 1 ] ,
447+ mockMessages [ 4 ] ,
448+ mockMessages [ 5 ]
449+ ] )
450+
451+ // Verify correct API messages were kept
452+ expect ( mockCline . overwriteApiConversationHistory ) . toHaveBeenCalledWith ( [
453+ mockApiHistory [ 0 ] ,
454+ mockApiHistory [ 1 ] ,
455+ mockApiHistory [ 4 ] ,
456+ mockApiHistory [ 5 ]
457+ ] )
458+ } )
459+
460+ test ( 'handles "This and all subsequent messages" deletion correctly' , async ( ) => {
461+ // Mock user selecting "This and all subsequent messages"
462+ ; ( vscode . window . showInformationMessage as jest . Mock ) . mockResolvedValue ( 'This and all subsequent messages' )
463+
464+ // Setup mock messages
465+ const mockMessages = [
466+ { ts : 1000 , type : 'say' , say : 'user_feedback' } ,
467+ { ts : 2000 , type : 'say' , say : 'text' , value : 3000 } , // Message to delete
468+ { ts : 3000 , type : 'say' , say : 'user_feedback' } ,
469+ { ts : 4000 , type : 'say' , say : 'user_feedback' }
470+ ]
471+
472+ const mockApiHistory = [
473+ { ts : 1000 } ,
474+ { ts : 2000 } ,
475+ { ts : 3000 } ,
476+ { ts : 4000 }
477+ ]
478+
479+ // Setup Cline instance with mock data
480+ const mockCline = {
481+ clineMessages : mockMessages ,
482+ apiConversationHistory : mockApiHistory ,
483+ overwriteClineMessages : jest . fn ( ) ,
484+ overwriteApiConversationHistory : jest . fn ( ) ,
485+ taskId : 'test-task-id' ,
486+ abortTask : jest . fn ( ) ,
487+ handleWebviewAskResponse : jest . fn ( )
488+ }
489+ // @ts -ignore - accessing private property for testing
490+ provider . cline = mockCline
491+
492+ // Mock getTaskWithId
493+ ; ( provider as any ) . getTaskWithId = jest . fn ( ) . mockResolvedValue ( {
494+ historyItem : { id : 'test-task-id' }
495+ } )
496+
497+ // Trigger message deletion
498+ const messageHandler = ( mockWebviewView . webview . onDidReceiveMessage as jest . Mock ) . mock . calls [ 0 ] [ 0 ]
499+ await messageHandler ( { type : 'deleteMessage' , value : 3000 } )
500+
501+ // Verify only messages before the deleted message were kept
502+ expect ( mockCline . overwriteClineMessages ) . toHaveBeenCalledWith ( [
503+ mockMessages [ 0 ]
504+ ] )
505+
506+ // Verify only API messages before the deleted message were kept
507+ expect ( mockCline . overwriteApiConversationHistory ) . toHaveBeenCalledWith ( [
508+ mockApiHistory [ 0 ]
509+ ] )
510+ } )
511+
512+ test ( 'handles Cancel correctly' , async ( ) => {
513+ // Mock user selecting "Cancel"
514+ ; ( vscode . window . showInformationMessage as jest . Mock ) . mockResolvedValue ( 'Cancel' )
515+
516+ const mockCline = {
517+ clineMessages : [ { ts : 1000 } , { ts : 2000 } ] ,
518+ apiConversationHistory : [ { ts : 1000 } , { ts : 2000 } ] ,
519+ overwriteClineMessages : jest . fn ( ) ,
520+ overwriteApiConversationHistory : jest . fn ( ) ,
521+ taskId : 'test-task-id'
522+ }
523+ // @ts -ignore - accessing private property for testing
524+ provider . cline = mockCline
525+
526+ // Trigger message deletion
527+ const messageHandler = ( mockWebviewView . webview . onDidReceiveMessage as jest . Mock ) . mock . calls [ 0 ] [ 0 ]
528+ await messageHandler ( { type : 'deleteMessage' , value : 2000 } )
529+
530+ // Verify no messages were deleted
531+ expect ( mockCline . overwriteClineMessages ) . not . toHaveBeenCalled ( )
532+ expect ( mockCline . overwriteApiConversationHistory ) . not . toHaveBeenCalled ( )
533+ } )
534+ } )
383535} )
0 commit comments