@@ -15,7 +15,7 @@ import type { SessionState } from '../types.ts';
1515import { LeaseRegistry } from '../lease-registry.ts' ;
1616import { attachRefs } from '../../utils/snapshot.ts' ;
1717import { PNG } from 'pngjs' ;
18- import { ANDROID_EMULATOR } from '../../__tests__/test-utils/device-fixtures.ts' ;
18+ import { ANDROID_EMULATOR , IOS_SIMULATOR } from '../../__tests__/test-utils/device-fixtures.ts' ;
1919import { makeSessionStore } from '../../__tests__/test-utils/store-factory.ts' ;
2020import { makeSession as makeBaseSession } from '../../__tests__/test-utils/session-factories.ts' ;
2121
@@ -25,6 +25,10 @@ function makeSession(name: string): SessionState {
2525 return makeBaseSession ( name , { device : ANDROID_EMULATOR } ) ;
2626}
2727
28+ function makeIosSession ( name : string ) : SessionState {
29+ return makeBaseSession ( name , { device : IOS_SIMULATOR } ) ;
30+ }
31+
2832function makeMacOsMenubarSession ( name : string ) : SessionState {
2933 return {
3034 name,
@@ -415,6 +419,102 @@ test('screenshot --overlay-refs captures a fresh snapshot when the session has n
415419 expect ( mockDispatch . mock . calls . map ( ( call ) => call [ 1 ] ) ) . toEqual ( [ 'screenshot' , 'snapshot' ] ) ;
416420} ) ;
417421
422+ test ( 'screenshot --overlay-refs uses interactive iOS presentation for row-like other nodes' , async ( ) => {
423+ const sessionStore = makeSessionStore ( 'agent-device-router-screenshot-' ) ;
424+ sessionStore . set ( 'default' , makeIosSession ( 'default' ) ) ;
425+ const screenshotPath = path . join ( os . tmpdir ( ) , `agent-device-overlay-ios-${ Date . now ( ) } .png` ) ;
426+
427+ mockDispatch . mockImplementation ( async ( _device , command ) => {
428+ if ( command === 'screenshot' ) {
429+ writeSolidPng ( screenshotPath , 402 , 874 ) ;
430+ return { path : screenshotPath } ;
431+ }
432+ if ( command === 'snapshot' ) {
433+ return {
434+ backend : 'xctest' ,
435+ nodes : [
436+ {
437+ index : 0 ,
438+ depth : 0 ,
439+ type : 'Application' ,
440+ label : 'New Expensify Dev' ,
441+ rect : { x : 0 , y : 0 , width : 402 , height : 874 } ,
442+ } ,
443+ {
444+ index : 1 ,
445+ depth : 1 ,
446+ parentIndex : 0 ,
447+ type : 'Other' ,
448+ label : '!, Open debugger to view warnings.' ,
449+ rect : { x : 0 , y : 0 , width : 402 , height : 874 } ,
450+ } ,
451+ {
452+ index : 2 ,
453+ depth : 1 ,
454+ parentIndex : 0 ,
455+ type : 'ScrollView' ,
456+ label : 'Recent chats' ,
457+ rect : { x : 8 , y : 212 , width : 386 , height : 600 } ,
458+ } ,
459+ {
460+ index : 3 ,
461+ depth : 2 ,
462+ parentIndex : 2 ,
463+ type : 'Other' ,
464+ label : 'Recent chats' ,
465+ rect : { x : 0 , y : 220 , width : 402 , height : 16 } ,
466+ } ,
467+ {
468+ index : 4 ,
469+ depth : 2 ,
470+ parentIndex : 2 ,
471+ type : 'Other' ,
472+ label : 'Receipt missing details, Receipt scanning failed. Enter details manually.' ,
473+ rect : { x : 8 , y : 367 , width : 386 , height : 64 } ,
474+ } ,
475+ ] ,
476+ } ;
477+ }
478+ return { } ;
479+ } ) ;
480+
481+ const handler = createRequestHandler ( {
482+ logPath : path . join ( os . tmpdir ( ) , 'daemon.log' ) ,
483+ token : 'test-token' ,
484+ sessionStore,
485+ leaseRegistry : new LeaseRegistry ( ) ,
486+ trackDownloadableArtifact : ( ) => 'artifact-id' ,
487+ } ) ;
488+
489+ const response = await handler ( {
490+ token : 'test-token' ,
491+ session : 'default' ,
492+ command : 'screenshot' ,
493+ positionals : [ screenshotPath ] ,
494+ flags : { overlayRefs : true } ,
495+ meta : { requestId : 'req-overlay-ios-rows' } ,
496+ } ) ;
497+
498+ expect ( response . ok ) . toBe ( true ) ;
499+ if ( response . ok ) {
500+ expect ( response . data ?. overlayRefs ) . toEqual ( [
501+ {
502+ ref : 'e5' ,
503+ label : 'Receipt missing details, Receipt scanning failed. Enter details manually.' ,
504+ rect : { x : 8 , y : 367 , width : 386 , height : 64 } ,
505+ overlayRect : { x : 8 , y : 367 , width : 386 , height : 64 } ,
506+ center : { x : 201 , y : 399 } ,
507+ } ,
508+ ] ) ;
509+ }
510+ expect ( mockDispatch . mock . calls . map ( ( call ) => call [ 1 ] ) ) . toEqual ( [ 'screenshot' , 'snapshot' ] ) ;
511+ expect ( mockDispatch . mock . calls [ 1 ] ?. [ 4 ] ) . toMatchObject ( {
512+ snapshotInteractiveOnly : true ,
513+ snapshotCompact : true ,
514+ } ) ;
515+ expect ( sessionStore . get ( 'default' ) ?. snapshot ?. nodes [ 4 ] ?. type ) . toBe ( 'Cell' ) ;
516+ } ) ;
517+
418518test ( 'screenshot --overlay-refs uses a fresh snapshot instead of stale session snapshot' , async ( ) => {
419519 const sessionStore = makeSessionStore ( 'agent-device-router-screenshot-' ) ;
420520 const session = makeSession ( 'default' ) ;
0 commit comments