@@ -6,6 +6,7 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
66
77import { ExtensionStateContextProvider } from "@src/context/ExtensionStateContext"
88import { vscode } from "@src/utils/vscode"
9+ import type { SuggestionItem } from "@roo-code/types"
910
1011import ChatView , { ChatViewProps } from "../ChatView"
1112
@@ -46,7 +47,33 @@ vi.mock("use-sound", () => ({
4647
4748// Mock components that use ESM dependencies
4849vi . mock ( "../ChatRow" , ( ) => ( {
49- default : function MockChatRow ( { message } : { message : ClineMessage } ) {
50+ default : function MockChatRow ( {
51+ message,
52+ onSuggestionClick,
53+ } : {
54+ message : ClineMessage
55+ onSuggestionClick ?: ( suggestion : SuggestionItem , event ?: React . MouseEvent ) => void
56+ } ) {
57+ if ( message . type === "ask" && message . ask === "followup" && message . text ) {
58+ try {
59+ const followUp = JSON . parse ( message . text ) as { suggest ?: SuggestionItem [ ] }
60+ return (
61+ < div data-testid = "chat-row" >
62+ { followUp . suggest ?. map ( ( suggestion ) => (
63+ < button
64+ key = { suggestion . answer }
65+ type = "button"
66+ onClick = { ( event ) => onSuggestionClick ?.( suggestion , event ) } >
67+ { suggestion . answer }
68+ </ button >
69+ ) ) }
70+ </ div >
71+ )
72+ } catch {
73+ // Fall through to the generic row renderer.
74+ }
75+ }
76+
5077 return < div data-testid = "chat-row" > { JSON . stringify ( message ) } </ div >
5178 } ,
5279} ) )
@@ -1050,6 +1077,97 @@ describe("ChatView - Message Queueing Tests", () => {
10501077 } )
10511078} )
10521079
1080+ describe ( "ChatView - Follow-up Suggestions" , ( ) => {
1081+ beforeEach ( ( ) => {
1082+ vi . clearAllMocks ( )
1083+ vi . mocked ( vscode . postMessage ) . mockClear ( )
1084+ } )
1085+
1086+ it ( "switches to a known mode from a malformed object mode suggestion" , async ( ) => {
1087+ const { getByRole } = renderChatView ( )
1088+
1089+ mockPostMessage ( {
1090+ mode : "ask" ,
1091+ customModes : [ ] ,
1092+ clineMessages : [
1093+ {
1094+ type : "say" ,
1095+ say : "task" ,
1096+ ts : Date . now ( ) - 1000 ,
1097+ text : "Initial task" ,
1098+ } ,
1099+ {
1100+ type : "ask" ,
1101+ ask : "followup" ,
1102+ ts : Date . now ( ) ,
1103+ text : JSON . stringify ( {
1104+ question : "Switch mode?" ,
1105+ suggest : [ { answer : "Use code mode" , mode : { mode_slug : "code" } } ] ,
1106+ } ) ,
1107+ partial : false ,
1108+ } ,
1109+ ] ,
1110+ } )
1111+
1112+ const suggestion = await waitFor ( ( ) => getByRole ( "button" , { name : "Use code mode" } ) )
1113+ vi . mocked ( vscode . postMessage ) . mockClear ( )
1114+
1115+ fireEvent . click ( suggestion )
1116+
1117+ await waitFor ( ( ) => {
1118+ expect ( vscode . postMessage ) . toHaveBeenCalledWith ( { type : "mode" , text : "code" } )
1119+ } )
1120+ expect ( vscode . postMessage ) . toHaveBeenCalledWith ( {
1121+ type : "askResponse" ,
1122+ askResponse : "messageResponse" ,
1123+ text : "Use code mode" ,
1124+ images : [ ] ,
1125+ } )
1126+ } )
1127+
1128+ it ( "does not switch modes for an unknown malformed object mode suggestion" , async ( ) => {
1129+ const { getByRole } = renderChatView ( )
1130+
1131+ mockPostMessage ( {
1132+ mode : "ask" ,
1133+ customModes : [ ] ,
1134+ clineMessages : [
1135+ {
1136+ type : "say" ,
1137+ say : "task" ,
1138+ ts : Date . now ( ) - 1000 ,
1139+ text : "Initial task" ,
1140+ } ,
1141+ {
1142+ type : "ask" ,
1143+ ask : "followup" ,
1144+ ts : Date . now ( ) ,
1145+ text : JSON . stringify ( {
1146+ question : "Switch mode?" ,
1147+ suggest : [ { answer : "Use invalid mode" , mode : { mode_slug : "not-a-mode" } } ] ,
1148+ } ) ,
1149+ partial : false ,
1150+ } ,
1151+ ] ,
1152+ } )
1153+
1154+ const suggestion = await waitFor ( ( ) => getByRole ( "button" , { name : "Use invalid mode" } ) )
1155+ vi . mocked ( vscode . postMessage ) . mockClear ( )
1156+
1157+ fireEvent . click ( suggestion )
1158+
1159+ await waitFor ( ( ) => {
1160+ expect ( vscode . postMessage ) . toHaveBeenCalledWith ( {
1161+ type : "askResponse" ,
1162+ askResponse : "messageResponse" ,
1163+ text : "Use invalid mode" ,
1164+ images : [ ] ,
1165+ } )
1166+ } )
1167+ expect ( vscode . postMessage ) . not . toHaveBeenCalledWith ( expect . objectContaining ( { type : "mode" } ) )
1168+ } )
1169+ } )
1170+
10531171describe ( "ChatView - Context Condensing Indicator Tests" , ( ) => {
10541172 beforeEach ( ( ) => {
10551173 vi . clearAllMocks ( )
0 commit comments