(
device: DeviceInfo,
bundleId: string,
options?: { launchConsole?: string; launchArgs?: string[]; terminateRunningApp?: boolean },
)
| 1117 | } |
| 1118 | |
| 1119 | async function launchIosSimulatorApp( |
| 1120 | device: DeviceInfo, |
| 1121 | bundleId: string, |
| 1122 | options?: { launchConsole?: string; launchArgs?: string[]; terminateRunningApp?: boolean }, |
| 1123 | ): Promise<void> { |
| 1124 | await ensureBootedSimulator(device); |
| 1125 | |
| 1126 | let consecutiveFBSFailures = 0; |
| 1127 | const MAX_CONSECUTIVE_FBS_FAILURES = 3; |
| 1128 | |
| 1129 | const launchDeadline = Deadline.fromTimeoutMs(IOS_APP_LAUNCH_TIMEOUT_MS); |
| 1130 | try { |
| 1131 | await retryWithPolicy( |
| 1132 | async ({ deadline: attemptDeadline }) => { |
| 1133 | if (attemptDeadline?.isExpired()) { |
| 1134 | throw new AppError('COMMAND_FAILED', 'App launch deadline exceeded', { |
| 1135 | timeoutMs: IOS_APP_LAUNCH_TIMEOUT_MS, |
| 1136 | }); |
| 1137 | } |
| 1138 | |
| 1139 | const launchArgs = simctlArgs( |
| 1140 | device, |
| 1141 | buildIosSimulatorLaunchArgs(device.id, bundleId, options), |
| 1142 | ); |
| 1143 | const result = options?.launchConsole |
| 1144 | ? await runIosSimulatorConsoleLaunch(launchArgs, options.launchConsole) |
| 1145 | : await runXcrun(launchArgs, { |
| 1146 | allowFailure: true, |
| 1147 | }); |
| 1148 | if (result.exitCode === 0) return; |
| 1149 | |
| 1150 | throw new AppError('COMMAND_FAILED', `xcrun exited with code ${result.exitCode}`, { |
| 1151 | cmd: 'xcrun', |
| 1152 | args: launchArgs, |
| 1153 | stdout: result.stdout, |
| 1154 | stderr: result.stderr, |
| 1155 | exitCode: result.exitCode, |
| 1156 | }); |
| 1157 | }, |
| 1158 | { |
| 1159 | maxAttempts: 10, |
| 1160 | baseDelayMs: 1_000, |
| 1161 | maxDelayMs: 5_000, |
| 1162 | jitter: 0.2, |
| 1163 | shouldRetry(error: unknown) { |
| 1164 | if (!isSimulatorLaunchFBSError(error)) return false; |
| 1165 | consecutiveFBSFailures += 1; |
| 1166 | return consecutiveFBSFailures < MAX_CONSECUTIVE_FBS_FAILURES; |
| 1167 | }, |
| 1168 | }, |
| 1169 | { deadline: launchDeadline }, |
| 1170 | ); |
| 1171 | } catch (error) { |
| 1172 | if (isSimulatorLaunchFBSError(error)) { |
| 1173 | const appError = error as AppError; |
| 1174 | const probe = await probeSimulatorLaunchContext(device, bundleId); |
| 1175 | const reason = classifyLaunchFailure(probe); |
| 1176 | appError.details = { ...appError.details, hint: launchFailureHint(reason) }; |
no test coverage detected