11import path from 'node:path' ;
22import type { ResolvedProfile } from './platform-profiles.ts' ;
33
4- // A legacy-form batch step: maps through the exact documented CLI grammar.
5- // `flags` uses internal CliFlags field names (e.g. snapshotInteractiveOnly).
4+ // A structured batch step: maps through the same command input as MCP and the Node client.
65export type BatchStepSpec = {
76 command : string ;
8- positionals ?: string [ ] ;
9- flags ?: Record < string , unknown > ;
7+ input : Record < string , unknown > ;
108} ;
119
1210type ScenarioStepBase = {
@@ -19,7 +17,7 @@ type ScenarioStepBase = {
1917} ;
2018
2119// Discriminated on execMode so the invoker gets the right payload without `!`/`?? []`:
22- // standalone carries full CLI args; batch carries one legacy batch step.
20+ // standalone carries full CLI args; batch carries one structured batch step.
2321export type ScenarioStep =
2422 | ( ScenarioStepBase & { execMode : 'standalone' ; args : string [ ] } )
2523 | ( ScenarioStepBase & { execMode : 'batch' ; step : BatchStepSpec ; isSnapshot ?: boolean } ) ;
@@ -56,32 +54,50 @@ export function buildSettingsTour(p: ResolvedProfile, ctx: StepContext): Scenari
5654 bat (
5755 'fill search' ,
5856 'fill' ,
59- { command : 'fill' , positionals : [ s . searchFieldEditable , 'general' ] } ,
57+ {
58+ command : 'fill' ,
59+ input : {
60+ target : { kind : 'selector' , selector : s . searchFieldEditable } ,
61+ text : 'general' ,
62+ } ,
63+ } ,
6064 { freshRoot : true } ,
6165 ) ,
62- bat ( 'type' , 'type' , { command : 'type' , positionals : [ 'wifi' ] } ) ,
66+ bat ( 'type' , 'type' , { command : 'type' , input : { text : 'wifi' } } ) ,
6367 bat ( 'get editable text' , 'get' , {
6468 command : 'get' ,
65- positionals : [ 'text' , s . searchFieldEditable ] ,
69+ input : {
70+ format : 'text' ,
71+ target : { kind : 'selector' , selector : s . searchFieldEditable } ,
72+ } ,
6673 } ) ,
67- bat ( 'keyboard return' , 'keyboard' , { command : 'keyboard' , positionals : [ 'return' ] } ) ,
74+ bat ( 'keyboard return' , 'keyboard' , { command : 'keyboard' , input : { action : 'return' } } ) ,
6875 ]
6976 : [
7077 // Android: tap the search entry first to reveal the editable, then type/fill it.
7178 bat (
7279 'press search field' ,
7380 'press' ,
74- { command : 'press' , positionals : [ s . searchField ] } ,
81+ {
82+ command : 'press' ,
83+ input : { target : { kind : 'selector' , selector : s . searchField } } ,
84+ } ,
7585 { freshRoot : true } ,
7686 ) ,
77- bat ( 'type' , 'type' , { command : 'type' , positionals : [ 'wifi' ] } ) ,
87+ bat ( 'type' , 'type' , { command : 'type' , input : { text : 'wifi' } } ) ,
7888 bat ( 'fill search' , 'fill' , {
7989 command : 'fill' ,
80- positionals : [ s . searchFieldEditable , 'general' ] ,
90+ input : {
91+ target : { kind : 'selector' , selector : s . searchFieldEditable } ,
92+ text : 'general' ,
93+ } ,
8194 } ) ,
8295 bat ( 'get editable text' , 'get' , {
8396 command : 'get' ,
84- positionals : [ 'text' , s . searchFieldEditable ] ,
97+ input : {
98+ format : 'text' ,
99+ target : { kind : 'selector' , selector : s . searchFieldEditable } ,
100+ } ,
85101 } ) ,
86102 ] ;
87103
@@ -93,16 +109,24 @@ export function buildSettingsTour(p: ResolvedProfile, ctx: StepContext): Scenari
93109 bat (
94110 'press series (sequence)' ,
95111 'press' ,
96- { command : 'press' , positionals : [ '200' , '95' ] , flags : { count : 2 , intervalMs : 50 } } ,
112+ {
113+ command : 'press' ,
114+ input : { target : { kind : 'point' , x : 200 , y : 95 } , count : 2 , intervalMs : 50 } ,
115+ } ,
97116 { freshRoot : true } ,
98117 ) ,
99118 bat (
100119 'swipe series (sequence)' ,
101120 'swipe' ,
102121 {
103122 command : 'swipe' ,
104- positionals : [ '200' , '650' , '200' , '450' , '120' ] ,
105- flags : { count : 2 , pauseMs : 50 , pattern : 'ping-pong' } ,
123+ input : {
124+ from : { x : 200 , y : 650 } ,
125+ to : { x : 200 , y : 450 } ,
126+ count : 2 ,
127+ pauseMs : 50 ,
128+ pattern : 'ping-pong' ,
129+ } ,
106130 } ,
107131 { freshRoot : true } ,
108132 ) ,
@@ -117,27 +141,30 @@ export function buildSettingsTour(p: ResolvedProfile, ctx: StepContext): Scenari
117141 bat (
118142 'snapshot -i (root)' ,
119143 'snapshot' ,
120- { command : 'snapshot' , flags : { snapshotInteractiveOnly : true } } ,
144+ { command : 'snapshot' , input : { interactiveOnly : true } } ,
121145 { isSnapshot : true } ,
122146 ) ,
123- bat ( 'snapshot (root)' , 'snapshot' , { command : 'snapshot' } , { isSnapshot : true } ) ,
147+ bat ( 'snapshot (root)' , 'snapshot' , { command : 'snapshot' , input : { } } , { isSnapshot : true } ) ,
124148
125149 // --- navigate into a sub-screen from a fresh root (freshRoot resets scroll so the
126150 // deep-screen row is in view), read it, then return ---
127151 bat (
128152 'press → deep screen' ,
129153 'press' ,
130- { command : 'press' , positionals : [ s . deepScreen ] } ,
154+ {
155+ command : 'press' ,
156+ input : { target : { kind : 'selector' , selector : s . deepScreen } } ,
157+ } ,
131158 { freshRoot : true } ,
132159 ) ,
133- bat ( 'snapshot (deep)' , 'snapshot' , { command : 'snapshot' } , { isSnapshot : true } ) ,
160+ bat ( 'snapshot (deep)' , 'snapshot' , { command : 'snapshot' , input : { } } , { isSnapshot : true } ) ,
134161 bat (
135162 'snapshot -i (deep)' ,
136163 'snapshot' ,
137- { command : 'snapshot' , flags : { snapshotInteractiveOnly : true } } ,
164+ { command : 'snapshot' , input : { interactiveOnly : true } } ,
138165 { isSnapshot : true } ,
139166 ) ,
140- bat ( 'back' , 'back' , { command : 'back' } ) ,
167+ bat ( 'back' , 'back' , { command : 'back' , input : { } } ) ,
141168
142169 // --- iOS runner series commands surfaced by PR #643 ---
143170 ...iosRunnerSeries ,
@@ -146,26 +173,38 @@ export function buildSettingsTour(p: ResolvedProfile, ctx: StepContext): Scenari
146173 bat (
147174 'wait text' ,
148175 'wait' ,
149- { command : 'wait' , positionals : [ ' text' , s . anchorText , ' 3000' ] } ,
176+ { command : 'wait' , input : { text : s . anchorText , timeoutMs : 3000 } } ,
150177 { freshRoot : true } ,
151178 ) ,
152- bat ( 'find' , 'find' , { command : 'find' , positionals : [ s . anchorText ] } ) ,
153- bat ( 'get text' , 'get' , { command : 'get' , positionals : [ 'text' , s . anchorLabel ] } ) ,
154- bat ( 'is visible' , 'is' , { command : 'is' , positionals : [ 'visible' , s . anchorLabel ] } ) ,
179+ bat ( 'find' , 'find' , { command : 'find' , input : { query : s . anchorText } } ) ,
180+ bat ( 'get text' , 'get' , {
181+ command : 'get' ,
182+ input : {
183+ format : 'text' ,
184+ target : { kind : 'selector' , selector : s . anchorLabel } ,
185+ } ,
186+ } ) ,
187+ bat ( 'is visible' , 'is' , {
188+ command : 'is' ,
189+ input : { predicate : 'visible' , selector : s . anchorLabel } ,
190+ } ) ,
155191
156192 // --- text entry (platform-specific order; see textEntry above) then scroll results ---
157193 ...textEntry ,
158- bat ( 'scroll down' , 'scroll' , { command : 'scroll' , positionals : [ 'down' ] } ) ,
194+ bat ( 'scroll down' , 'scroll' , { command : 'scroll' , input : { direction : 'down' } } ) ,
159195
160196 // --- artifact-producing commands; record brackets the rest so the clip has >1s of
161197 // footage (an instant start→stop makes simctl recordVideo fail to finalize) ---
162198 std ( 'record start' , 'record' , [ 'record' , 'start' , rec , '--hide-touches' ] ) ,
163- bat ( 'screenshot' , 'screenshot' , { command : 'screenshot' , positionals : [ shot ] } ) ,
164- bat ( 'logs mark' , 'logs' , { command : 'logs' , positionals : [ 'mark' , 'perf-mark' ] } ) ,
165- bat ( 'logs clear' , 'logs' , { command : 'logs' , positionals : [ 'clear' ] } ) ,
199+ bat ( 'screenshot' , 'screenshot' , { command : 'screenshot' , input : { path : shot } } ) ,
200+ bat ( 'logs mark' , 'logs' , {
201+ command : 'logs' ,
202+ input : { action : 'mark' , message : 'perf-mark' } ,
203+ } ) ,
204+ bat ( 'logs clear' , 'logs' , { command : 'logs' , input : { action : 'clear' } } ) ,
166205 std ( 'trace start' , 'trace' , [ 'trace' , 'start' , trace ] ) ,
167206 std ( 'trace stop' , 'trace' , [ 'trace' , 'stop' ] ) ,
168- bat ( 'perf' , 'perf' , { command : 'perf' } ) ,
207+ bat ( 'perf frames ' , 'perf' , { command : 'perf' , input : { area : 'frames' } } ) ,
169208 std ( 'record stop' , 'record' , [ 'record' , 'stop' ] ) ,
170209 ] ;
171210}
0 commit comments