@@ -9,15 +9,17 @@ import packageJson from '../package.json';
99import MaestroOptions , {
1010 Orientation ,
1111 ThrottleNetwork ,
12+ ReportFormat ,
1213} from './models/maestro_options' ;
1314import Maestro from './providers/maestro' ;
1415
1516const program = new Command ( ) ;
1617
1718program
18- . version ( packageJson . version )
19+ . name ( 'testingbot' )
20+ . version ( packageJson . version , '-v, --version' , 'Show version number' )
1921 . description (
20- 'TestingBotCTL is a CLI- tool to run Espresso, XCUITest and Maestro tests in the TestingBot cloud' ,
22+ 'CLI tool to run Espresso, XCUITest and Maestro tests on TestingBot cloud' ,
2123 ) ;
2224
2325program
@@ -59,7 +61,7 @@ program
5961 } )
6062 . showHelpAfterError ( true ) ;
6163
62- program
64+ const maestroCommand = program
6365 . command ( 'maestro' )
6466 . description ( 'Run Maestro flows on TestingBot.' )
6567 . argument (
@@ -72,30 +74,30 @@ program
7274 )
7375 // App and flows options
7476 . option (
75- '--app <string >' ,
77+ '--app <path >' ,
7678 'Path to application under test (.apk, .ipa, .app, or .zip).' ,
7779 )
7880 . option (
79- '--flows <string >' ,
81+ '--flows <path >' ,
8082 'Path to flow file (.yaml/.yml), directory of flows, .zip file or glob pattern.' ,
8183 )
8284 // Device configuration
8385 . option (
8486 '--device <device>' ,
85- 'Device name to use for testing (e.g., "Pixel 8 ", "iPhone 15"). If not specified, uses "*" for any available device .' ,
87+ 'Device name to use for testing (e.g., "Pixel 9 ", "iPhone 17") .' ,
8688 )
8789 . option (
8890 '--platform <platform>' ,
8991 'Platform name: Android or iOS.' ,
9092 ( val ) => val as 'Android' | 'iOS' ,
9193 )
92- . option ( '--version <version>' , 'OS version (e.g., "14", "17.2").' )
94+ . option ( '--deviceVersion <version>' , 'OS version (e.g., "14", "17.2").' )
9395 . option (
9496 '--orientation <orientation>' ,
9597 'Screen orientation: PORTRAIT or LANDSCAPE.' ,
9698 ( val ) => val . toUpperCase ( ) as Orientation ,
9799 )
98- . option ( '--locale <locale>' , 'Device locale (e.g., "en_US", "de_DE").' )
100+ . option ( '--device- locale <locale>' , 'Device locale (e.g., "en_US", "de_DE").' )
99101 . option (
100102 '--timezone <timezone>' ,
101103 'Device timezone (e.g., "America/New_York", "Europe/London").' ,
@@ -134,6 +136,30 @@ program
134136 } ,
135137 [ ] as string [ ] ,
136138 )
139+ // Maestro configuration
140+ . option (
141+ '--maestro-version <version>' ,
142+ 'Maestro version to use (e.g., "2.0.10").' ,
143+ )
144+ // Execution mode
145+ . option (
146+ '-q, --quiet' ,
147+ 'Quieter console output without progress updates.' ,
148+ )
149+ . option (
150+ '--async' ,
151+ 'Start tests and exit immediately without waiting for results.' ,
152+ )
153+ // Report options
154+ . option (
155+ '--report <format>' ,
156+ 'Download test report after completion: html or junit.' ,
157+ ( val ) => val . toLowerCase ( ) as ReportFormat ,
158+ )
159+ . option (
160+ '--report-output-dir <path>' ,
161+ 'Directory to save test reports (required when --report is used).' ,
162+ )
137163 // Authentication
138164 . option ( '--api-key <key>' , 'TestingBot API key.' )
139165 . option ( '--api-secret <secret>' , 'TestingBot API secret.' )
@@ -143,15 +169,9 @@ program
143169 const app = appFileArg || args . app ;
144170 const flows = flowsArg || args . flows ;
145171
146- if ( ! app ) {
147- throw new Error (
148- 'App file is required. Provide it as first argument or use --app option.' ,
149- ) ;
150- }
151- if ( ! flows ) {
152- throw new Error (
153- 'Flows path is required. Provide it as second argument or use --flows option.' ,
154- ) ;
172+ if ( ! app || ! flows ) {
173+ maestroCommand . help ( ) ;
174+ return ;
155175 }
156176
157177 // Parse environment variables from -e KEY=VALUE format
@@ -169,15 +189,20 @@ program
169189 includeTags : args . includeTags ,
170190 excludeTags : args . excludeTags ,
171191 platformName : args . platform ,
172- version : args . version ,
192+ version : args . deviceVersion ,
173193 name : args . name ,
174194 build : args . build ,
175195 orientation : args . orientation ,
176- locale : args . locale ,
196+ locale : args . deviceLocale ,
177197 timeZone : args . timezone ,
178198 throttleNetwork : args . throttleNetwork ,
179199 geoCountryCode : args . geoCountryCode ,
180200 env : Object . keys ( env ) . length > 0 ? env : undefined ,
201+ maestroVersion : args . maestroVersion ,
202+ quiet : args . quiet ,
203+ async : args . async ,
204+ report : args . report ,
205+ reportOutputDir : args . reportOutputDir ,
181206 } ) ;
182207 const credentials = await Auth . getCredentials ( {
183208 apiKey : args . apiKey ,
@@ -189,11 +214,15 @@ program
189214 ) ;
190215 }
191216 const maestro = new Maestro ( credentials , options ) ;
192- await maestro . run ( ) ;
217+ const result = await maestro . run ( ) ;
218+ if ( ! result . success ) {
219+ process . exitCode = 1 ;
220+ }
193221 } catch ( err ) {
194222 logger . error (
195223 `Maestro error: ${ err instanceof Error ? err . message : err } ` ,
196224 ) ;
225+ process . exitCode = 1 ;
197226 }
198227 } )
199228 . showHelpAfterError ( true ) ;
0 commit comments