@@ -1081,6 +1081,188 @@ describe("ChatView - Message Queueing Tests", () => {
10811081 } ) ,
10821082 )
10831083 } )
1084+
1085+ it ( "queues messages when tool approval buttons are shown (tool state) - Issue #10675" , async ( ) => {
1086+ const { getByTestId, container } = renderChatView ( )
1087+
1088+ // Hydrate state with a tool ask (file edit approval)
1089+ mockPostMessage ( {
1090+ clineMessages : [
1091+ {
1092+ type : "say" ,
1093+ say : "task" ,
1094+ ts : Date . now ( ) - 2000 ,
1095+ text : "Initial task" ,
1096+ } ,
1097+ {
1098+ type : "ask" ,
1099+ ask : "tool" ,
1100+ ts : Date . now ( ) ,
1101+ text : JSON . stringify ( { tool : "editedExistingFile" , path : "test.txt" , diff : "some diff" } ) ,
1102+ partial : false , // Buttons are shown when not partial
1103+ } ,
1104+ ] ,
1105+ } )
1106+
1107+ // Wait for buttons to become enabled (indicates enableButtons = true)
1108+ await waitFor ( ( ) => {
1109+ const buttons = container . querySelectorAll ( "button" )
1110+ const saveButton = Array . from ( buttons ) . find ( ( btn ) => btn . textContent ?. includes ( "chat:save.title" ) )
1111+ expect ( saveButton ) . toBeTruthy ( )
1112+ expect ( saveButton ) . not . toHaveAttribute ( "disabled" )
1113+ } )
1114+
1115+ // Clear message calls before simulating user input
1116+ vi . mocked ( vscode . postMessage ) . mockClear ( )
1117+
1118+ // Simulate user typing and sending a message while Save/Reject buttons are shown
1119+ const chatTextArea = getByTestId ( "chat-textarea" )
1120+ const input = chatTextArea . querySelector ( "input" ) ! as HTMLInputElement
1121+
1122+ await act ( async ( ) => {
1123+ fireEvent . change ( input , { target : { value : "additional context for later" } } )
1124+ fireEvent . keyDown ( input , { key : "Enter" , code : "Enter" } )
1125+ } )
1126+
1127+ // Verify that the message was queued, not sent as askResponse
1128+ await waitFor ( ( ) => {
1129+ expect ( vscode . postMessage ) . toHaveBeenCalledWith ( {
1130+ type : "queueMessage" ,
1131+ text : "additional context for later" ,
1132+ images : [ ] ,
1133+ } )
1134+ } )
1135+
1136+ // Verify it was NOT sent as askResponse (which would cause the message to be lost)
1137+ expect ( vscode . postMessage ) . not . toHaveBeenCalledWith (
1138+ expect . objectContaining ( {
1139+ type : "askResponse" ,
1140+ askResponse : "messageResponse" ,
1141+ } ) ,
1142+ )
1143+ } )
1144+
1145+ it ( "queues messages when command approval buttons are shown (command state)" , async ( ) => {
1146+ const { getByTestId, container } = renderChatView ( )
1147+
1148+ // Hydrate state with a command ask (command approval)
1149+ mockPostMessage ( {
1150+ clineMessages : [
1151+ {
1152+ type : "say" ,
1153+ say : "task" ,
1154+ ts : Date . now ( ) - 2000 ,
1155+ text : "Initial task" ,
1156+ } ,
1157+ {
1158+ type : "ask" ,
1159+ ask : "command" ,
1160+ ts : Date . now ( ) ,
1161+ text : "npm install" ,
1162+ partial : false , // Buttons are shown when not partial
1163+ } ,
1164+ ] ,
1165+ } )
1166+
1167+ // Wait for buttons to become enabled (indicates enableButtons = true)
1168+ await waitFor ( ( ) => {
1169+ const buttons = container . querySelectorAll ( "button" )
1170+ const runButton = Array . from ( buttons ) . find ( ( btn ) => btn . textContent ?. includes ( "chat:runCommand.title" ) )
1171+ expect ( runButton ) . toBeTruthy ( )
1172+ expect ( runButton ) . not . toHaveAttribute ( "disabled" )
1173+ } )
1174+
1175+ // Clear message calls before simulating user input
1176+ vi . mocked ( vscode . postMessage ) . mockClear ( )
1177+
1178+ // Simulate user typing and sending a message while Run Command/Reject buttons are shown
1179+ const chatTextArea = getByTestId ( "chat-textarea" )
1180+ const input = chatTextArea . querySelector ( "input" ) ! as HTMLInputElement
1181+
1182+ await act ( async ( ) => {
1183+ fireEvent . change ( input , { target : { value : "wait, let me think about this" } } )
1184+ fireEvent . keyDown ( input , { key : "Enter" , code : "Enter" } )
1185+ } )
1186+
1187+ // Verify that the message was queued, not sent as askResponse
1188+ await waitFor ( ( ) => {
1189+ expect ( vscode . postMessage ) . toHaveBeenCalledWith ( {
1190+ type : "queueMessage" ,
1191+ text : "wait, let me think about this" ,
1192+ images : [ ] ,
1193+ } )
1194+ } )
1195+
1196+ // Verify it was NOT sent as askResponse
1197+ expect ( vscode . postMessage ) . not . toHaveBeenCalledWith (
1198+ expect . objectContaining ( {
1199+ type : "askResponse" ,
1200+ askResponse : "messageResponse" ,
1201+ } ) ,
1202+ )
1203+ } )
1204+
1205+ it ( "queues messages when command is running (command_output state) - Issue #10675" , async ( ) => {
1206+ const { getByTestId, container } = renderChatView ( )
1207+
1208+ // Hydrate state with a command_output ask (command running)
1209+ mockPostMessage ( {
1210+ clineMessages : [
1211+ {
1212+ type : "say" ,
1213+ say : "task" ,
1214+ ts : Date . now ( ) - 2000 ,
1215+ text : "Initial task" ,
1216+ } ,
1217+ {
1218+ type : "ask" ,
1219+ ask : "command_output" ,
1220+ ts : Date . now ( ) ,
1221+ text : "Running sleep 60..." ,
1222+ partial : false ,
1223+ } ,
1224+ ] ,
1225+ } )
1226+
1227+ // Wait for buttons to become enabled (indicates enableButtons = true)
1228+ await waitFor ( ( ) => {
1229+ const buttons = container . querySelectorAll ( "button" )
1230+ const proceedButton = Array . from ( buttons ) . find ( ( btn ) =>
1231+ btn . textContent ?. includes ( "chat:proceedWhileRunning.title" ) ,
1232+ )
1233+ expect ( proceedButton ) . toBeTruthy ( )
1234+ expect ( proceedButton ) . not . toHaveAttribute ( "disabled" )
1235+ } )
1236+
1237+ // Clear message calls before simulating user input
1238+ vi . mocked ( vscode . postMessage ) . mockClear ( )
1239+
1240+ // Simulate user typing and sending a message while Proceed While Running/Kill Command buttons are shown
1241+ const chatTextArea = getByTestId ( "chat-textarea" )
1242+ const input = chatTextArea . querySelector ( "input" ) ! as HTMLInputElement
1243+
1244+ await act ( async ( ) => {
1245+ fireEvent . change ( input , { target : { value : "clarifying message for later" } } )
1246+ fireEvent . keyDown ( input , { key : "Enter" , code : "Enter" } )
1247+ } )
1248+
1249+ // Verify that the message was queued, not sent as askResponse
1250+ await waitFor ( ( ) => {
1251+ expect ( vscode . postMessage ) . toHaveBeenCalledWith ( {
1252+ type : "queueMessage" ,
1253+ text : "clarifying message for later" ,
1254+ images : [ ] ,
1255+ } )
1256+ } )
1257+
1258+ // Verify it was NOT sent as askResponse (which would cause the message to be lost)
1259+ expect ( vscode . postMessage ) . not . toHaveBeenCalledWith (
1260+ expect . objectContaining ( {
1261+ type : "askResponse" ,
1262+ askResponse : "messageResponse" ,
1263+ } ) ,
1264+ )
1265+ } )
10841266} )
10851267
10861268describe ( "ChatView - Context Condensing Indicator Tests" , ( ) => {
0 commit comments