@@ -176,6 +176,7 @@ describe("retainThreadDetailSubscription", () => {
176176 } ,
177177 } ) ) ,
178178 } ,
179+ isHeartbeatFresh : vi . fn ( ( ) => true ) ,
179180 orchestration : {
180181 subscribeThread : mockSubscribeThread ,
181182 } ,
@@ -382,7 +383,7 @@ describe("retainThreadDetailSubscription", () => {
382383 await resetEnvironmentServiceForTests ( ) ;
383384 } ) ;
384385
385- it ( "reconnects environment streams when the browser resumes from the background" , async ( ) => {
386+ it ( "keeps healthy environment streams connected when the browser resumes from the background" , async ( ) => {
386387 let visibilityState : DocumentVisibilityState = "visible" ;
387388 const documentTarget = new EventTarget ( ) ;
388389 const windowTarget = new EventTarget ( ) ;
@@ -408,6 +409,57 @@ describe("retainThreadDetailSubscription", () => {
408409 documentTarget . dispatchEvent ( new Event ( "visibilitychange" ) ) ;
409410 expect ( mockConnectionReconnects [ 0 ] ) . not . toHaveBeenCalled ( ) ;
410411
412+ visibilityState = "visible" ;
413+ documentTarget . dispatchEvent ( new Event ( "visibilitychange" ) ) ;
414+ expect ( mockConnectionReconnects [ 0 ] ) . not . toHaveBeenCalled ( ) ;
415+
416+ stop ( ) ;
417+ await resetEnvironmentServiceForTests ( ) ;
418+ } ) ;
419+
420+ it ( "reconnects stale environment streams when the browser resumes from the background" , async ( ) => {
421+ let visibilityState : DocumentVisibilityState = "visible" ;
422+ const documentTarget = new EventTarget ( ) ;
423+ const windowTarget = new EventTarget ( ) ;
424+ vi . stubGlobal ( "document" , {
425+ addEventListener : documentTarget . addEventListener . bind ( documentTarget ) ,
426+ removeEventListener : documentTarget . removeEventListener . bind ( documentTarget ) ,
427+ get visibilityState ( ) {
428+ return visibilityState ;
429+ } ,
430+ } ) ;
431+ vi . stubGlobal ( "window" , {
432+ addEventListener : windowTarget . addEventListener . bind ( windowTarget ) ,
433+ removeEventListener : windowTarget . removeEventListener . bind ( windowTarget ) ,
434+ } ) ;
435+ mockCreateWsRpcClient . mockReturnValue ( {
436+ server : {
437+ getConfig : vi . fn ( async ( ) => ( {
438+ environment : {
439+ environmentId : EnvironmentId . make ( "env-remote" ) ,
440+ label : "Remote env" ,
441+ platform : { os : "darwin" , arch : "arm64" } ,
442+ serverVersion : "0.0.0-test" ,
443+ capabilities : { repositoryIdentity : true } ,
444+ } ,
445+ } ) ) ,
446+ } ,
447+ isHeartbeatFresh : vi . fn ( ( ) => false ) ,
448+ orchestration : {
449+ subscribeThread : mockSubscribeThread ,
450+ } ,
451+ } ) ;
452+
453+ const { resetEnvironmentServiceForTests, startEnvironmentConnectionService } =
454+ await import ( "./service" ) ;
455+
456+ const stop = startEnvironmentConnectionService ( new QueryClient ( ) ) ;
457+ expect ( mockConnectionReconnects ) . toHaveLength ( 1 ) ;
458+
459+ visibilityState = "hidden" ;
460+ documentTarget . dispatchEvent ( new Event ( "visibilitychange" ) ) ;
461+ expect ( mockConnectionReconnects [ 0 ] ) . not . toHaveBeenCalled ( ) ;
462+
411463 visibilityState = "visible" ;
412464 documentTarget . dispatchEvent ( new Event ( "visibilitychange" ) ) ;
413465 expect ( mockConnectionReconnects [ 0 ] ) . toHaveBeenCalledTimes ( 1 ) ;
0 commit comments