@@ -225,7 +225,11 @@ const postState = (clineMessages: ClineMessage[]) => {
225225 } ,
226226 }
227227
228- window . postMessage ( message , "*" )
228+ window . dispatchEvent (
229+ new MessageEvent ( "message" , {
230+ data : message ,
231+ } ) ,
232+ )
229233}
230234
231235const renderView = ( ) =>
@@ -240,20 +244,42 @@ const renderView = () =>
240244const hydrate = async ( atBottomAfterCalls : number ) => {
241245 harness . atBottomAfterCalls = atBottomAfterCalls
242246 renderView ( )
247+ await act ( async ( ) => {
248+ await Promise . resolve ( )
249+ } )
243250 await act ( async ( ) => {
244251 postState ( buildMessages ( Date . now ( ) - 3_000 ) )
245252 } )
253+ await waitFor ( ( ) => {
254+ const list = document . querySelector ( "[data-testid='virtuoso-item-list']" )
255+ expect ( list ) . toBeTruthy ( )
256+ expect ( list ?. getAttribute ( "data-count" ) ) . toBe ( "2" )
257+ } )
246258}
247259
248260const waitForCalls = async ( min : number , timeout = 1_500 ) => {
249261 await waitFor ( ( ) => expect ( harness . scrollCalls ) . toBeGreaterThanOrEqual ( min ) , { timeout } )
250262}
251263
252- const expectCallsStable = async ( ms = 120 ) => {
253- await sleep ( ms )
254- const snapshot = harness . scrollCalls
255- await sleep ( ms )
256- expect ( harness . scrollCalls ) . toBe ( snapshot )
264+ const waitForCallsSettled = async ( idleMs = 80 , timeoutMs = 2_000 ) => {
265+ const deadline = Date . now ( ) + timeoutMs
266+ let lastSeen = harness . scrollCalls
267+
268+ while ( Date . now ( ) < deadline ) {
269+ await sleep ( idleMs )
270+ const current = harness . scrollCalls
271+
272+ if ( current === lastSeen ) {
273+ await sleep ( idleMs )
274+ if ( harness . scrollCalls === current ) {
275+ return
276+ }
277+ }
278+
279+ lastSeen = current
280+ }
281+
282+ throw new Error ( `Expected scroll calls to settle within ${ timeoutMs } ms, last count: ${ harness . scrollCalls } ` )
257283}
258284
259285const getScrollable = ( ) : HTMLElement => {
@@ -291,7 +317,7 @@ describe("ChatView scroll behavior regression coverage", () => {
291317 it ( "rehydration converges to bottom" , async ( ) => {
292318 await hydrate ( 6 )
293319 await waitForCalls ( 6 , 2_000 )
294- await expectCallsStable ( )
320+ await waitForCallsSettled ( )
295321 expect ( document . querySelector ( ".codicon-chevron-down" ) ) . toBeNull ( )
296322 } )
297323
@@ -302,7 +328,7 @@ describe("ChatView scroll behavior regression coverage", () => {
302328 expect ( document . querySelector ( ".codicon-chevron-down" ) ) . toBeNull ( )
303329
304330 await waitForCalls ( 8 , 2_000 )
305- await expectCallsStable ( )
331+ await waitForCallsSettled ( )
306332 expect ( resolveFollowOutput ( false ) ) . toBe ( "auto" )
307333 } )
308334
@@ -327,7 +353,7 @@ describe("ChatView scroll behavior regression coverage", () => {
327353 it ( "non-wheel upward intent disengages sticky follow" , async ( ) => {
328354 await hydrate ( 4 )
329355 await waitForCalls ( 4 )
330- await expectCallsStable ( )
356+ await waitForCallsSettled ( )
331357 expect ( resolveFollowOutput ( false ) ) . toBe ( "auto" )
332358
333359 const scrollable = getScrollable ( )
@@ -346,7 +372,7 @@ describe("ChatView scroll behavior regression coverage", () => {
346372 it ( "nested scroller scroll events do not falsely disengage sticky follow" , async ( ) => {
347373 await hydrate ( 4 )
348374 await waitForCalls ( 4 )
349- await expectCallsStable ( )
375+ await waitForCallsSettled ( )
350376 expect ( resolveFollowOutput ( false ) ) . toBe ( "auto" )
351377
352378 const scrollable = getScrollable ( )
@@ -371,7 +397,7 @@ describe("ChatView scroll behavior regression coverage", () => {
371397 it ( "wheel-up intent disengages sticky follow" , async ( ) => {
372398 await hydrate ( 4 )
373399 await waitForCalls ( 4 )
374- await expectCallsStable ( )
400+ await waitForCallsSettled ( )
375401 expect ( resolveFollowOutput ( false ) ) . toBe ( "auto" )
376402
377403 const scrollable = getScrollable ( )
@@ -413,7 +439,7 @@ describe("ChatView scroll behavior regression coverage", () => {
413439 it ( "scroll-to-bottom CTA re-anchors with one interaction" , async ( ) => {
414440 await hydrate ( 4 )
415441 await waitForCalls ( 4 )
416- await expectCallsStable ( )
442+ await waitForCallsSettled ( )
417443 expect ( resolveFollowOutput ( false ) ) . toBe ( "auto" )
418444
419445 await act ( async ( ) => {
0 commit comments