@@ -1733,6 +1733,49 @@ describe("Cline", () => {
17331733 expect ( messageListener ) . toHaveBeenCalledWith ( { action : "created" , message } )
17341734 } )
17351735
1736+ it ( "continues the message lifecycle when throttled state scheduling and flushing fail" , async ( ) => {
1737+ const task = new Task ( {
1738+ provider : mockProvider ,
1739+ apiConfiguration : mockApiConfig ,
1740+ task : "test task" ,
1741+ startTask : false ,
1742+ } )
1743+ const taskAccess = getTaskTestAccess ( task )
1744+ const postError = new Error ( "state schedule failed" )
1745+ const flushError = new Error ( "state flush failed" )
1746+ const postSpy = vi . mocked ( mockProvider . postStateToWebviewThrottled ) . mockRejectedValueOnce ( postError )
1747+ const flushSpy = vi . mocked ( mockProvider . flushPostStateToWebviewThrottled ) . mockRejectedValueOnce ( flushError )
1748+ const saveSpy = vi . spyOn ( taskAccess , "saveClineMessages" ) . mockResolvedValue ( true )
1749+ const messageListener = vi . fn ( )
1750+ const consoleErrorSpy = vi . spyOn ( console , "error" ) . mockImplementation ( ( ) => { } )
1751+ task . on ( RooCodeEventName . Message , messageListener )
1752+ const message = {
1753+ ts : 1 ,
1754+ type : "ask" as const ,
1755+ ask : "resume_task" as const ,
1756+ }
1757+
1758+ await expect ( taskAccess . addToClineMessages ( message ) ) . resolves . toBeUndefined ( )
1759+
1760+ expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
1761+ "[Task#addToClineMessages] postStateToWebviewThrottled failed:" ,
1762+ postError ,
1763+ )
1764+ expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
1765+ "[Task#addToClineMessages] flushPostStateToWebviewThrottled failed:" ,
1766+ flushError ,
1767+ )
1768+ expect ( postSpy ) . toHaveBeenCalledOnce ( )
1769+ expect ( flushSpy ) . toHaveBeenCalledOnce ( )
1770+ expect ( messageListener ) . toHaveBeenCalledWith ( { action : "created" , message } )
1771+ expect ( saveSpy ) . toHaveBeenCalledOnce ( )
1772+ expect ( postSpy . mock . invocationCallOrder [ 0 ] ) . toBeLessThan ( flushSpy . mock . invocationCallOrder [ 0 ] )
1773+ expect ( flushSpy . mock . invocationCallOrder [ 0 ] ) . toBeLessThan ( messageListener . mock . invocationCallOrder [ 0 ] )
1774+ expect ( messageListener . mock . invocationCallOrder [ 0 ] ) . toBeLessThan ( saveSpy . mock . invocationCallOrder [ 0 ] )
1775+
1776+ consoleErrorSpy . mockRestore ( )
1777+ } )
1778+
17361779 it ( "keeps an already answered ask on the throttled path" , async ( ) => {
17371780 const task = new Task ( {
17381781 provider : mockProvider ,
@@ -1877,6 +1920,38 @@ describe("Cline", () => {
18771920 )
18781921 } )
18791922
1923+ it ( "continues abort cleanup when flushing pending state fails" , async ( ) => {
1924+ const task = new Task ( {
1925+ provider : mockProvider ,
1926+ apiConfiguration : mockApiConfig ,
1927+ task : "test task" ,
1928+ startTask : false ,
1929+ } )
1930+ const error = new Error ( "state flush failed" )
1931+ const flushSpy = vi . mocked ( mockProvider . flushPostStateToWebviewThrottled ) . mockRejectedValueOnce ( error )
1932+ const taskAbortedListener = vi . fn ( )
1933+ const disposeSpy = vi . spyOn ( task , "dispose" ) . mockImplementation ( ( ) => { } )
1934+ const saveSpy = vi . spyOn ( getTaskTestAccess ( task ) , "saveClineMessages" ) . mockResolvedValue ( true )
1935+ const consoleErrorSpy = vi . spyOn ( console , "error" ) . mockImplementation ( ( ) => { } )
1936+ task . on ( RooCodeEventName . TaskAborted , taskAbortedListener )
1937+
1938+ await expect ( task . abortTask ( ) ) . resolves . toBeUndefined ( )
1939+
1940+ expect ( consoleErrorSpy ) . toHaveBeenCalledWith (
1941+ `[Task#abortTask] flushPostStateToWebviewThrottled failed for ${ task . taskId } .${ task . instanceId } :` ,
1942+ error ,
1943+ )
1944+ expect ( task . abort ) . toBe ( true )
1945+ expect ( flushSpy ) . toHaveBeenCalledOnce ( )
1946+ expect ( taskAbortedListener ) . toHaveBeenCalledOnce ( )
1947+ expect ( disposeSpy ) . toHaveBeenCalledOnce ( )
1948+ expect ( saveSpy ) . toHaveBeenCalledOnce ( )
1949+ expect ( flushSpy . mock . invocationCallOrder [ 0 ] ) . toBeLessThan ( taskAbortedListener . mock . invocationCallOrder [ 0 ] )
1950+ expect ( taskAbortedListener . mock . invocationCallOrder [ 0 ] ) . toBeLessThan ( disposeSpy . mock . invocationCallOrder [ 0 ] )
1951+
1952+ consoleErrorSpy . mockRestore ( )
1953+ } )
1954+
18801955 it ( "should work with TaskLike interface" , async ( ) => {
18811956 const task = new Task ( {
18821957 provider : mockProvider ,
0 commit comments