@@ -1776,4 +1776,130 @@ describe("Cline", () => {
17761776 consoleErrorSpy . mockRestore ( )
17771777 } )
17781778 } )
1779+
1780+ describe ( "Message Queue Race Condition Fix" , ( ) => {
1781+ it ( "should process messages from queue when available" , async ( ) => {
1782+ const task = new Task ( {
1783+ provider : mockProvider ,
1784+ apiConfiguration : mockApiConfig ,
1785+ task : "test task" ,
1786+ startTask : false ,
1787+ } )
1788+
1789+ // Add a message to the queue
1790+ task . messageQueueService . addMessage ( "queued message" , [ "image.png" ] )
1791+
1792+ // Call ask which should process the queued message
1793+ const result = await task . ask ( "followup" , "Initial question" )
1794+
1795+ // Verify the queued message was processed
1796+ expect ( result . response ) . toBe ( "messageResponse" )
1797+ expect ( result . text ) . toBe ( "queued message" )
1798+ expect ( result . images ) . toEqual ( [ "image.png" ] )
1799+
1800+ // Verify queue is now empty
1801+ expect ( task . messageQueueService . isEmpty ( ) ) . toBe ( true )
1802+ } )
1803+
1804+ it ( "should handle tool approval messages from queue" , async ( ) => {
1805+ const task = new Task ( {
1806+ provider : mockProvider ,
1807+ apiConfiguration : mockApiConfig ,
1808+ task : "test task" ,
1809+ startTask : false ,
1810+ } )
1811+
1812+ // Add a message to the queue
1813+ task . messageQueueService . addMessage ( "approve with context" , [ "image.png" ] )
1814+
1815+ // Call ask for tool approval - should auto-approve with queued message
1816+ const result = await task . ask ( "tool" , "Do you want to use this tool?" )
1817+
1818+ // Verify the queued message was processed as tool approval
1819+ expect ( result . response ) . toBe ( "yesButtonClicked" )
1820+ expect ( result . text ) . toBe ( "approve with context" )
1821+ expect ( result . images ) . toEqual ( [ "image.png" ] )
1822+
1823+ // Verify queue is now empty
1824+ expect ( task . messageQueueService . isEmpty ( ) ) . toBe ( true )
1825+ } )
1826+
1827+ it ( "should check for new messages during wait period" , async ( ) => {
1828+ const task = new Task ( {
1829+ provider : mockProvider ,
1830+ apiConfiguration : mockApiConfig ,
1831+ task : "test task" ,
1832+ startTask : false ,
1833+ } )
1834+
1835+ // Mock pWaitFor to simulate adding a message during the wait
1836+ const originalPWaitFor = ( await import ( "p-wait-for" ) ) . default
1837+ let conditionCheckCount = 0
1838+ vi . mocked ( originalPWaitFor ) . mockImplementation ( async ( condition , options ) => {
1839+ // Simulate checking the condition multiple times
1840+ while ( true ) {
1841+ conditionCheckCount ++
1842+
1843+ // On the second check, add a message to the queue
1844+ if ( conditionCheckCount === 2 ) {
1845+ task . messageQueueService . addMessage ( "delayed message" )
1846+ // The condition should now detect the message and process it
1847+ task . setMessageResponse ( "delayed message" )
1848+ }
1849+
1850+ // Check the condition
1851+ const result = await condition ( )
1852+ if ( result ) {
1853+ return
1854+ }
1855+
1856+ // Prevent infinite loop
1857+ if ( conditionCheckCount > 5 ) {
1858+ // Force completion
1859+ task . setMessageResponse ( "forced completion" )
1860+ return
1861+ }
1862+
1863+ await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) )
1864+ }
1865+ } )
1866+
1867+ // Call ask - initially no messages in queue
1868+ const result = await task . ask ( "followup" , "Question" )
1869+
1870+ // Should have processed the message that was added during wait
1871+ expect ( result . response ) . toBe ( "messageResponse" )
1872+ expect ( result . text ) . toBe ( "delayed message" )
1873+
1874+ // Verify condition was checked multiple times
1875+ expect ( conditionCheckCount ) . toBeGreaterThan ( 1 )
1876+ } )
1877+
1878+ it ( "should handle multiple messages in queue" , async ( ) => {
1879+ const task = new Task ( {
1880+ provider : mockProvider ,
1881+ apiConfiguration : mockApiConfig ,
1882+ task : "test task" ,
1883+ startTask : false ,
1884+ } )
1885+
1886+ // Add multiple messages to the queue
1887+ task . messageQueueService . addMessage ( "first message" )
1888+ task . messageQueueService . addMessage ( "second message" )
1889+
1890+ // First ask should process first message
1891+ const result1 = await task . ask ( "followup" , "Question 1" )
1892+ expect ( result1 . text ) . toBe ( "first message" )
1893+
1894+ // Queue should still have one message
1895+ expect ( task . messageQueueService . isEmpty ( ) ) . toBe ( false )
1896+
1897+ // Second ask should process second message
1898+ const result2 = await task . ask ( "followup" , "Question 2" )
1899+ expect ( result2 . text ) . toBe ( "second message" )
1900+
1901+ // Queue should now be empty
1902+ expect ( task . messageQueueService . isEmpty ( ) ) . toBe ( true )
1903+ } )
1904+ } )
17791905} )
0 commit comments