@@ -38,30 +38,43 @@ const WORKING_DIRECTORY = args[5];
3838
3939const MAX_ATTEMPTS = 5 ;
4040
41- function launchSimulator ( simulatorName ) {
42- console . log ( `Launching simulator ${ simulatorName } ` ) ;
41+ function resolveSimulatorUDID ( simulatorName ) {
42+ console . log ( `Resolving UDID for simulator "${ simulatorName } "` ) ;
43+ // Resolve by name (not from the booted list) so we target a specific device
44+ // even before it has finished booting.
45+ const command = `xcrun simctl list devices available -j | jq -r '[.devices[][] | select(.name == "${ simulatorName } ")] | first | .udid'` ;
46+ const udid = String ( childProcess . execSync ( command ) ) . trim ( ) ;
47+ if ( udid === '' || udid === 'null' ) {
48+ throw new Error (
49+ `Could not resolve a UDID for a simulator named "${ simulatorName } ". ` +
50+ 'Is the device available on this runner?' ,
51+ ) ;
52+ }
53+ console . log ( `UDID is ${ udid } ` ) ;
54+ return udid ;
55+ }
56+
57+ function launchSimulator ( udid ) {
58+ console . log ( `Booting simulator ${ udid } ` ) ;
4359 try {
44- childProcess . execSync ( `xcrun simctl boot "${ simulatorName } "` ) ;
60+ childProcess . execSync ( `xcrun simctl boot "${ udid } "` ) ;
4561 } catch ( error ) {
4662 if (
4763 ! error . message . includes ( 'Unable to boot device in current state: Booted' )
4864 ) {
4965 throw error ;
5066 }
5167 }
68+ // `simctl boot` returns as soon as boot is *initiated*. Block until the device
69+ // is fully booted so install/launch/Maestro don't race a half-booted
70+ // simulator, which is the usual cause of Maestro hanging on driver startup.
71+ console . log ( 'Waiting for the simulator to finish booting' ) ;
72+ childProcess . execSync ( `xcrun simctl bootstatus "${ udid } " -b` ) ;
5273}
5374
54- function installAppOnSimulator ( appPath ) {
75+ function installAppOnSimulator ( udid , appPath ) {
5576 console . log ( `Installing app at path ${ appPath } ` ) ;
56- childProcess . execSync ( `xcrun simctl install booted "${ appPath } "` ) ;
57- }
58-
59- function extractSimulatorUDID ( ) {
60- console . log ( 'Retrieving device UDID' ) ;
61- const command = `xcrun simctl list devices booted -j | jq -r '[.devices[]] | add | first | .udid'` ;
62- const udid = String ( childProcess . execSync ( command ) ) . trim ( ) ;
63- console . log ( `UDID is ${ udid } ` ) ;
64- return udid ;
77+ childProcess . execSync ( `xcrun simctl install "${ udid } " "${ appPath } "` ) ;
6578}
6679
6780function bringSimulatorInForeground ( ) {
@@ -123,9 +136,11 @@ function executeTestsWithRetries(
123136 const recProcess = startVideoRecording ( jsengine , currentAttempt ) ;
124137 try {
125138 const timeout = 1000 * 60 * 10 ; // 10 minutes
126- const command = `$HOME/.maestro/bin/maestro --udid="${ udid } " test "${ maestroFlow } " --format junit -e APP_ID="${ appId } "` ;
139+ const command = `$HOME/.maestro/bin/maestro --udid="${ udid } " test "${ maestroFlow } " --format junit --debug-output /tmp/MaestroLogs - e APP_ID="${ appId } "` ;
127140 console . log ( command ) ;
128- childProcess . execSync ( `MAESTRO_DRIVER_STARTUP_TIMEOUT=1500000 ${ command } ` , {
141+ // Keep the driver-startup budget well under the execSync `timeout` so a
142+ // stuck driver surfaces a real Maestro error instead of a silent SIGTERM.
143+ childProcess . execSync ( `MAESTRO_DRIVER_STARTUP_TIMEOUT=180000 ${ command } ` , {
129144 stdio : 'inherit' ,
130145 timeout,
131146 } ) ;
@@ -163,9 +178,9 @@ async function main() {
163178 console . info ( '==============================\n' ) ;
164179
165180 const simulatorName = 'iPhone 16 Pro' ;
166- launchSimulator ( simulatorName ) ;
167- installAppOnSimulator ( APP_PATH ) ;
168- const udid = extractSimulatorUDID ( ) ;
181+ const udid = resolveSimulatorUDID ( simulatorName ) ;
182+ launchSimulator ( udid ) ;
183+ installAppOnSimulator ( udid , APP_PATH ) ;
169184 bringSimulatorInForeground ( ) ;
170185 await launchAppOnSimulator ( APP_ID , udid , IS_DEBUG ) ;
171186 executeTestsWithRetries ( APP_ID , udid , MAESTRO_FLOW , JS_ENGINE , 1 ) ;
0 commit comments