@@ -4,6 +4,7 @@ import { makeSessionStore } from '../../../../__tests__/test-utils/store-factory
44import { handleInteractionCommands } from '../../index.ts' ;
55import {
66 buildInteractionResponseData ,
7+ buildTargetedTouchResponsePayloads ,
78 transformTouchResponseData ,
89} from '../interaction-touch-response.ts' ;
910import type { PressCommandResult } from '@agent-device/contracts/interaction' ;
@@ -100,6 +101,87 @@ function selectorResult(readiness?: { polls: number; waitedMs: number }): PressC
100101
101102const WAITED_SELECTOR_RESULT = selectorResult ( { polls : 3 , waitedMs : 400 } ) ;
102103
104+ test . each ( [ false , true ] ) (
105+ 'point-touch publication after a held frame probe, retired=%s' ,
106+ async ( retired ) => {
107+ const sessionStore = makeSessionStore ( ) ;
108+ const address = 'cwd:held-touch-response:default' ;
109+ const session = makeSession ( 'default' ) ;
110+ session . snapshot = {
111+ nodes : attachRefs ( [ { index : 0 , type : 'Button' , label : 'Continue' } ] ) ,
112+ createdAt : Date . now ( ) ,
113+ backend : 'xctest' ,
114+ } ;
115+ session . snapshotGeneration = 3 ;
116+ installTestScreenRecording ( session ) ;
117+ const ref = sessionStore . publish ( address , session ) ;
118+ let startProbe ! : ( ) => void ;
119+ let releaseProbe ! : ( ) => void ;
120+ const probing = new Promise < void > ( ( resolve ) => {
121+ startProbe = resolve ;
122+ } ) ;
123+ const released = new Promise < void > ( ( resolve ) => {
124+ releaseProbe = resolve ;
125+ } ) ;
126+ const result : PressCommandResult = {
127+ kind : 'point' ,
128+ point : { x : 10 , y : 20 } ,
129+ settle : {
130+ settled : true ,
131+ waitedMs : 25 ,
132+ captures : 2 ,
133+ quietMs : 25 ,
134+ timeoutMs : 2000 ,
135+ diff : {
136+ summary : { additions : 1 , removals : 0 , unchanged : 0 } ,
137+ lines : [ { kind : 'added' , text : 'Continue' , ref : 'e1' } ] ,
138+ } ,
139+ } ,
140+ } ;
141+ const running = buildTargetedTouchResponsePayloads ( {
142+ params : {
143+ req : {
144+ token : 't' ,
145+ command : 'press' ,
146+ positionals : [ '10' , '20' ] ,
147+ session : 'default' ,
148+ flags : { } ,
149+ } ,
150+ sessionName : address ,
151+ sessionRef : ref ,
152+ sessionStore,
153+ contextFromFlags,
154+ captureSnapshotForSession : async ( ) => {
155+ startProbe ( ) ;
156+ await released ;
157+ return sessionStore . requireCurrent ( ref ) . snapshot ! ;
158+ } ,
159+ } ,
160+ session,
161+ result,
162+ staleRefsWarning : undefined ,
163+ extra : { } ,
164+ } ) ;
165+ await probing ;
166+ let successor ;
167+ if ( retired ) {
168+ sessionStore . retire ( ref ) ;
169+ successor = sessionStore . publish ( address , makeSession ( 'default' ) ) ;
170+ }
171+ releaseProbe ( ) ;
172+ const payloads = await running ;
173+ expect ( payloads . responseData . x ) . toBe ( 10 ) ;
174+ if ( retired ) {
175+ expect ( payloads . responseData . settle ) . toBeUndefined ( ) ;
176+ expect ( payloads . result . settle ) . toBeUndefined ( ) ;
177+ expect ( sessionStore . lookup ( address ) ) . toEqual ( successor ) ;
178+ expect ( successor ?. session . snapshot ) . toBeUndefined ( ) ;
179+ } else {
180+ expect ( payloads . responseData . settle ) . toMatchObject ( { refsGeneration : 3 , settled : true } ) ;
181+ }
182+ } ,
183+ ) ;
184+
103185test ( 'the response builder reports the resolved wait and keeps the prior warning' , ( ) => {
104186 const { responseData, result } = buildInteractionResponseData ( {
105187 source : { kind : 'runtime' , result : WAITED_SELECTOR_RESULT } ,
0 commit comments