@@ -99,6 +99,10 @@ const emptyPollCounts = (): PollCounts => ({
9999 workspace_tree : 0 ,
100100} ) ;
101101
102+ test . beforeEach ( async ( { page } ) => {
103+ await closeAllOpenWorkspaces ( page ) ;
104+ } ) ;
105+
102106test . describe ( 'workspace transport baseline' , ( ) => {
103107 test ( 'fallback polling refreshes git/tree/worktree on the configured cadence' , async ( { page } ) => {
104108 const baseline = await observePollingBaseline ( page ) ;
@@ -347,15 +351,31 @@ async function observeWatcherInvalidationBaseline(page: Page): Promise<WatcherIn
347351 'e2e' ,
348352 `.transport-watcher-probe-${ process . pid } -${ Date . now ( ) } .txt` ,
349353 ) ;
354+ const predicate = ( payload : Record < string , unknown > ) =>
355+ payload . path === workspace . workspacePath && payload . reason === 'file_watcher' ;
350356
351357 await fs . mkdir ( path . dirname ( probeFile ) , { recursive : true } ) ;
352358 try {
353- await fs . writeFile ( probeFile , `watcher ${ Date . now ( ) } \n` , 'utf8' ) ;
354- const dirtyFrame = await waitForWsEvent (
355- page ,
356- 'workspace://artifacts_dirty' ,
357- ( payload ) => payload . path === workspace . workspacePath && payload . reason === 'file_watcher' ,
358- ) ;
359+ let dirtyFrame : WsEventFrame | null = null ;
360+ let lastError : unknown = null ;
361+ for ( let attempt = 0 ; attempt < 3 ; attempt += 1 ) {
362+ await fs . writeFile ( probeFile , `watcher ${ Date . now ( ) } -${ attempt } \n` , 'utf8' ) ;
363+ try {
364+ dirtyFrame = await waitForWsEvent (
365+ page ,
366+ 'workspace://artifacts_dirty' ,
367+ predicate ,
368+ 2500 ,
369+ ) ;
370+ break ;
371+ } catch ( error ) {
372+ lastError = error ;
373+ await page . waitForTimeout ( 350 ) ;
374+ }
375+ }
376+ if ( ! dirtyFrame ) {
377+ throw lastError ?? new Error ( 'watcher_invalidation_timeout' ) ;
378+ }
359379
360380 return {
361381 dirtyFrame,
@@ -381,12 +401,14 @@ async function observeGitIndexInvalidationBaseline(page: Page): Promise<GitIndex
381401 const predicate = ( payload : Record < string , unknown > ) =>
382402 payload . path === workspace . workspacePath && payload . reason === 'file_watcher' ;
383403 const baselineCount = await countWsEvents ( page , 'workspace://artifacts_dirty' , predicate ) ;
404+ const countsBeforeFileWrite = snapshotCounts ( probe . counts ) ;
384405
385406 await fs . mkdir ( path . dirname ( probeFile ) , { recursive : true } ) ;
386407 try {
387408 await fs . writeFile ( probeFile , `index ${ Date . now ( ) } \n` , 'utf8' ) ;
388409 await waitForWsEventCount ( page , 'workspace://artifacts_dirty' , predicate , baselineCount + 1 ) ;
389- await page . waitForTimeout ( 400 ) ;
410+ await waitForCountsAtLeast ( probe . counts , incrementCounts ( countsBeforeFileWrite ) ) ;
411+ await page . waitForTimeout ( 1000 ) ;
390412 const countsAfterFileWrite = await countWsEvents ( page , 'workspace://artifacts_dirty' , predicate ) ;
391413
392414 await execFileAsync ( 'git' , [ 'add' , '--' , probeFile ] , { cwd : WORKSPACE_PATH } ) ;
@@ -532,6 +554,18 @@ async function invokeRpc<T>(page: Page, command: string, payload: Record<string,
532554 return body . data as T ;
533555}
534556
557+ async function closeAllOpenWorkspaces ( page : Page ) {
558+ const bootstrap = await invokeRpc < {
559+ ui_state : {
560+ open_workspace_ids : string [ ] ;
561+ } ;
562+ } > ( page , 'workbench_bootstrap' ) ;
563+
564+ for ( const workspaceId of bootstrap . ui_state . open_workspace_ids ) {
565+ await invokeRpc ( page , 'close_workspace' , { workspace_id : workspaceId } ) ;
566+ }
567+ }
568+
535569async function waitForPollCycle ( counts : PollCounts ) {
536570 await expect
537571 . poll ( ( ) => {
@@ -551,6 +585,20 @@ async function waitForCounts(actual: PollCounts, expected: PollCounts) {
551585 . toEqual ( expected ) ;
552586}
553587
588+ async function waitForCountsAtLeast ( actual : PollCounts , expectedMinimum : PollCounts ) {
589+ await expect
590+ . poll ( ( ) => {
591+ const snapshot = snapshotCounts ( actual ) ;
592+ return snapshot . git_status >= expectedMinimum . git_status
593+ && snapshot . git_changes >= expectedMinimum . git_changes
594+ && snapshot . worktree_list >= expectedMinimum . worktree_list
595+ && snapshot . workspace_tree >= expectedMinimum . workspace_tree ;
596+ } , {
597+ timeout : 10000 ,
598+ } )
599+ . toBe ( true ) ;
600+ }
601+
554602function snapshotCounts ( counts : PollCounts ) : PollCounts {
555603 return {
556604 git_status : counts . git_status ,
@@ -602,6 +650,7 @@ async function waitForWsEvent(
602650 page : Page ,
603651 eventName : string ,
604652 predicate : ( payload : Record < string , unknown > ) => boolean ,
653+ timeoutMs = 10000 ,
605654) : Promise < WsEventFrame > {
606655 await expect
607656 . poll ( async ( ) => {
@@ -615,7 +664,7 @@ async function waitForWsEvent(
615664 ) ;
616665 return match ?? null ;
617666 } , {
618- timeout : 10000 ,
667+ timeout : timeoutMs ,
619668 } )
620669 . not . toBeNull ( ) ;
621670
@@ -650,10 +699,11 @@ async function waitForWsEventCount(
650699 eventName : string ,
651700 predicate : ( payload : Record < string , unknown > ) => boolean ,
652701 expectedCount : number ,
702+ timeoutMs = 10000 ,
653703) {
654704 await expect
655705 . poll ( ( ) => countWsEvents ( page , eventName , predicate ) , {
656- timeout : 10000 ,
706+ timeout : timeoutMs ,
657707 } )
658708 . toBeGreaterThanOrEqual ( expectedCount ) ;
659709}
0 commit comments