@@ -214,6 +214,7 @@ test('scrollintoview @ref dispatches geometry-based swipe series', async () => {
214214 positionals : string [ ] ;
215215 context : Record < string , unknown > | undefined ;
216216 } > = [ ] ;
217+ let snapshotCallCount = 0 ;
217218 const response = await handleInteractionCommands ( {
218219 req : {
219220 token : 't' ,
@@ -226,13 +227,24 @@ test('scrollintoview @ref dispatches geometry-based swipe series', async () => {
226227 sessionStore,
227228 contextFromFlags,
228229 dispatch : async ( _device , command , positionals , _out , context ) => {
230+ if ( command === 'snapshot' ) {
231+ snapshotCallCount += 1 ;
232+ return {
233+ nodes : [
234+ { index : 0 , type : 'Application' , rect : { x : 0 , y : 0 , width : 390 , height : 844 } } ,
235+ { index : 1 , type : 'XCUIElementTypeStaticText' , label : 'Far item' , rect : { x : 20 , y : 320 , width : 120 , height : 40 } } ,
236+ ] ,
237+ backend : 'xctest' ,
238+ } ;
239+ }
229240 dispatchCalls . push ( { command, positionals, context : context as Record < string , unknown > | undefined } ) ;
230241 return { ok : true } ;
231242 } ,
232243 } ) ;
233244
234245 assert . ok ( response ) ;
235246 assert . equal ( response . ok , true ) ;
247+ assert . equal ( snapshotCallCount , 1 ) ;
236248 assert . equal ( dispatchCalls . length , 1 ) ;
237249 assert . equal ( dispatchCalls [ 0 ] ?. command , 'swipe' ) ;
238250 assert . equal ( dispatchCalls [ 0 ] ?. positionals . length , 5 ) ;
@@ -248,6 +260,7 @@ test('scrollintoview @ref dispatches geometry-based swipe series', async () => {
248260 const result = ( stored ?. actions [ 0 ] ?. result ?? { } ) as Record < string , unknown > ;
249261 assert . equal ( result . ref , 'e2' ) ;
250262 assert . equal ( result . strategy , 'ref-geometry' ) ;
263+ assert . equal ( result . verified , true ) ;
251264} ) ;
252265
253266test ( 'scrollintoview @ref returns immediately when target is already in viewport safe band' , async ( ) => {
@@ -299,3 +312,59 @@ test('scrollintoview @ref returns immediately when target is already in viewport
299312 assert . equal ( response . data ?. alreadyVisible , true ) ;
300313 }
301314} ) ;
315+
316+ test ( 'scrollintoview @ref fails if target remains outside viewport after scroll' , async ( ) => {
317+ const sessionStore = makeSessionStore ( ) ;
318+ const sessionName = 'default' ;
319+ const session = makeSession ( sessionName ) ;
320+ session . snapshot = {
321+ nodes : attachRefs ( [
322+ {
323+ index : 0 ,
324+ type : 'Application' ,
325+ rect : { x : 0 , y : 0 , width : 390 , height : 844 } ,
326+ } ,
327+ {
328+ index : 1 ,
329+ type : 'XCUIElementTypeStaticText' ,
330+ label : 'Far item' ,
331+ rect : { x : 20 , y : 2600 , width : 120 , height : 40 } ,
332+ } ,
333+ ] ) ,
334+ createdAt : Date . now ( ) ,
335+ backend : 'xctest' ,
336+ } ;
337+ sessionStore . set ( sessionName , session ) ;
338+
339+ const response = await handleInteractionCommands ( {
340+ req : {
341+ token : 't' ,
342+ session : sessionName ,
343+ command : 'scrollintoview' ,
344+ positionals : [ '@e2' ] ,
345+ flags : { } ,
346+ } ,
347+ sessionName,
348+ sessionStore,
349+ contextFromFlags,
350+ dispatch : async ( _device , command ) => {
351+ if ( command === 'snapshot' ) {
352+ return {
353+ nodes : [
354+ { index : 0 , type : 'Application' , rect : { x : 0 , y : 0 , width : 390 , height : 844 } } ,
355+ { index : 1 , type : 'XCUIElementTypeStaticText' , label : 'Far item' , rect : { x : 20 , y : 2600 , width : 120 , height : 40 } } ,
356+ ] ,
357+ backend : 'xctest' ,
358+ } ;
359+ }
360+ return { ok : true } ;
361+ } ,
362+ } ) ;
363+
364+ assert . ok ( response ) ;
365+ assert . equal ( response . ok , false ) ;
366+ if ( ! response . ok ) {
367+ assert . equal ( response . error ?. code , 'COMMAND_FAILED' ) ;
368+ assert . match ( response . error ?. message ?? '' , / o u t s i d e v i e w p o r t / i) ;
369+ }
370+ } ) ;
0 commit comments