@@ -99,6 +99,52 @@ describe("waitForBrowserExpectation", () => {
9999 expect ( result ) . toMatchObject ( { status : reason === "observation_failed" ? "unverifiable" : "interrupted" , reason } ) ;
100100 } ) ;
101101
102+ it ( "does not treat a reset frame generation as navigation when epochs match" , async ( ) => {
103+ let time = 0 , reads = 0 ;
104+ const generations = new Map < string , number > ( ) ;
105+ const result = await waitForBrowserExpectation ( {
106+ selectTarget : async ( ) => "page" ,
107+ observeTarget : async ( ) => {
108+ const current = reads ++ === 0
109+ ? observation ( [ ] , true , { generations : new Map ( [ [ "page" , 0 ] , [ "frame" , 2 ] ] ) } )
110+ : observation ( [ ] , true , { generations : new Map ( [ [ "page" , 0 ] , [ "frame" , 0 ] ] ) } ) ;
111+ generations . clear ( ) ;
112+ for ( const [ key , generation ] of current . generations ) generations . set ( key , generation ) ;
113+ return current ;
114+ } ,
115+ dialogCount : ( ) => 0 ,
116+ targetExists : async ( ) => true ,
117+ liveGeneration : ( key ) => generations . get ( key ) ?? 0 ,
118+ resolveRef : missingRef ,
119+ now : ( ) => time ,
120+ delay : async ( ms ) => { time += ms ; } ,
121+ } , { expect : { type : "text" , text : "Ready" } , timeoutMs : 20 , pollMs : 10 } ) ;
122+ expect ( result ) . toMatchObject ( { status : "timed_out" , evidence : "failed" } ) ;
123+ } ) ;
124+
125+ it ( "interrupts absence waits when complete observations drop baseline frames" , async ( ) => {
126+ let time = 0 , reads = 0 ;
127+ const generations = new Map < string , number > ( ) ;
128+ const result = await waitForBrowserExpectation ( {
129+ selectTarget : async ( ) => "page" ,
130+ observeTarget : async ( ) => {
131+ const current = reads ++ === 0
132+ ? observation ( [ "Ready" ] , true , { generations : new Map ( [ [ "page" , 0 ] , [ "frame" , 1 ] ] ) } )
133+ : observation ( [ ] , true , { generations : new Map ( [ [ "page" , 0 ] ] ) } ) ;
134+ generations . clear ( ) ;
135+ for ( const [ key , generation ] of current . generations ) generations . set ( key , generation ) ;
136+ return current ;
137+ } ,
138+ dialogCount : ( ) => 0 ,
139+ targetExists : async ( ) => true ,
140+ liveGeneration : ( key ) => generations . get ( key ) ?? 0 ,
141+ resolveRef : missingRef ,
142+ now : ( ) => time ,
143+ delay : async ( ms ) => { time += ms ; } ,
144+ } , { expect : { type : "text" , text : "Ready" , exists : false } , timeoutMs : 20 , pollMs : 10 } ) ;
145+ expect ( result ) . toMatchObject ( { status : "interrupted" , reason : "navigation" } ) ;
146+ } ) ;
147+
102148 it ( "interrupts when a ref becomes stale after the baseline" , async ( ) => {
103149 let time = 0 , resolves = 0 ;
104150 const resolveRef : BrowserRefResolver = ( ) => resolves ++ === 0 ? { truth : false , details : [ "not checked" ] } : { truth : undefined , details : [ "stale" ] , reason : "stale_ref" } ;
0 commit comments