@@ -345,6 +345,39 @@ describe('batch MCP result shaping', () => {
345345 expect ( ( final . alerts as unknown [ ] ) . length ) . toBe ( 1 )
346346 } )
347347
348+ it ( 'caps run_actions step timeouts under the soft deadline and resumes from an action index' , async ( ) => {
349+ const handler = getToolHandler ( 'geometra_run_actions' )
350+
351+ const result = await handler ( {
352+ actions : [
353+ { type : 'click' , x : 10 , y : 20 , timeoutMs : 60_000 } ,
354+ { type : 'click' , x : 30 , y : 40 , timeoutMs : 60_000 } ,
355+ ] ,
356+ resumeFromIndex : 1 ,
357+ softTimeoutMs : 1_000 ,
358+ includeSteps : true ,
359+ detail : 'terse' ,
360+ } )
361+
362+ expect ( mockState . sendClick ) . toHaveBeenCalledTimes ( 1 )
363+ const call = mockState . sendClick . mock . calls [ 0 ] !
364+ expect ( call [ 1 ] ) . toBe ( 30 )
365+ expect ( call [ 2 ] ) . toBe ( 40 )
366+ expect ( call [ 3 ] ) . toBeGreaterThanOrEqual ( 50 )
367+ expect ( call [ 3 ] ) . toBeLessThanOrEqual ( 300 )
368+
369+ const payload = JSON . parse ( result . content [ 0 ] ! . text ) as Record < string , unknown >
370+ const steps = payload . steps as Array < Record < string , unknown > >
371+ expect ( payload ) . toMatchObject ( {
372+ completed : true ,
373+ resumedFromIndex : 1 ,
374+ stepCount : 2 ,
375+ successCount : 1 ,
376+ errorCount : 0 ,
377+ } )
378+ expect ( steps [ 0 ] ) . toMatchObject ( { index : 1 , type : 'click' , ok : true } )
379+ } )
380+
348381 it ( 'uses the proxy batch path for fill_fields when step output is omitted' , async ( ) => {
349382 const handler = getToolHandler ( 'geometra_fill_fields' )
350383
@@ -433,6 +466,38 @@ describe('batch MCP result shaping', () => {
433466 expect ( payload ) . not . toHaveProperty ( 'stepCount' )
434467 } )
435468
469+ it ( 'caps submit_form submit clicks under the soft deadline' , async ( ) => {
470+ const handler = getToolHandler ( 'geometra_submit_form' )
471+
472+ mockState . currentA11yRoot = node ( 'group' , undefined , {
473+ bounds : { x : 0 , y : 0 , width : 1280 , height : 720 } ,
474+ meta : { pageUrl : 'https://jobs.example.com/application' , scrollX : 0 , scrollY : 0 } ,
475+ children : [
476+ node ( 'button' , 'Submit' , { path : [ 0 ] , bounds : { x : 100 , y : 180 , width : 120 , height : 40 } } ) ,
477+ ] ,
478+ } )
479+
480+ const result = await handler ( {
481+ skipFill : true ,
482+ submitTimeoutMs : 60_000 ,
483+ softTimeoutMs : 1_000 ,
484+ detail : 'terse' ,
485+ } )
486+
487+ expect ( mockState . sendClick ) . toHaveBeenCalledTimes ( 1 )
488+ const call = mockState . sendClick . mock . calls [ 0 ] !
489+ expect ( call [ 1 ] ) . toBe ( 160 )
490+ expect ( call [ 2 ] ) . toBe ( 200 )
491+ expect ( call [ 3 ] ) . toBeGreaterThanOrEqual ( 50 )
492+ expect ( call [ 3 ] ) . toBeLessThanOrEqual ( 300 )
493+
494+ const payload = JSON . parse ( result . content [ 0 ] ! . text ) as Record < string , unknown >
495+ expect ( payload ) . toMatchObject ( {
496+ completed : true ,
497+ submit : { wait : 'updated' } ,
498+ } )
499+ } )
500+
436501 it ( 'attaches verifyFills readback results to run_actions fill_fields step' , async ( ) => {
437502 const handler = getToolHandler ( 'geometra_run_actions' )
438503
@@ -1922,7 +1987,7 @@ describe('query and reveal tools', () => {
19221987 const steps = payload . steps as Array < Record < string , unknown > >
19231988
19241989 expect ( mockState . sendWheel ) . toHaveBeenCalledTimes ( 1 )
1925- expect ( mockState . sendClick ) . toHaveBeenCalledWith ( mockState . session , 150 , 340 , undefined )
1990+ expect ( mockState . sendClick ) . toHaveBeenCalledWith ( mockState . session , 150 , 340 , expect . any ( Number ) )
19261991 expect ( steps [ 0 ] ) . toMatchObject ( {
19271992 index : 0 ,
19281993 type : 'click' ,
0 commit comments