@limrun/appium-xcuitest-driver 10.4.3-lim.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (444) hide show
  1. package/CHANGELOG.md +2600 -0
  2. package/LICENSE +201 -0
  3. package/README.md +55 -0
  4. package/build/index.d.ts +5 -0
  5. package/build/index.js +41 -0
  6. package/build/lib/app-infos-cache.d.ts +62 -0
  7. package/build/lib/app-infos-cache.d.ts.map +1 -0
  8. package/build/lib/app-infos-cache.js +180 -0
  9. package/build/lib/app-infos-cache.js.map +1 -0
  10. package/build/lib/app-utils.d.ts +89 -0
  11. package/build/lib/app-utils.d.ts.map +1 -0
  12. package/build/lib/app-utils.js +657 -0
  13. package/build/lib/app-utils.js.map +1 -0
  14. package/build/lib/commands/active-app-info.d.ts +9 -0
  15. package/build/lib/commands/active-app-info.d.ts.map +1 -0
  16. package/build/lib/commands/active-app-info.js +14 -0
  17. package/build/lib/commands/active-app-info.js.map +1 -0
  18. package/build/lib/commands/advanced-battery-types.d.ts +444 -0
  19. package/build/lib/commands/advanced-battery-types.d.ts.map +1 -0
  20. package/build/lib/commands/advanced-battery-types.js +8 -0
  21. package/build/lib/commands/advanced-battery-types.js.map +1 -0
  22. package/build/lib/commands/alert.d.ts +45 -0
  23. package/build/lib/commands/alert.d.ts.map +1 -0
  24. package/build/lib/commands/alert.js +87 -0
  25. package/build/lib/commands/alert.js.map +1 -0
  26. package/build/lib/commands/app-management.d.ts +153 -0
  27. package/build/lib/commands/app-management.d.ts.map +1 -0
  28. package/build/lib/commands/app-management.js +323 -0
  29. package/build/lib/commands/app-management.js.map +1 -0
  30. package/build/lib/commands/app-strings.d.ts +16 -0
  31. package/build/lib/commands/app-strings.d.ts.map +1 -0
  32. package/build/lib/commands/app-strings.js +30 -0
  33. package/build/lib/commands/app-strings.js.map +1 -0
  34. package/build/lib/commands/appearance.d.ts +22 -0
  35. package/build/lib/commands/appearance.d.ts.map +1 -0
  36. package/build/lib/commands/appearance.js +74 -0
  37. package/build/lib/commands/appearance.js.map +1 -0
  38. package/build/lib/commands/audit.d.ts +43 -0
  39. package/build/lib/commands/audit.d.ts.map +1 -0
  40. package/build/lib/commands/audit.js +31 -0
  41. package/build/lib/commands/audit.js.map +1 -0
  42. package/build/lib/commands/battery.d.ts +13 -0
  43. package/build/lib/commands/battery.d.ts.map +1 -0
  44. package/build/lib/commands/battery.js +49 -0
  45. package/build/lib/commands/battery.js.map +1 -0
  46. package/build/lib/commands/bidi/constants.d.ts +6 -0
  47. package/build/lib/commands/bidi/constants.d.ts.map +1 -0
  48. package/build/lib/commands/bidi/constants.js +10 -0
  49. package/build/lib/commands/bidi/constants.js.map +1 -0
  50. package/build/lib/commands/bidi/models.d.ts +9 -0
  51. package/build/lib/commands/bidi/models.d.ts.map +1 -0
  52. package/build/lib/commands/bidi/models.js +54 -0
  53. package/build/lib/commands/bidi/models.js.map +1 -0
  54. package/build/lib/commands/bidi/types.d.ts +26 -0
  55. package/build/lib/commands/bidi/types.d.ts.map +1 -0
  56. package/build/lib/commands/bidi/types.js +4 -0
  57. package/build/lib/commands/bidi/types.js.map +1 -0
  58. package/build/lib/commands/biometric.d.ts +32 -0
  59. package/build/lib/commands/biometric.d.ts.map +1 -0
  60. package/build/lib/commands/biometric.js +54 -0
  61. package/build/lib/commands/biometric.js.map +1 -0
  62. package/build/lib/commands/certificate.d.ts +50 -0
  63. package/build/lib/commands/certificate.d.ts.map +1 -0
  64. package/build/lib/commands/certificate.js +454 -0
  65. package/build/lib/commands/certificate.js.map +1 -0
  66. package/build/lib/commands/clipboard.d.ts +21 -0
  67. package/build/lib/commands/clipboard.d.ts.map +1 -0
  68. package/build/lib/commands/clipboard.js +36 -0
  69. package/build/lib/commands/clipboard.js.map +1 -0
  70. package/build/lib/commands/condition.d.ts +102 -0
  71. package/build/lib/commands/condition.d.ts.map +1 -0
  72. package/build/lib/commands/condition.js +146 -0
  73. package/build/lib/commands/condition.js.map +1 -0
  74. package/build/lib/commands/content-size.d.ts +30 -0
  75. package/build/lib/commands/content-size.d.ts.map +1 -0
  76. package/build/lib/commands/content-size.js +67 -0
  77. package/build/lib/commands/content-size.js.map +1 -0
  78. package/build/lib/commands/context.d.ts +191 -0
  79. package/build/lib/commands/context.d.ts.map +1 -0
  80. package/build/lib/commands/context.js +625 -0
  81. package/build/lib/commands/context.js.map +1 -0
  82. package/build/lib/commands/deviceInfo.d.ts +12 -0
  83. package/build/lib/commands/deviceInfo.d.ts.map +1 -0
  84. package/build/lib/commands/deviceInfo.js +25 -0
  85. package/build/lib/commands/deviceInfo.js.map +1 -0
  86. package/build/lib/commands/element.d.ts +108 -0
  87. package/build/lib/commands/element.d.ts.map +1 -0
  88. package/build/lib/commands/element.js +395 -0
  89. package/build/lib/commands/element.js.map +1 -0
  90. package/build/lib/commands/enum.d.ts +105 -0
  91. package/build/lib/commands/enum.d.ts.map +1 -0
  92. package/build/lib/commands/enum.js +113 -0
  93. package/build/lib/commands/enum.js.map +1 -0
  94. package/build/lib/commands/execute.d.ts +33 -0
  95. package/build/lib/commands/execute.d.ts.map +1 -0
  96. package/build/lib/commands/execute.js +142 -0
  97. package/build/lib/commands/execute.js.map +1 -0
  98. package/build/lib/commands/file-movement.d.ts +90 -0
  99. package/build/lib/commands/file-movement.d.ts.map +1 -0
  100. package/build/lib/commands/file-movement.js +477 -0
  101. package/build/lib/commands/file-movement.js.map +1 -0
  102. package/build/lib/commands/find.d.ts +21 -0
  103. package/build/lib/commands/find.d.ts.map +1 -0
  104. package/build/lib/commands/find.js +199 -0
  105. package/build/lib/commands/find.js.map +1 -0
  106. package/build/lib/commands/general.d.ts +137 -0
  107. package/build/lib/commands/general.d.ts.map +1 -0
  108. package/build/lib/commands/general.js +270 -0
  109. package/build/lib/commands/general.js.map +1 -0
  110. package/build/lib/commands/geolocation.d.ts +57 -0
  111. package/build/lib/commands/geolocation.d.ts.map +1 -0
  112. package/build/lib/commands/geolocation.js +58 -0
  113. package/build/lib/commands/geolocation.js.map +1 -0
  114. package/build/lib/commands/gesture.d.ts +283 -0
  115. package/build/lib/commands/gesture.d.ts.map +1 -0
  116. package/build/lib/commands/gesture.js +565 -0
  117. package/build/lib/commands/gesture.js.map +1 -0
  118. package/build/lib/commands/hid-event.d.ts +2773 -0
  119. package/build/lib/commands/hid-event.d.ts.map +1 -0
  120. package/build/lib/commands/hid-event.js +1633 -0
  121. package/build/lib/commands/hid-event.js.map +1 -0
  122. package/build/lib/commands/increase-contrast.d.ts +24 -0
  123. package/build/lib/commands/increase-contrast.d.ts.map +1 -0
  124. package/build/lib/commands/increase-contrast.js +49 -0
  125. package/build/lib/commands/increase-contrast.js.map +1 -0
  126. package/build/lib/commands/iohid.d.ts +1372 -0
  127. package/build/lib/commands/iohid.d.ts.map +1 -0
  128. package/build/lib/commands/iohid.js +63 -0
  129. package/build/lib/commands/iohid.js.map +1 -0
  130. package/build/lib/commands/keyboard.d.ts +32 -0
  131. package/build/lib/commands/keyboard.d.ts.map +1 -0
  132. package/build/lib/commands/keyboard.js +67 -0
  133. package/build/lib/commands/keyboard.js.map +1 -0
  134. package/build/lib/commands/keychains.d.ts +10 -0
  135. package/build/lib/commands/keychains.d.ts.map +1 -0
  136. package/build/lib/commands/keychains.js +22 -0
  137. package/build/lib/commands/keychains.js.map +1 -0
  138. package/build/lib/commands/localization.d.ts +17 -0
  139. package/build/lib/commands/localization.d.ts.map +1 -0
  140. package/build/lib/commands/localization.js +34 -0
  141. package/build/lib/commands/localization.js.map +1 -0
  142. package/build/lib/commands/location.d.ts +40 -0
  143. package/build/lib/commands/location.d.ts.map +1 -0
  144. package/build/lib/commands/location.js +121 -0
  145. package/build/lib/commands/location.js.map +1 -0
  146. package/build/lib/commands/lock.d.ts +23 -0
  147. package/build/lib/commands/lock.d.ts.map +1 -0
  148. package/build/lib/commands/lock.js +49 -0
  149. package/build/lib/commands/lock.js.map +1 -0
  150. package/build/lib/commands/log.d.ts +68 -0
  151. package/build/lib/commands/log.d.ts.map +1 -0
  152. package/build/lib/commands/log.js +287 -0
  153. package/build/lib/commands/log.js.map +1 -0
  154. package/build/lib/commands/memory.d.ts +11 -0
  155. package/build/lib/commands/memory.d.ts.map +1 -0
  156. package/build/lib/commands/memory.js +49 -0
  157. package/build/lib/commands/memory.js.map +1 -0
  158. package/build/lib/commands/navigation.d.ts +44 -0
  159. package/build/lib/commands/navigation.d.ts.map +1 -0
  160. package/build/lib/commands/navigation.js +121 -0
  161. package/build/lib/commands/navigation.js.map +1 -0
  162. package/build/lib/commands/notifications.d.ts +28 -0
  163. package/build/lib/commands/notifications.d.ts.map +1 -0
  164. package/build/lib/commands/notifications.js +64 -0
  165. package/build/lib/commands/notifications.js.map +1 -0
  166. package/build/lib/commands/pasteboard.d.ts +23 -0
  167. package/build/lib/commands/pasteboard.d.ts.map +1 -0
  168. package/build/lib/commands/pasteboard.js +43 -0
  169. package/build/lib/commands/pasteboard.js.map +1 -0
  170. package/build/lib/commands/pcap.d.ts +54 -0
  171. package/build/lib/commands/pcap.d.ts.map +1 -0
  172. package/build/lib/commands/pcap.js +149 -0
  173. package/build/lib/commands/pcap.js.map +1 -0
  174. package/build/lib/commands/performance.d.ts +85 -0
  175. package/build/lib/commands/performance.d.ts.map +1 -0
  176. package/build/lib/commands/performance.js +331 -0
  177. package/build/lib/commands/performance.js.map +1 -0
  178. package/build/lib/commands/permissions.d.ts +36 -0
  179. package/build/lib/commands/permissions.d.ts.map +1 -0
  180. package/build/lib/commands/permissions.js +80 -0
  181. package/build/lib/commands/permissions.js.map +1 -0
  182. package/build/lib/commands/proxy-helper.d.ts +15 -0
  183. package/build/lib/commands/proxy-helper.d.ts.map +1 -0
  184. package/build/lib/commands/proxy-helper.js +117 -0
  185. package/build/lib/commands/proxy-helper.js.map +1 -0
  186. package/build/lib/commands/record-audio.d.ts +69 -0
  187. package/build/lib/commands/record-audio.d.ts.map +1 -0
  188. package/build/lib/commands/record-audio.js +228 -0
  189. package/build/lib/commands/record-audio.js.map +1 -0
  190. package/build/lib/commands/recordscreen.d.ts +89 -0
  191. package/build/lib/commands/recordscreen.d.ts.map +1 -0
  192. package/build/lib/commands/recordscreen.js +326 -0
  193. package/build/lib/commands/recordscreen.js.map +1 -0
  194. package/build/lib/commands/screenshots.d.ts +16 -0
  195. package/build/lib/commands/screenshots.d.ts.map +1 -0
  196. package/build/lib/commands/screenshots.js +129 -0
  197. package/build/lib/commands/screenshots.js.map +1 -0
  198. package/build/lib/commands/simctl.d.ts +27 -0
  199. package/build/lib/commands/simctl.d.ts.map +1 -0
  200. package/build/lib/commands/simctl.js +65 -0
  201. package/build/lib/commands/simctl.js.map +1 -0
  202. package/build/lib/commands/source.d.ts +16 -0
  203. package/build/lib/commands/source.d.ts.map +1 -0
  204. package/build/lib/commands/source.js +128 -0
  205. package/build/lib/commands/source.js.map +1 -0
  206. package/build/lib/commands/timeouts.d.ts +53 -0
  207. package/build/lib/commands/timeouts.d.ts.map +1 -0
  208. package/build/lib/commands/timeouts.js +71 -0
  209. package/build/lib/commands/timeouts.js.map +1 -0
  210. package/build/lib/commands/types.d.ts +539 -0
  211. package/build/lib/commands/types.d.ts.map +1 -0
  212. package/build/lib/commands/types.js +3 -0
  213. package/build/lib/commands/types.js.map +1 -0
  214. package/build/lib/commands/web.d.ts +297 -0
  215. package/build/lib/commands/web.d.ts.map +1 -0
  216. package/build/lib/commands/web.js +1029 -0
  217. package/build/lib/commands/web.js.map +1 -0
  218. package/build/lib/commands/xctest-record-screen.d.ts +92 -0
  219. package/build/lib/commands/xctest-record-screen.d.ts.map +1 -0
  220. package/build/lib/commands/xctest-record-screen.js +193 -0
  221. package/build/lib/commands/xctest-record-screen.js.map +1 -0
  222. package/build/lib/commands/xctest.d.ts +71 -0
  223. package/build/lib/commands/xctest.d.ts.map +1 -0
  224. package/build/lib/commands/xctest.js +257 -0
  225. package/build/lib/commands/xctest.js.map +1 -0
  226. package/build/lib/css-converter.d.ts +10 -0
  227. package/build/lib/css-converter.d.ts.map +1 -0
  228. package/build/lib/css-converter.js +258 -0
  229. package/build/lib/css-converter.js.map +1 -0
  230. package/build/lib/desired-caps.d.ts +506 -0
  231. package/build/lib/desired-caps.d.ts.map +1 -0
  232. package/build/lib/desired-caps.js +400 -0
  233. package/build/lib/desired-caps.js.map +1 -0
  234. package/build/lib/device-connections-factory.d.ts +13 -0
  235. package/build/lib/device-connections-factory.d.ts.map +1 -0
  236. package/build/lib/device-connections-factory.js +244 -0
  237. package/build/lib/device-connections-factory.js.map +1 -0
  238. package/build/lib/device-log/helpers.d.ts +10 -0
  239. package/build/lib/device-log/helpers.d.ts.map +1 -0
  240. package/build/lib/device-log/helpers.js +37 -0
  241. package/build/lib/device-log/helpers.js.map +1 -0
  242. package/build/lib/device-log/ios-crash-log.d.ts +34 -0
  243. package/build/lib/device-log/ios-crash-log.d.ts.map +1 -0
  244. package/build/lib/device-log/ios-crash-log.js +141 -0
  245. package/build/lib/device-log/ios-crash-log.js.map +1 -0
  246. package/build/lib/device-log/ios-device-log.d.ts +19 -0
  247. package/build/lib/device-log/ios-device-log.d.ts.map +1 -0
  248. package/build/lib/device-log/ios-device-log.js +42 -0
  249. package/build/lib/device-log/ios-device-log.js.map +1 -0
  250. package/build/lib/device-log/ios-log.d.ts +24 -0
  251. package/build/lib/device-log/ios-log.d.ts.map +1 -0
  252. package/build/lib/device-log/ios-log.js +50 -0
  253. package/build/lib/device-log/ios-log.js.map +1 -0
  254. package/build/lib/device-log/ios-performance-log.d.ts +18 -0
  255. package/build/lib/device-log/ios-performance-log.d.ts.map +1 -0
  256. package/build/lib/device-log/ios-performance-log.js +43 -0
  257. package/build/lib/device-log/ios-performance-log.js.map +1 -0
  258. package/build/lib/device-log/ios-simulator-log.d.ts +38 -0
  259. package/build/lib/device-log/ios-simulator-log.d.ts.map +1 -0
  260. package/build/lib/device-log/ios-simulator-log.js +184 -0
  261. package/build/lib/device-log/ios-simulator-log.js.map +1 -0
  262. package/build/lib/device-log/line-consuming-log.d.ts +9 -0
  263. package/build/lib/device-log/line-consuming-log.d.ts.map +1 -0
  264. package/build/lib/device-log/line-consuming-log.js +16 -0
  265. package/build/lib/device-log/line-consuming-log.js.map +1 -0
  266. package/build/lib/device-log/safari-console-log.d.ts +67 -0
  267. package/build/lib/device-log/safari-console-log.d.ts.map +1 -0
  268. package/build/lib/device-log/safari-console-log.js +81 -0
  269. package/build/lib/device-log/safari-console-log.js.map +1 -0
  270. package/build/lib/device-log/safari-network-log.d.ts +75 -0
  271. package/build/lib/device-log/safari-network-log.d.ts.map +1 -0
  272. package/build/lib/device-log/safari-network-log.js +47 -0
  273. package/build/lib/device-log/safari-network-log.js.map +1 -0
  274. package/build/lib/doctor/checks.d.ts +3 -0
  275. package/build/lib/doctor/checks.d.ts.map +1 -0
  276. package/build/lib/doctor/checks.js +39 -0
  277. package/build/lib/doctor/checks.js.map +1 -0
  278. package/build/lib/doctor/optional-checks.d.ts +46 -0
  279. package/build/lib/doctor/optional-checks.d.ts.map +1 -0
  280. package/build/lib/doctor/optional-checks.js +129 -0
  281. package/build/lib/doctor/optional-checks.js.map +1 -0
  282. package/build/lib/doctor/required-checks.d.ts +42 -0
  283. package/build/lib/doctor/required-checks.d.ts.map +1 -0
  284. package/build/lib/doctor/required-checks.js +94 -0
  285. package/build/lib/doctor/required-checks.js.map +1 -0
  286. package/build/lib/doctor/utils.d.ts +8 -0
  287. package/build/lib/doctor/utils.d.ts.map +1 -0
  288. package/build/lib/doctor/utils.js +21 -0
  289. package/build/lib/doctor/utils.js.map +1 -0
  290. package/build/lib/driver.d.ts +2429 -0
  291. package/build/lib/driver.d.ts.map +1 -0
  292. package/build/lib/driver.js +1967 -0
  293. package/build/lib/driver.js.map +1 -0
  294. package/build/lib/execute-method-map.d.ts +552 -0
  295. package/build/lib/execute-method-map.d.ts.map +1 -0
  296. package/build/lib/execute-method-map.js +586 -0
  297. package/build/lib/execute-method-map.js.map +1 -0
  298. package/build/lib/ios-fs-helpers.d.ts +75 -0
  299. package/build/lib/ios-fs-helpers.d.ts.map +1 -0
  300. package/build/lib/ios-fs-helpers.js +370 -0
  301. package/build/lib/ios-fs-helpers.js.map +1 -0
  302. package/build/lib/ios-generic-simulators.d.ts +6 -0
  303. package/build/lib/ios-generic-simulators.d.ts.map +1 -0
  304. package/build/lib/ios-generic-simulators.js +14 -0
  305. package/build/lib/ios-generic-simulators.js.map +1 -0
  306. package/build/lib/logger.d.ts +3 -0
  307. package/build/lib/logger.d.ts.map +1 -0
  308. package/build/lib/logger.js +6 -0
  309. package/build/lib/logger.js.map +1 -0
  310. package/build/lib/method-map.d.ts +229 -0
  311. package/build/lib/method-map.d.ts.map +1 -0
  312. package/build/lib/method-map.js +200 -0
  313. package/build/lib/method-map.js.map +1 -0
  314. package/build/lib/real-device-clients/base-device-client.d.ts +22 -0
  315. package/build/lib/real-device-clients/base-device-client.d.ts.map +1 -0
  316. package/build/lib/real-device-clients/base-device-client.js +14 -0
  317. package/build/lib/real-device-clients/base-device-client.js.map +1 -0
  318. package/build/lib/real-device-clients/py-ios-device-client.d.ts +21 -0
  319. package/build/lib/real-device-clients/py-ios-device-client.d.ts.map +1 -0
  320. package/build/lib/real-device-clients/py-ios-device-client.js +125 -0
  321. package/build/lib/real-device-clients/py-ios-device-client.js.map +1 -0
  322. package/build/lib/real-device-management.d.ts +53 -0
  323. package/build/lib/real-device-management.d.ts.map +1 -0
  324. package/build/lib/real-device-management.js +128 -0
  325. package/build/lib/real-device-management.js.map +1 -0
  326. package/build/lib/real-device.d.ts +112 -0
  327. package/build/lib/real-device.d.ts.map +1 -0
  328. package/build/lib/real-device.js +352 -0
  329. package/build/lib/real-device.js.map +1 -0
  330. package/build/lib/simulator-management.d.ts +96 -0
  331. package/build/lib/simulator-management.d.ts.map +1 -0
  332. package/build/lib/simulator-management.js +278 -0
  333. package/build/lib/simulator-management.js.map +1 -0
  334. package/build/lib/stubs.d.ts +3 -0
  335. package/build/lib/stubs.d.ts.map +1 -0
  336. package/build/lib/stubs.js +3 -0
  337. package/build/lib/stubs.js.map +1 -0
  338. package/build/lib/types.d.ts +31 -0
  339. package/build/lib/types.d.ts.map +1 -0
  340. package/build/lib/types.js +3 -0
  341. package/build/lib/types.js.map +1 -0
  342. package/build/lib/utils.d.ts +191 -0
  343. package/build/lib/utils.d.ts.map +1 -0
  344. package/build/lib/utils.js +549 -0
  345. package/build/lib/utils.js.map +1 -0
  346. package/build/lib/xcrun.d.ts +3 -0
  347. package/build/lib/xcrun.d.ts.map +1 -0
  348. package/build/lib/xcrun.js +17 -0
  349. package/build/lib/xcrun.js.map +1 -0
  350. package/index.js +7 -0
  351. package/lib/app-infos-cache.js +187 -0
  352. package/lib/app-utils.js +710 -0
  353. package/lib/commands/active-app-info.js +12 -0
  354. package/lib/commands/advanced-battery-types.ts +454 -0
  355. package/lib/commands/alert.js +88 -0
  356. package/lib/commands/app-management.js +346 -0
  357. package/lib/commands/app-strings.js +30 -0
  358. package/lib/commands/appearance.js +71 -0
  359. package/lib/commands/audit.js +31 -0
  360. package/lib/commands/battery.js +45 -0
  361. package/lib/commands/bidi/constants.ts +6 -0
  362. package/lib/commands/bidi/models.ts +55 -0
  363. package/lib/commands/bidi/types.ts +31 -0
  364. package/lib/commands/biometric.js +53 -0
  365. package/lib/commands/certificate.js +497 -0
  366. package/lib/commands/clipboard.js +35 -0
  367. package/lib/commands/condition.js +155 -0
  368. package/lib/commands/content-size.js +68 -0
  369. package/lib/commands/context.js +705 -0
  370. package/lib/commands/deviceInfo.js +27 -0
  371. package/lib/commands/element.js +423 -0
  372. package/lib/commands/enum.ts +108 -0
  373. package/lib/commands/execute.js +153 -0
  374. package/lib/commands/file-movement.js +510 -0
  375. package/lib/commands/find.js +205 -0
  376. package/lib/commands/general.js +278 -0
  377. package/lib/commands/geolocation.js +56 -0
  378. package/lib/commands/gesture.js +596 -0
  379. package/lib/commands/hid-event.ts +1634 -0
  380. package/lib/commands/increase-contrast.js +50 -0
  381. package/lib/commands/iohid.js +64 -0
  382. package/lib/commands/keyboard.js +62 -0
  383. package/lib/commands/keychains.js +18 -0
  384. package/lib/commands/localization.js +30 -0
  385. package/lib/commands/location.js +131 -0
  386. package/lib/commands/lock.js +46 -0
  387. package/lib/commands/log.js +327 -0
  388. package/lib/commands/memory.js +51 -0
  389. package/lib/commands/navigation.js +125 -0
  390. package/lib/commands/notifications.js +66 -0
  391. package/lib/commands/pasteboard.js +42 -0
  392. package/lib/commands/pcap.js +168 -0
  393. package/lib/commands/performance.js +392 -0
  394. package/lib/commands/permissions.js +85 -0
  395. package/lib/commands/proxy-helper.js +122 -0
  396. package/lib/commands/record-audio.js +264 -0
  397. package/lib/commands/recordscreen.js +391 -0
  398. package/lib/commands/screenshots.js +137 -0
  399. package/lib/commands/simctl.js +71 -0
  400. package/lib/commands/source.js +131 -0
  401. package/lib/commands/timeouts.js +68 -0
  402. package/lib/commands/types.ts +648 -0
  403. package/lib/commands/web.js +1113 -0
  404. package/lib/commands/xctest-record-screen.js +204 -0
  405. package/lib/commands/xctest.js +285 -0
  406. package/lib/css-converter.js +311 -0
  407. package/lib/desired-caps.js +396 -0
  408. package/lib/device-connections-factory.js +269 -0
  409. package/lib/device-log/helpers.ts +40 -0
  410. package/lib/device-log/ios-crash-log.ts +166 -0
  411. package/lib/device-log/ios-device-log.ts +51 -0
  412. package/lib/device-log/ios-log.ts +70 -0
  413. package/lib/device-log/ios-performance-log.ts +50 -0
  414. package/lib/device-log/ios-simulator-log.ts +202 -0
  415. package/lib/device-log/line-consuming-log.ts +16 -0
  416. package/lib/device-log/safari-console-log.ts +117 -0
  417. package/lib/device-log/safari-network-log.ts +120 -0
  418. package/lib/doctor/checks.ts +3 -0
  419. package/lib/doctor/optional-checks.ts +173 -0
  420. package/lib/doctor/required-checks.ts +120 -0
  421. package/lib/doctor/utils.ts +18 -0
  422. package/lib/driver.js +2316 -0
  423. package/lib/execute-method-map.ts +585 -0
  424. package/lib/ios-fs-helpers.js +355 -0
  425. package/lib/ios-generic-simulators.js +11 -0
  426. package/lib/logger.js +5 -0
  427. package/lib/method-map.js +196 -0
  428. package/lib/real-device-clients/base-device-client.ts +34 -0
  429. package/lib/real-device-clients/py-ios-device-client.ts +149 -0
  430. package/lib/real-device-management.js +133 -0
  431. package/lib/real-device.js +347 -0
  432. package/lib/simulator-management.js +324 -0
  433. package/lib/stubs.ts +3 -0
  434. package/lib/types.ts +33 -0
  435. package/lib/utils.js +551 -0
  436. package/lib/xcrun.js +16 -0
  437. package/package.json +175 -0
  438. package/scripts/build-docs.js +56 -0
  439. package/scripts/build-wda.js +42 -0
  440. package/scripts/download-wda-sim.mjs +68 -0
  441. package/scripts/image-mounter.mjs +239 -0
  442. package/scripts/open-wda.mjs +15 -0
  443. package/scripts/tunnel-creation.mjs +359 -0
  444. package/scripts/utils.js +16 -0
package/lib/driver.js ADDED
@@ -0,0 +1,2316 @@
1
+ import IDB from 'appium-idb';
2
+ import {getSimulator} from '@limrun/appium-ios-simulator';
3
+ import {WebDriverAgent} from 'appium-webdriveragent';
4
+ import {BaseDriver, DeviceSettings, errors} from 'appium/driver';
5
+ import {fs, mjpeg, util, timing} from 'appium/support';
6
+ import AsyncLock from 'async-lock';
7
+ import {retryInterval} from 'asyncbox';
8
+ import B from 'bluebird';
9
+ import _ from 'lodash';
10
+ import {LRUCache} from 'lru-cache';
11
+ import EventEmitter from 'node:events';
12
+ import path from 'node:path';
13
+ import url from 'node:url';
14
+ import {
15
+ SUPPORTED_EXTENSIONS,
16
+ SAFARI_BUNDLE_ID,
17
+ onPostConfigureApp,
18
+ onDownloadApp,
19
+ verifyApplicationPlatform,
20
+ } from './app-utils';
21
+ import * as activeAppInfoCommands from './commands/active-app-info';
22
+ import * as alertCommands from './commands/alert';
23
+ import * as appManagementCommands from './commands/app-management';
24
+ import * as appearanceCommands from './commands/appearance';
25
+ import * as appStringsCommands from './commands/app-strings';
26
+ import * as auditCommands from './commands/audit';
27
+ import * as batteryCommands from './commands/battery';
28
+ import * as biometricCommands from './commands/biometric';
29
+ import * as certificateCommands from './commands/certificate';
30
+ import * as clipboardCommands from './commands/clipboard';
31
+ import * as conditionCommands from './commands/condition';
32
+ import * as contentSizeCommands from './commands/content-size';
33
+ import * as contextCommands from './commands/context';
34
+ import * as deviceInfoCommands from './commands/deviceInfo';
35
+ import * as elementCommands from './commands/element';
36
+ import * as executeCommands from './commands/execute';
37
+ import * as fileMovementCommands from './commands/file-movement';
38
+ import * as findCommands from './commands/find';
39
+ import * as generalCommands from './commands/general';
40
+ import * as geolocationCommands from './commands/geolocation';
41
+ import * as gestureCommands from './commands/gesture';
42
+ import * as iohidCommands from './commands/iohid';
43
+ import * as keychainsCommands from './commands/keychains';
44
+ import * as keyboardCommands from './commands/keyboard';
45
+ import * as localizationCommands from './commands/localization';
46
+ import * as locationCommands from './commands/location';
47
+ import * as lockCommands from './commands/lock';
48
+ import * as logCommands from './commands/log';
49
+ import * as memoryCommands from './commands/memory';
50
+ import * as navigationCommands from './commands/navigation';
51
+ import * as notificationsCommands from './commands/notifications';
52
+ import * as pasteboardCommands from './commands/pasteboard';
53
+ import * as pcapCommands from './commands/pcap';
54
+ import * as performanceCommands from './commands/performance';
55
+ import * as permissionsCommands from './commands/permissions';
56
+ import * as proxyHelperCommands from './commands/proxy-helper';
57
+ import * as recordAudioCommands from './commands/record-audio';
58
+ import * as recordScreenCommands from './commands/recordscreen';
59
+ import * as screenshotCommands from './commands/screenshots';
60
+ import * as sourceCommands from './commands/source';
61
+ import * as simctlCommands from './commands/simctl';
62
+ import * as timeoutCommands from './commands/timeouts';
63
+ import * as webCommands from './commands/web';
64
+ import * as xctestCommands from './commands/xctest';
65
+ import * as xctestRecordScreenCommands from './commands/xctest-record-screen';
66
+ import * as increaseContrastCommands from './commands/increase-contrast';
67
+ import {desiredCapConstraints} from './desired-caps';
68
+ import {DEVICE_CONNECTIONS_FACTORY} from './device-connections-factory';
69
+ import {executeMethodMap} from './execute-method-map';
70
+ import {newMethodMap} from './method-map';
71
+ import { Pyidevice } from './real-device-clients/py-ios-device-client';
72
+ import {
73
+ installToRealDevice,
74
+ runRealDeviceReset,
75
+ applySafariStartupArgs,
76
+ detectUdid,
77
+ } from './real-device-management';
78
+ import {
79
+ RealDevice,
80
+ getConnectedDevices,
81
+ } from './real-device';
82
+ import {
83
+ createSim,
84
+ getExistingSim,
85
+ installToSimulator,
86
+ runSimulatorReset,
87
+ setLocalizationPrefs,
88
+ setSafariPrefs,
89
+ shutdownOtherSimulators,
90
+ shutdownSimulator,
91
+ } from './simulator-management';
92
+ import {
93
+ DEFAULT_TIMEOUT_KEY,
94
+ UDID_AUTO,
95
+ checkAppPresent,
96
+ clearSystemFiles,
97
+ getAndCheckIosSdkVersion,
98
+ getAndCheckXcodeVersion,
99
+ getDriverInfo,
100
+ isLocalHost,
101
+ markSystemFilesForCleanup,
102
+ normalizeCommandTimeouts,
103
+ normalizePlatformVersion,
104
+ printUser,
105
+ removeAllSessionWebSocketHandlers,
106
+ shouldSetInitialSafariUrl,
107
+ translateDeviceName,
108
+ } from './utils';
109
+ import { AppInfosCache } from './app-infos-cache';
110
+ import { notifyBiDiContextChange } from './commands/context';
111
+
112
+ const SHUTDOWN_OTHER_FEAT_NAME = 'shutdown_other_sims';
113
+ const CUSTOMIZE_RESULT_BUNDLE_PATH = 'customize_result_bundle_path';
114
+
115
+ const defaultServerCaps = {
116
+ webStorageEnabled: false,
117
+ locationContextEnabled: false,
118
+ browserName: '',
119
+ platform: 'MAC',
120
+ javascriptEnabled: true,
121
+ databaseEnabled: false,
122
+ takesScreenshot: true,
123
+ networkConnectionEnabled: false,
124
+ };
125
+ const WDA_SIM_STARTUP_RETRIES = 2;
126
+ const WDA_REAL_DEV_STARTUP_RETRIES = 1;
127
+ const WDA_REAL_DEV_TUTORIAL_URL =
128
+ 'https://appium.github.io/appium-xcuitest-driver/latest/preparation/real-device-config/';
129
+ const WDA_STARTUP_RETRY_INTERVAL = 10000;
130
+ const DEFAULT_SETTINGS = {
131
+ nativeWebTap: false,
132
+ nativeWebTapStrict: false,
133
+ useJSONSource: false,
134
+ webScreenshotMode: 'native',
135
+ shouldUseCompactResponses: true,
136
+ elementResponseAttributes: 'type,label',
137
+ // Read https://github.com/appium/WebDriverAgent/blob/master/WebDriverAgentLib/Utilities/FBConfiguration.m for following settings' values
138
+ mjpegServerScreenshotQuality: 25,
139
+ mjpegServerFramerate: 10,
140
+ screenshotQuality: 1,
141
+ mjpegScalingFactor: 100,
142
+ // set `reduceMotion` to `null` so that it will be verified but still set either true/false
143
+ reduceMotion: null,
144
+ pageSourceExcludedAttributes: ''
145
+ };
146
+ // This lock assures, that each driver session does not
147
+ // affect shared resources of the other parallel sessions
148
+ const SHARED_RESOURCES_GUARD = new AsyncLock();
149
+ const WEB_ELEMENTS_CACHE_SIZE = 500;
150
+ const SUPPORTED_ORIENATIONS = ['LANDSCAPE', 'PORTRAIT'];
151
+ const DEFAULT_MJPEG_SERVER_PORT = 9100;
152
+
153
+ /* eslint-disable no-useless-escape */
154
+ /** @type {import('@appium/types').RouteMatcher[]} */
155
+ const NO_PROXY_NATIVE_LIST = [
156
+ ['DELETE', /window/],
157
+ ['GET', /^\/session\/[^\/]+$/],
158
+ ['GET', /alert_text/],
159
+ ['GET', /alert\/[^\/]+/],
160
+ ['GET', /appium/],
161
+ ['GET', /attribute/],
162
+ ['GET', /context/],
163
+ ['GET', /location/],
164
+ ['GET', /log/],
165
+ ['GET', /screenshot/],
166
+ ['GET', /size/],
167
+ ['GET', /source/],
168
+ ['GET', /timeouts$/],
169
+ ['GET', /url/],
170
+ ['GET', /window/],
171
+ ['POST', /accept_alert/],
172
+ ['POST', /actions$/],
173
+ ['DELETE', /actions$/],
174
+ ['POST', /alert_text/],
175
+ ['POST', /alert\/[^\/]+/],
176
+ ['POST', /appium/],
177
+ ['POST', /appium\/device\/is_locked/],
178
+ ['POST', /appium\/device\/lock/],
179
+ ['POST', /appium\/device\/unlock/],
180
+ ['POST', /back/],
181
+ ['POST', /clear/],
182
+ ['POST', /context/],
183
+ ['POST', /dismiss_alert/],
184
+ ['POST', /element\/active/], // MJSONWP get active element should proxy
185
+ ['POST', /element$/],
186
+ ['POST', /elements$/],
187
+ ['POST', /execute/],
188
+ ['POST', /keys/],
189
+ ['POST', /log/],
190
+ ['POST', /receive_async_response/], // always, in case context switches while waiting
191
+ ['POST', /session\/[^\/]+\/location/], // geo location, but not element location
192
+ ['POST', /shake/],
193
+ ['POST', /timeouts/],
194
+ ['POST', /url/],
195
+ ['POST', /value/],
196
+ ['POST', /window/],
197
+ ['DELETE', /cookie/],
198
+ ['GET', /cookie/],
199
+ ['POST', /cookie/],
200
+ ];
201
+
202
+ const NO_PROXY_WEB_LIST = /** @type {import('@appium/types').RouteMatcher[]} */ ([
203
+ ['GET', /attribute/],
204
+ ['GET', /element/],
205
+ ['GET', /text/],
206
+ ['GET', /title/],
207
+ ['POST', /clear/],
208
+ ['POST', /click/],
209
+ ['POST', /element/],
210
+ ['POST', /forward/],
211
+ ['POST', /frame/],
212
+ ['POST', /keys/],
213
+ ['POST', /refresh/],
214
+ ]).concat(NO_PROXY_NATIVE_LIST);
215
+ /* eslint-enable no-useless-escape */
216
+
217
+ const MEMOIZED_FUNCTIONS = ['getStatusBarHeight', 'getDevicePixelRatio', 'getScreenInfo'];
218
+
219
+ // Capabilities that do not have xcodebuild process
220
+ const CAP_NAMES_NO_XCODEBUILD_REQUIRED = ['webDriverAgentUrl', 'usePreinstalledWDA'];
221
+
222
+ const BUNDLE_VERSION_PATTERN = /CFBundleVersion\s+=\s+"?([^(;|")]+)/;
223
+
224
+ /**
225
+ * @implements {ExternalDriver<XCUITestDriverConstraints, FullContext|string>}
226
+ * @extends {BaseDriver<XCUITestDriverConstraints>}
227
+ * @privateRemarks **This class should be considered "final"**. It cannot be extended
228
+ * due to use of public class field assignments. If extending this class becomes a hard requirement, refer to the implementation of `BaseDriver` on how to do so.
229
+ */
230
+ export class XCUITestDriver extends BaseDriver {
231
+ static newMethodMap = newMethodMap;
232
+
233
+ static executeMethodMap = executeMethodMap;
234
+
235
+ /** @type {string|null|undefined} */
236
+ curWindowHandle;
237
+
238
+ /**
239
+ * @type {boolean|undefined}
240
+ */
241
+ selectingNewPage;
242
+
243
+ /** @type {string[]} */
244
+ contexts;
245
+
246
+ /** @type {string|null} */
247
+ curContext;
248
+
249
+ /** @type {string[]} */
250
+ curWebFrames;
251
+
252
+ /** @type {import('./types').CalibrationData|null} */
253
+ webviewCalibrationResult;
254
+
255
+ /** @type {import('./types').AsyncPromise|undefined} */
256
+ asyncPromise;
257
+
258
+ /** @type {number|undefined} */
259
+ asyncWaitMs;
260
+
261
+ /** @type {((logRecord: {message: string}) => void)|null} */
262
+ _syslogWebsocketListener;
263
+
264
+ /** @type {import('./commands/performance').PerfRecorder[]} */
265
+ _perfRecorders;
266
+
267
+ /** @type {LRUCache} */
268
+ webElementsCache;
269
+
270
+ /**
271
+ * @type {any|null}
272
+ * @privateRemarks needs types
273
+ **/
274
+ _conditionInducerService;
275
+
276
+ /** @type {boolean|undefined} */
277
+ _isSafariIphone;
278
+
279
+ /** @type {boolean|undefined} */
280
+ _isSafariNotched;
281
+
282
+ /** @type {import('./commands/types').WaitingAtoms} */
283
+ _waitingAtoms;
284
+
285
+ /** @type {import('./types').LifecycleData} */
286
+ lifecycleData;
287
+
288
+ /** @type {import('./commands/record-audio').AudioRecorder|null} */
289
+ _audioRecorder;
290
+
291
+ /** @type {XcodeVersion|undefined} */
292
+ xcodeVersion;
293
+
294
+ /** @type {import('./commands/pcap').TrafficCapture|null} */
295
+ _trafficCapture;
296
+
297
+ /** @type {import('./commands/recordscreen').ScreenRecorder|null} */
298
+ _recentScreenRecorder;
299
+
300
+ /** @type {Simulator|RealDevice} */
301
+ _device;
302
+
303
+ /** @type {string|null} */
304
+ _iosSdkVersion;
305
+
306
+ /** @type {WebDriverAgent} */
307
+ wda;
308
+
309
+ /** @type {import('appium-remote-debugger').RemoteDebugger|null} */
310
+ remote;
311
+
312
+ /** @type {DriverLogs} */
313
+ logs;
314
+
315
+ /** @type {import('./commands/types').LogListener|undefined} */
316
+ _bidiServerLogListener;
317
+
318
+ /**
319
+ *
320
+ * @param {XCUITestDriverOpts} opts
321
+ * @param {boolean} shouldValidateCaps
322
+ */
323
+ constructor(opts = /** @type {XCUITestDriverOpts} */ ({}), shouldValidateCaps = true) {
324
+ super(opts, shouldValidateCaps);
325
+
326
+ this.locatorStrategies = [
327
+ 'xpath',
328
+ 'id',
329
+ 'name',
330
+ 'class name',
331
+ '-ios predicate string',
332
+ '-ios class chain',
333
+ 'accessibility id',
334
+ 'css selector',
335
+ ];
336
+ this.webLocatorStrategies = [
337
+ 'link text',
338
+ 'css selector',
339
+ 'tag name',
340
+ 'link text',
341
+ 'partial link text',
342
+ ];
343
+ this.curWebFrames = [];
344
+ this._perfRecorders = [];
345
+ this.desiredCapConstraints = desiredCapConstraints;
346
+ this.webElementsCache = new LRUCache({
347
+ max: WEB_ELEMENTS_CACHE_SIZE,
348
+ });
349
+ this.webviewCalibrationResult = null;
350
+ this._waitingAtoms = {
351
+ count: 0,
352
+ alertNotifier: new EventEmitter(),
353
+ alertMonitor: B.resolve(),
354
+ };
355
+ this.resetIos();
356
+ this.settings = new DeviceSettings(DEFAULT_SETTINGS, this.onSettingsUpdate.bind(this));
357
+ this.logs = {};
358
+ this._trafficCapture = null;
359
+ // memoize functions here, so that they are done on a per-instance basis
360
+ for (const fn of MEMOIZED_FUNCTIONS) {
361
+ this[fn] = _.memoize(this[fn]);
362
+ }
363
+ this.lifecycleData = {};
364
+ this._audioRecorder = null;
365
+ this.appInfosCache = new AppInfosCache(this.log);
366
+ this.remote = null;
367
+ this.doesSupportBidi = true;
368
+ }
369
+
370
+ async onSettingsUpdate(key, value) {
371
+ // skip sending the update request to the WDA nor saving it in opts
372
+ // to not spend unnecessary time.
373
+ if (['pageSourceExcludedAttributes'].includes(key)) {
374
+ return;
375
+ }
376
+
377
+ if (key !== 'nativeWebTap' && key !== 'nativeWebTapStrict') {
378
+ return await this.proxyCommand('/appium/settings', 'POST', {
379
+ settings: {[key]: value},
380
+ });
381
+ }
382
+ this.opts[key] = !!value;
383
+ }
384
+
385
+ resetIos() {
386
+ this.opts = this.opts || {};
387
+ // @ts-ignore this is ok
388
+ this.wda = null;
389
+ this.jwpProxyActive = false;
390
+ this.proxyReqRes = null;
391
+ this.safari = false;
392
+ this.cachedWdaStatus = null;
393
+
394
+ this.curWebFrames = [];
395
+ this._currentUrl = null;
396
+ this.curContext = null;
397
+ this.xcodeVersion = undefined;
398
+ this.contexts = [];
399
+ this.implicitWaitMs = 0;
400
+ this.pageLoadMs = 6000;
401
+ this.landscapeWebCoordsOffset = 0;
402
+ this.remote = null;
403
+ this._conditionInducerService = null;
404
+
405
+ this.webElementsCache = new LRUCache({
406
+ max: WEB_ELEMENTS_CACHE_SIZE,
407
+ });
408
+
409
+ this._waitingAtoms = {
410
+ count: 0,
411
+ alertNotifier: new EventEmitter(),
412
+ alertMonitor: B.resolve(),
413
+ };
414
+ }
415
+
416
+ get driverData() {
417
+ // TODO fill out resource info here
418
+ return {};
419
+ }
420
+
421
+ async getStatus() {
422
+ const status = {
423
+ ready: true,
424
+ message: 'The driver is ready to accept new connections',
425
+ build: await getDriverInfo(),
426
+ };
427
+ if (this.cachedWdaStatus) {
428
+ status.wda = this.cachedWdaStatus;
429
+ }
430
+ return status;
431
+ }
432
+
433
+ mergeCliArgsToOpts() {
434
+ let didMerge = false;
435
+ // this.cliArgs should never include anything we do not expect.
436
+ for (const [key, value] of Object.entries(this.cliArgs ?? {})) {
437
+ if (_.has(this.opts, key)) {
438
+ this.log.info(
439
+ `CLI arg '${key}' with value '${value}' overwrites value '${this.opts[key]}' sent in via caps)`,
440
+ );
441
+ didMerge = true;
442
+ }
443
+ this.opts[key] = value;
444
+ }
445
+ return didMerge;
446
+ }
447
+
448
+ /**
449
+ * @returns {Simulator|RealDevice}
450
+ */
451
+ get device() {
452
+ return this._device;
453
+ }
454
+
455
+ isXcodebuildNeeded() {
456
+ return !(CAP_NAMES_NO_XCODEBUILD_REQUIRED.some((x) => Boolean(this.opts[x])));
457
+ }
458
+
459
+ async createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData) {
460
+ try {
461
+ let [sessionId, caps] = await super.createSession(w3cCaps1, w3cCaps2, w3cCaps3, driverData);
462
+
463
+ // merge cli args to opts, and if we did merge any, revalidate opts to ensure the final set
464
+ // is also consistent
465
+ if (this.mergeCliArgsToOpts()) {
466
+ this.validateDesiredCaps({...caps, ...this.cliArgs});
467
+ }
468
+
469
+ await this.start();
470
+
471
+ // merge server capabilities + desired capabilities
472
+ caps = { ...defaultServerCaps, ...caps };
473
+ // update the udid with what is actually used
474
+ caps.udid = this.opts.udid;
475
+ // ensure we track nativeWebTap capability as a setting as well
476
+ if (_.has(this.opts, 'nativeWebTap')) {
477
+ await this.updateSettings({nativeWebTap: this.opts.nativeWebTap});
478
+ }
479
+ // ensure we track nativeWebTapStrict capability as a setting as well
480
+ if (_.has(this.opts, 'nativeWebTapStrict')) {
481
+ await this.updateSettings({nativeWebTapStrict: this.opts.nativeWebTapStrict});
482
+ }
483
+ // ensure we track useJSONSource capability as a setting as well
484
+ if (_.has(this.opts, 'useJSONSource')) {
485
+ await this.updateSettings({useJSONSource: this.opts.useJSONSource});
486
+ }
487
+
488
+ /** @type {import('appium-webdriveragent').WDASettings} */
489
+ let wdaSettings = {
490
+ elementResponseAttributes: DEFAULT_SETTINGS.elementResponseAttributes,
491
+ shouldUseCompactResponses: DEFAULT_SETTINGS.shouldUseCompactResponses,
492
+ };
493
+ if ('elementResponseAttributes' in this.opts && _.isString(this.opts.elementResponseAttributes)) {
494
+ wdaSettings.elementResponseAttributes = this.opts.elementResponseAttributes;
495
+ }
496
+ if ('shouldUseCompactResponses' in this.opts && _.isBoolean(this.opts.shouldUseCompactResponses)) {
497
+ wdaSettings.shouldUseCompactResponses = this.opts.shouldUseCompactResponses;
498
+ }
499
+ if ('mjpegServerScreenshotQuality' in this.opts && _.isNumber(this.opts.mjpegServerScreenshotQuality)) {
500
+ wdaSettings.mjpegServerScreenshotQuality = this.opts.mjpegServerScreenshotQuality;
501
+ }
502
+ if ('mjpegServerFramerate' in this.opts && _.isNumber(this.opts.mjpegServerFramerate)) {
503
+ wdaSettings.mjpegServerFramerate = this.opts.mjpegServerFramerate;
504
+ }
505
+ if (_.has(this.opts, 'screenshotQuality')) {
506
+ this.log.info(`Setting the quality of phone screenshot: '${this.opts.screenshotQuality}'`);
507
+ wdaSettings.screenshotQuality = this.opts.screenshotQuality;
508
+ }
509
+ // ensure WDA gets our defaults instead of whatever its own might be
510
+ await this.updateSettings(wdaSettings);
511
+
512
+ await this.handleMjpegOptions();
513
+
514
+ return /** @type {[string, import('@appium/types').DriverCaps<XCUITestDriverConstraints>]} */ ([
515
+ sessionId,
516
+ caps,
517
+ ]);
518
+ } catch (e) {
519
+ this.log.error(JSON.stringify(e));
520
+ await this.deleteSession();
521
+ throw e;
522
+ }
523
+ }
524
+
525
+ /**
526
+ * Handles MJPEG server-related capabilities
527
+ * @returns {Promise<void>}
528
+ */
529
+ async handleMjpegOptions() {
530
+ await this.allocateMjpegServerPort();
531
+ // turn on mjpeg stream reading if requested
532
+ if (this.opts.mjpegScreenshotUrl) {
533
+ this.log.info(`Starting MJPEG stream reading URL: '${this.opts.mjpegScreenshotUrl}'`);
534
+ this.mjpegStream = new mjpeg.MJpegStream(this.opts.mjpegScreenshotUrl);
535
+ await this.mjpegStream.start();
536
+ }
537
+ }
538
+
539
+ /**
540
+ * Allocates and configures port forwarding for the MJPEG server
541
+ * @returns {Promise<void>}
542
+ * @throws {Error} If port forwarding fails and mjpegServerPort capability value is provided explicitly
543
+ */
544
+ async allocateMjpegServerPort() {
545
+ const mjpegServerPort = this.opts.mjpegServerPort || DEFAULT_MJPEG_SERVER_PORT;
546
+ this.log.debug(
547
+ `Forwarding MJPEG server port ${mjpegServerPort} to local port ${mjpegServerPort}`,
548
+ );
549
+ try {
550
+ await DEVICE_CONNECTIONS_FACTORY.requestConnection(this.opts.udid, mjpegServerPort, {
551
+ devicePort: mjpegServerPort,
552
+ usePortForwarding: this.isRealDevice(),
553
+ });
554
+ } catch (error) {
555
+ if (_.isUndefined(this.opts.mjpegServerPort)) {
556
+ this.log.warn(
557
+ `Cannot forward the device port ${DEFAULT_MJPEG_SERVER_PORT} to the local port ${DEFAULT_MJPEG_SERVER_PORT}. ` +
558
+ `Certain features, like MJPEG-based screen recording, will be unavailable during this session. ` +
559
+ `Try to customize the value of 'mjpegServerPort' capability as a possible solution`,
560
+ );
561
+ } else {
562
+ this.log.debug(error.stack);
563
+ throw new Error(
564
+ `Cannot ensure MJPEG broadcast functionality by forwarding the local port ${mjpegServerPort} ` +
565
+ `requested by the 'mjpegServerPort' capability to the device port ${mjpegServerPort}. ` +
566
+ `Original error: ${error}`,
567
+ );
568
+ }
569
+ }
570
+ }
571
+
572
+ /**
573
+ * Returns the default URL for Safari browser
574
+ * @returns {string} The default URL
575
+ */
576
+ getDefaultUrl() {
577
+ // Setting this to some external URL slows down the session init
578
+ return `${this.getWdaLocalhostRoot()}/health`;
579
+ }
580
+
581
+ async start() {
582
+ this.opts.noReset = !!this.opts.noReset;
583
+ this.opts.fullReset = !!this.opts.fullReset;
584
+
585
+ await printUser();
586
+ this._iosSdkVersion = null; // For WDA and xcodebuild
587
+ const {device, udid, realDevice} = await this.determineDevice();
588
+ this.log.info(
589
+ `Determining device to run tests on: udid: '${udid}', real device: ${realDevice}`,
590
+ );
591
+ this._device = device;
592
+ this.opts.udid = udid;
593
+
594
+ if (this.opts.simulatorDevicesSetPath) {
595
+ if (realDevice) {
596
+ this.log.info(
597
+ `The 'simulatorDevicesSetPath' capability is only supported for Simulator devices`,
598
+ );
599
+ } else {
600
+ this.log.info(
601
+ `Setting simulator devices set path to '${this.opts.simulatorDevicesSetPath}'`,
602
+ );
603
+ (/** @type {Simulator} */ (this.device)).devicesSetPath = this.opts.simulatorDevicesSetPath;
604
+ }
605
+ }
606
+
607
+ // at this point if there is no platformVersion, get it from the device
608
+ if (!this.opts.platformVersion) {
609
+ this.opts.platformVersion = await this.device.getPlatformVersion();
610
+ this.log.info(
611
+ `No platformVersion specified. Using device version: '${this.opts.platformVersion}'`,
612
+ );
613
+ }
614
+
615
+ const normalizedVersion = normalizePlatformVersion(this.opts.platformVersion);
616
+ if (this.opts.platformVersion !== normalizedVersion) {
617
+ this.log.info(
618
+ `Normalized platformVersion capability value '${this.opts.platformVersion}' to '${normalizedVersion}'`,
619
+ );
620
+ this.opts.platformVersion = normalizedVersion;
621
+ }
622
+ this.caps.platformVersion = this.opts.platformVersion;
623
+
624
+ if (_.isEmpty(this.xcodeVersion) && (this.isXcodebuildNeeded() || this.isSimulator())) {
625
+ // no `webDriverAgentUrl`, or on a simulator, so we need an Xcode version
626
+ this.xcodeVersion = await getAndCheckXcodeVersion();
627
+ }
628
+ this.logEvent('xcodeDetailsRetrieved');
629
+
630
+ if (_.toLower(this.opts.browserName) === 'safari') {
631
+ this.log.info('Safari test requested');
632
+ this.safari = true;
633
+ this.opts.app = undefined;
634
+ this.opts.processArguments = this.opts.processArguments || {};
635
+ applySafariStartupArgs.bind(this)();
636
+ this.opts.bundleId = SAFARI_BUNDLE_ID;
637
+ this._currentUrl = this.opts.safariInitialUrl || this.getDefaultUrl();
638
+ } else if (this.opts.app || this.opts.bundleId) {
639
+ await this.configureApp();
640
+ }
641
+ this.logEvent('appConfigured');
642
+
643
+ // fail very early if the app doesn't actually exist
644
+ // or if bundle id doesn't point to an installed app
645
+ if (this.opts.app) {
646
+ await checkAppPresent(this.opts.app);
647
+
648
+ if (!this.opts.bundleId) {
649
+ this.opts.bundleId = await this.appInfosCache.extractBundleId(this.opts.app);
650
+ }
651
+ }
652
+
653
+ await this.runReset();
654
+
655
+ this.wda = new WebDriverAgent(
656
+ /** @type {import('@limrun/appium-xcode').XcodeVersion} */ (this.xcodeVersion),
657
+ {
658
+ ...this.opts,
659
+ device: this.device,
660
+ realDevice: this.isRealDevice(),
661
+ iosSdkVersion: this._iosSdkVersion ?? undefined,
662
+ reqBasePath: this.basePath,
663
+ },
664
+ // @ts-ignore this is ok
665
+ this.log,
666
+ );
667
+ // Derived data path retrieval is an expensive operation
668
+ // We could start that now in background and get the cached result
669
+ // whenever it is needed
670
+ // eslint-disable-next-line promise/prefer-await-to-then
671
+ this.wda.retrieveDerivedDataPath().catch((e) => this.log.debug(e));
672
+
673
+ const memoizedLogInfo = _.memoize(() => {
674
+ this.log.info(
675
+ "'skipLogCapture' is set. Skipping starting logs such as crash, system, safari console and safari network.",
676
+ );
677
+ });
678
+ const startLogCapture = async () => {
679
+ if (this.opts.skipLogCapture) {
680
+ memoizedLogInfo();
681
+ return false;
682
+ }
683
+
684
+ const result = await this.startLogCapture();
685
+ if (result) {
686
+ this.logEvent('logCaptureStarted');
687
+ }
688
+ return result;
689
+ };
690
+ const isLogCaptureStarted = await startLogCapture();
691
+
692
+ this.log.info(`Setting up ${this.isRealDevice() ? 'real device' : 'simulator'}`);
693
+
694
+ if (this.isSimulator()) {
695
+ await this.initSimulator();
696
+ if (!isLogCaptureStarted) {
697
+ // Retry log capture if Simulator was not running before
698
+ await startLogCapture();
699
+ }
700
+ } else if (this.opts.customSSLCert) {
701
+ await new Pyidevice({
702
+ udid,
703
+ log: this.log,
704
+ }).installProfile({payload: this.opts.customSSLCert});
705
+ this.logEvent('customCertInstalled');
706
+ }
707
+
708
+ await this.installAUT();
709
+
710
+ // if we only have bundle identifier and no app, fail if it is not already installed
711
+ if (
712
+ !this.opts.app &&
713
+ this.opts.bundleId &&
714
+ !this.isSafari() &&
715
+ !(await this.device.isAppInstalled(this.opts.bundleId))
716
+ ) {
717
+ throw this.log.errorWithException(`App with bundle identifier '${this.opts.bundleId}' unknown`);
718
+ }
719
+
720
+ if (this.isSimulator()) {
721
+ if (this.opts.permissions) {
722
+ this.log.debug('Setting the requested permissions before WDA is started');
723
+ for (const [bundleId, permissionsMapping] of _.toPairs(JSON.parse(this.opts.permissions))) {
724
+ await /** @type {Simulator} */ (this.device).setPermissions(bundleId, permissionsMapping);
725
+ }
726
+ }
727
+
728
+ // TODO: Deprecate and remove this block together with calendarAccessAuthorized capability
729
+ if (_.isBoolean(this.opts.calendarAccessAuthorized)) {
730
+ this.log.warn(
731
+ `The 'calendarAccessAuthorized' capability is deprecated and will be removed soon. ` +
732
+ `Consider using 'permissions' one instead with 'calendar' key`,
733
+ );
734
+ const methodName = `${
735
+ this.opts.calendarAccessAuthorized ? 'enable' : 'disable'
736
+ }CalendarAccess`;
737
+ await this.device[methodName](this.opts.bundleId);
738
+ }
739
+ }
740
+
741
+ await this.startWda();
742
+
743
+ if (_.isString(this.opts.orientation)) {
744
+ await this.setInitialOrientation(this.opts.orientation);
745
+ this.logEvent('orientationSet');
746
+ }
747
+
748
+ if (this.isSafari() || this.opts.autoWebview) {
749
+ await this.activateRecentWebview();
750
+ } else {
751
+ // We want to always setup the initial context value upon session startup
752
+ await notifyBiDiContextChange.bind(this)();
753
+ }
754
+ if (this.isSafari()) {
755
+ if (shouldSetInitialSafariUrl(this.opts)) {
756
+ this.log.info(`About to set the initial Safari URL to '${this.getCurrentUrl()}'`);
757
+ if (_.isNil(this.opts.safariInitialUrl) && _.isNil(this.opts.initialDeeplinkUrl)) {
758
+ this.log.info(`Use the 'safariInitialUrl' capability to customize it`);
759
+ };
760
+ await this.setUrl(this.getCurrentUrl() || this.getDefaultUrl());
761
+ } else {
762
+ const currentUrl = await this.getUrl();
763
+ this.log.info(`Current URL: ${currentUrl}`);
764
+ this.setCurrentUrl(currentUrl);
765
+ }
766
+ }
767
+ }
768
+
769
+ /**
770
+ * Start the simulator and initialize based on capabilities
771
+ */
772
+ async initSimulator() {
773
+ const device = /** @type {Simulator} */ (this.device);
774
+
775
+ if (this.opts.shutdownOtherSimulators) {
776
+ this.assertFeatureEnabled(SHUTDOWN_OTHER_FEAT_NAME);
777
+ await shutdownOtherSimulators.bind(this)();
778
+ }
779
+
780
+ await this.startSim();
781
+
782
+ if (this.opts.customSSLCert) {
783
+ // Simulator must be booted in order to call this helper
784
+ await device.addCertificate(this.opts.customSSLCert);
785
+ this.logEvent('customCertInstalled');
786
+ }
787
+
788
+ if (await setSafariPrefs.bind(this)()) {
789
+ this.log.debug('Safari preferences have been updated');
790
+ }
791
+
792
+ if (await setLocalizationPrefs.bind(this)()) {
793
+ this.log.debug('Localization preferences have been updated');
794
+ }
795
+
796
+ /** @type {Promise[]} */
797
+ const promises = ['reduceMotion', 'reduceTransparency', 'autoFillPasswords']
798
+ .filter((optName) => _.isBoolean(this.opts[optName]))
799
+ .map((optName) => {
800
+ this.log.info(`Setting ${optName} to ${this.opts[optName]}`);
801
+ return device[`set${_.upperFirst(optName)}`](this.opts[optName]);
802
+ });
803
+ await B.all(promises);
804
+
805
+ if (this.opts.launchWithIDB) {
806
+ try {
807
+ const idb = new IDB({udid: this.opts.udid});
808
+ await idb.connect();
809
+ device.idb = idb;
810
+ } catch (e) {
811
+ this.log.debug(e.stack);
812
+ this.log.warn(
813
+ `idb will not be used for Simulator interaction. Original error: ${e.message}`,
814
+ );
815
+ }
816
+ }
817
+
818
+ this.logEvent('simStarted');
819
+ }
820
+
821
+ /**
822
+ * Start WebDriverAgentRunner
823
+ */
824
+ async startWda() {
825
+ // Don't cleanup the processes if webDriverAgentUrl is set
826
+ if (!util.hasValue(this.wda.webDriverAgentUrl)) {
827
+ await this.wda.cleanupObsoleteProcesses();
828
+ }
829
+
830
+ const usePortForwarding =
831
+ this.isRealDevice() && !this.wda.webDriverAgentUrl && isLocalHost(this.wda.wdaBaseUrl);
832
+ await DEVICE_CONNECTIONS_FACTORY.requestConnection(this.opts.udid, this.wda.url.port, {
833
+ devicePort: usePortForwarding ? this.wda.wdaRemotePort : null,
834
+ usePortForwarding,
835
+ });
836
+
837
+ // Let multiple WDA binaries with different derived data folders be built in parallel
838
+ // Concurrent WDA builds from the same source will cause xcodebuild synchronization errors
839
+ let synchronizationKey = XCUITestDriver.name;
840
+ if (this.opts.useXctestrunFile || !(await this.wda.isSourceFresh())) {
841
+ // First-time compilation is an expensive operation, which is done faster if executed
842
+ // sequentially. Xcodebuild spreads the load caused by the clang compiler to all available CPU cores
843
+ const derivedDataPath = await this.wda.retrieveDerivedDataPath();
844
+ if (derivedDataPath) {
845
+ synchronizationKey = path.normalize(derivedDataPath);
846
+ }
847
+ }
848
+ this.log.debug(
849
+ `Starting WebDriverAgent initialization with the synchronization key '${synchronizationKey}'`,
850
+ );
851
+ if (SHARED_RESOURCES_GUARD.isBusy() && !this.opts.derivedDataPath && !this.opts.bootstrapPath) {
852
+ this.log.debug(
853
+ `Consider setting a unique 'derivedDataPath' capability value for each parallel driver instance ` +
854
+ `to avoid conflicts and speed up the building process`,
855
+ );
856
+ }
857
+
858
+ if (this.opts.usePreinstalledWDA && this.opts.prebuiltWDAPath && !(await fs.exists(this.opts.prebuiltWDAPath))) {
859
+ throw new Error(
860
+ `The prebuilt WebDriverAgent app at '${this.opts.prebuiltWDAPath}' provided as 'prebuiltWDAPath' ` +
861
+ `capability value does not exist or is not accessible`
862
+ );
863
+ }
864
+
865
+ return await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
866
+ if (this.opts.useNewWDA) {
867
+ this.log.debug(`Capability 'useNewWDA' set to true, so uninstalling WDA before proceeding`);
868
+ await this.wda.quitAndUninstall();
869
+ this.logEvent('wdaUninstalled');
870
+ } else if (!util.hasValue(this.wda.webDriverAgentUrl) && this.isXcodebuildNeeded()) {
871
+ await this.wda.setupCaching();
872
+ }
873
+
874
+ // local helper for the two places we need to uninstall wda and re-start it
875
+ const quitAndUninstall = async (msg) => {
876
+ this.log.debug(msg);
877
+ if (!this.isXcodebuildNeeded()) {
878
+ this.log.debug(
879
+ `Not quitting/uninstalling WebDriverAgent since at least one of ${CAP_NAMES_NO_XCODEBUILD_REQUIRED} capabilities is provided`,
880
+ );
881
+ throw new Error(msg);
882
+ }
883
+ this.log.warn('Quitting and uninstalling WebDriverAgent');
884
+ await this.wda.quitAndUninstall();
885
+
886
+ throw new Error(msg);
887
+ };
888
+
889
+ // Used in the following WDA build
890
+ if (this.opts.resultBundlePath) {
891
+ this.assertFeatureEnabled(CUSTOMIZE_RESULT_BUNDLE_PATH);
892
+ }
893
+
894
+ let startupRetries =
895
+ this.opts.wdaStartupRetries ||
896
+ (this.isRealDevice() ? WDA_REAL_DEV_STARTUP_RETRIES : WDA_SIM_STARTUP_RETRIES);
897
+ const startupRetryInterval = this.opts.wdaStartupRetryInterval || WDA_STARTUP_RETRY_INTERVAL;
898
+
899
+ // These values help only xcodebuild.
900
+ if (this.isXcodebuildNeeded()) {
901
+ this.log.debug(
902
+ `Trying to start WebDriverAgent ${startupRetries} times with ${startupRetryInterval}ms interval`,
903
+ );
904
+ if (
905
+ !util.hasValue(this.opts.wdaStartupRetries) &&
906
+ !util.hasValue(this.opts.wdaStartupRetryInterval)
907
+ ) {
908
+ this.log.debug(
909
+ `These values can be customized by changing wdaStartupRetries/wdaStartupRetryInterval capabilities`,
910
+ );
911
+ }
912
+ } else {
913
+ // The startup retry will be one time if the session does not need WDA build
914
+ this.log.debug(`Trying to start WebDriverAgent once since at least one of ${CAP_NAMES_NO_XCODEBUILD_REQUIRED} capabilities is provided`);
915
+ startupRetries = 1;
916
+ }
917
+
918
+ /** @type {Error|null} */
919
+ let shortCircuitError = null;
920
+ let retryCount = 0;
921
+ await retryInterval(startupRetries, startupRetryInterval, async () => {
922
+ this.logEvent('wdaStartAttempted');
923
+ if (retryCount > 0) {
924
+ this.log.info(`Retrying WDA startup (${retryCount + 1} of ${startupRetries})`);
925
+ }
926
+ try {
927
+ if (this.opts.usePreinstalledWDA) {
928
+ await this.preparePreinstalledWda();
929
+ }
930
+
931
+ this.cachedWdaStatus = await this.wda.launch(/** @type {string} */ (this.sessionId));
932
+ } catch (err) {
933
+ this.logEvent('wdaStartFailed');
934
+ this.log.debug(err.stack);
935
+ retryCount++;
936
+ let errorMsg = `Unable to launch WebDriverAgent. Original error: ${err.message}`;
937
+ if (this.isRealDevice()) {
938
+ errorMsg += `. Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}`;
939
+ }
940
+ if (this.opts.usePreinstalledWDA) {
941
+ try {
942
+ // In case the bundle id process start got failed because of
943
+ // auth popup in the device. Then, the bundle id process itself started. It is safe to stop it here.
944
+ await this.mobileKillApp(this.wda.bundleIdForXctest);
945
+ } catch {};
946
+ // Mostly it failed to start the WDA process as no the bundle id
947
+ // e.g. '<bundle id of WDA> not found on device <udid>'
948
+
949
+ errorMsg = `Unable to launch WebDriverAgent. Original error: ${err.message}. ` +
950
+ `Make sure the application ${this.wda.bundleIdForXctest} exists and it is launchable.`;
951
+ if (this.isRealDevice()) {
952
+ errorMsg += ` ${WDA_REAL_DEV_TUTORIAL_URL} may help to complete the preparation.`;
953
+ };
954
+ throw new Error(errorMsg);
955
+ } else {
956
+ await quitAndUninstall(errorMsg);
957
+ }
958
+ }
959
+
960
+ this.proxyReqRes = this.wda.proxyReqRes.bind(this.wda);
961
+ this.jwpProxyActive = true;
962
+
963
+ try {
964
+ this.logEvent('wdaSessionAttempted');
965
+ this.log.debug('Sending createSession command to WDA');
966
+ this.cachedWdaStatus = this.cachedWdaStatus || (await this.proxyCommand('/status', 'GET'));
967
+ await this.startWdaSession(this.opts.bundleId, this.opts.processArguments);
968
+ this.logEvent('wdaSessionStarted');
969
+ } catch (err) {
970
+ this.logEvent('wdaSessionFailed');
971
+ this.log.debug(err.stack);
972
+ if (err instanceof errors.TimeoutError) {
973
+ // Session startup timed out. There is no point to retry
974
+ shortCircuitError = err;
975
+ return;
976
+ }
977
+ let errorMsg = `Unable to start WebDriverAgent session. Original error: ${err.message}`;
978
+ if (this.isRealDevice() && _.includes(err.message, 'xcodebuild')) {
979
+ errorMsg += ` Make sure you follow the tutorial at ${WDA_REAL_DEV_TUTORIAL_URL}.`;
980
+ }
981
+ throw new Error(errorMsg);
982
+ }
983
+
984
+ if (this.opts.clearSystemFiles && this.isXcodebuildNeeded()) {
985
+ await markSystemFilesForCleanup(this.wda);
986
+ }
987
+
988
+ // We don't restrict the version, but show what version of WDA is running on the device for debugging purposes.
989
+ if (this.cachedWdaStatus?.build) {
990
+ this.log.info(`WebDriverAgent version: '${this.cachedWdaStatus.build.version}'`);
991
+ } else {
992
+ this.log.warn(
993
+ `WebDriverAgent does not provide any version information. ` +
994
+ `This might indicate either a custom or an outdated build.`
995
+ );
996
+ }
997
+
998
+ // we expect certain socket errors until this point, but now
999
+ // mark things as fully working
1000
+ this.wda.fullyStarted = true;
1001
+ this.logEvent('wdaStarted');
1002
+ });
1003
+
1004
+ if (shortCircuitError) {
1005
+ throw shortCircuitError;
1006
+ }
1007
+ });
1008
+ }
1009
+
1010
+ /**
1011
+ *
1012
+ * @param {boolean} [enforceSimulatorShutdown=false]
1013
+ */
1014
+ async runReset(enforceSimulatorShutdown = false) {
1015
+ this.logEvent('resetStarted');
1016
+ if (this.isRealDevice()) {
1017
+ await runRealDeviceReset.bind(this)();
1018
+ } else {
1019
+ await runSimulatorReset.bind(this)(enforceSimulatorShutdown);
1020
+ }
1021
+ this.logEvent('resetComplete');
1022
+ }
1023
+
1024
+ async deleteSession(sessionId) {
1025
+ await removeAllSessionWebSocketHandlers.bind(this)();
1026
+
1027
+ for (const recorder of _.compact([
1028
+ this._recentScreenRecorder,
1029
+ this._audioRecorder,
1030
+ this._trafficCapture,
1031
+ ])) {
1032
+ await recorder.interrupt(true);
1033
+ await recorder.cleanup();
1034
+ }
1035
+
1036
+ if (!_.isEmpty(this._perfRecorders)) {
1037
+ await B.all(this._perfRecorders.map((x) => x.stop(true)));
1038
+ this._perfRecorders = [];
1039
+ }
1040
+
1041
+ if (this._conditionInducerService) {
1042
+ this.disableConditionInducer();
1043
+ }
1044
+
1045
+ await this.stop();
1046
+
1047
+ if (this.wda && this.isXcodebuildNeeded()) {
1048
+ if (this.opts.clearSystemFiles) {
1049
+ let synchronizationKey = XCUITestDriver.name;
1050
+ const derivedDataPath = await this.wda.retrieveDerivedDataPath();
1051
+ if (derivedDataPath) {
1052
+ synchronizationKey = path.normalize(derivedDataPath);
1053
+ }
1054
+ await SHARED_RESOURCES_GUARD.acquire(synchronizationKey, async () => {
1055
+ await clearSystemFiles(this.wda);
1056
+ });
1057
+ } else {
1058
+ this.log.debug('Not clearing log files. Use `clearSystemFiles` capability to turn on.');
1059
+ }
1060
+ }
1061
+
1062
+ if (this.remote) {
1063
+ this.log.debug('Found a remote debugger session. Removing...');
1064
+ await this.stopRemote();
1065
+ }
1066
+
1067
+ if (this.opts.resetOnSessionStartOnly === false) {
1068
+ await this.runReset(true);
1069
+ }
1070
+
1071
+ const simulatorDevice = this.isSimulator() ? /** @type {Simulator} */ (this.device) : null;
1072
+ if (simulatorDevice && this.lifecycleData.createSim) {
1073
+ this.log.debug(`Deleting simulator created for this run (udid: '${simulatorDevice.udid}')`);
1074
+ await shutdownSimulator.bind(this)();
1075
+ await simulatorDevice.delete();
1076
+ }
1077
+
1078
+ const shouldResetLocationService = this.isRealDevice() && !!this.opts.resetLocationService;
1079
+ if (shouldResetLocationService) {
1080
+ try {
1081
+ await this.mobileResetLocationService();
1082
+ } catch {
1083
+ /* Ignore this error since mobileResetLocationService already logged the error */
1084
+ }
1085
+ }
1086
+
1087
+ await this.logs.syslog?.stopCapture();
1088
+ _.values(this.logs).forEach((x) => x.removeAllListeners());
1089
+ if (this._bidiServerLogListener) {
1090
+ this.log.unwrap().off('log', this._bidiServerLogListener);
1091
+ }
1092
+ this.logs = {};
1093
+
1094
+ if (this.mjpegStream) {
1095
+ this.log.info('Closing MJPEG stream');
1096
+ this.mjpegStream.stop();
1097
+ }
1098
+
1099
+ this.resetIos();
1100
+
1101
+ await super.deleteSession(sessionId);
1102
+ }
1103
+
1104
+ async stop() {
1105
+ this.jwpProxyActive = false;
1106
+ this.proxyReqRes = null;
1107
+
1108
+ if (this.wda?.fullyStarted) {
1109
+ if (this.wda.jwproxy) {
1110
+ try {
1111
+ await this.proxyCommand(`/session/${this.sessionId}`, 'DELETE');
1112
+ } catch (err) {
1113
+ // an error here should not short-circuit the rest of clean up
1114
+ this.log.debug(`Unable to DELETE session on WDA: '${err.message}'. Continuing shutdown.`);
1115
+ }
1116
+ }
1117
+ // The former could cache the xcodebuild, so should not quit the process.
1118
+ // If the session skipped the xcodebuild (this.wda.canSkipXcodebuild), the this.wda instance
1119
+ // should quit properly.
1120
+ if ((!this.wda.webDriverAgentUrl && this.opts.useNewWDA) || this.wda.canSkipXcodebuild) {
1121
+ await this.wda.quit();
1122
+ }
1123
+ }
1124
+ DEVICE_CONNECTIONS_FACTORY.releaseConnection(this.opts.udid);
1125
+ }
1126
+
1127
+ /**
1128
+ *
1129
+ * @param {string} cmd
1130
+ * @param {...any} args
1131
+ * @returns {Promise<any>}
1132
+ */
1133
+ async executeCommand(cmd, ...args) {
1134
+ this.log.debug(`Executing command '${cmd}'`);
1135
+
1136
+ if (cmd === 'receiveAsyncResponse') {
1137
+ return await this.receiveAsyncResponse(...args);
1138
+ }
1139
+ // TODO: once this fix gets into base driver remove from here
1140
+ if (cmd === 'getStatus') {
1141
+ return await this.getStatus();
1142
+ }
1143
+ return await super.executeCommand(cmd, ...args);
1144
+ }
1145
+
1146
+ async configureApp() {
1147
+ function appIsPackageOrBundle(app) {
1148
+ return /^([a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+)+$/.test(app);
1149
+ }
1150
+
1151
+ // the app name is a bundleId assign it to the bundleId property
1152
+ if (!this.opts.bundleId && appIsPackageOrBundle(this.opts.app)) {
1153
+ this.opts.bundleId = this.opts.app;
1154
+ this.opts.app = '';
1155
+ }
1156
+ // we have a bundle ID, but no app, or app is also a bundle
1157
+ if (
1158
+ this.opts.bundleId &&
1159
+ appIsPackageOrBundle(this.opts.bundleId) &&
1160
+ (this.opts.app === '' || appIsPackageOrBundle(this.opts.app))
1161
+ ) {
1162
+ this.log.debug('App is an iOS bundle, will attempt to run as pre-existing');
1163
+ return;
1164
+ }
1165
+
1166
+ // check for supported build-in apps
1167
+ switch (_.toLower(this.opts.app)) {
1168
+ case 'settings':
1169
+ this.opts.bundleId = 'com.apple.Preferences';
1170
+ this.opts.app = null;
1171
+ return;
1172
+ case 'calendar':
1173
+ this.opts.bundleId = 'com.apple.mobilecal';
1174
+ this.opts.app = null;
1175
+ return;
1176
+ }
1177
+
1178
+ this.opts.app = await this.helpers.configureApp(this.opts.app, {
1179
+ onPostProcess: onPostConfigureApp.bind(this),
1180
+ onDownload: onDownloadApp.bind(this),
1181
+ supportedExtensions: SUPPORTED_EXTENSIONS,
1182
+ });
1183
+ }
1184
+
1185
+ async determineDevice() {
1186
+ // in the one case where we create a sim, we will set this state
1187
+ this.lifecycleData.createSim = false;
1188
+
1189
+ // if we get generic names, translate them
1190
+ this.opts.deviceName = translateDeviceName(this.opts.platformVersion ?? '', this.opts.deviceName);
1191
+
1192
+ const setupVersionCaps = async () => {
1193
+ this._iosSdkVersion = await getAndCheckIosSdkVersion();
1194
+ this.log.info(`iOS SDK Version set to '${this._iosSdkVersion}'`);
1195
+ if (!this.opts.platformVersion && this._iosSdkVersion) {
1196
+ this.log.info(
1197
+ `No platformVersion specified. Using the latest version Xcode supports: '${this._iosSdkVersion}'. ` +
1198
+ `This may cause problems if a simulator does not exist for this platform version.`,
1199
+ );
1200
+ this.opts.platformVersion = normalizePlatformVersion(this._iosSdkVersion);
1201
+ }
1202
+ };
1203
+
1204
+ if (this.opts.udid) {
1205
+ if (this.opts.udid.toLowerCase() === UDID_AUTO) {
1206
+ try {
1207
+ this.opts.udid = await detectUdid.bind(this)();
1208
+ } catch (err) {
1209
+ // Trying to find matching UDID for Simulator
1210
+ this.log.warn(
1211
+ `Cannot detect any connected real devices. Falling back to Simulator. Original error: ${err.message}`,
1212
+ );
1213
+ await setupVersionCaps();
1214
+
1215
+ const device = await getExistingSim.bind(this)();
1216
+ if (!device) {
1217
+ // No matching Simulator is found. Throw an error
1218
+ throw this.log.errorWithException(
1219
+ `Cannot detect udid for ${this.opts.deviceName} Simulator running iOS ${this.opts.platformVersion}`,
1220
+ );
1221
+ }
1222
+ this.opts.udid = device.udid;
1223
+ return {device, realDevice: false, udid: device.udid};
1224
+ }
1225
+ } else {
1226
+ // If the session specified this.opts.webDriverAgentUrl with a real device,
1227
+ // we can assume the user prepared the device properly already.
1228
+ let isRealDeviceUdid = false;
1229
+ const shouldCheckAvailableRealDevices = !this.opts.webDriverAgentUrl;
1230
+ if (shouldCheckAvailableRealDevices) {
1231
+ const devices = await getConnectedDevices();
1232
+ this.log.debug(`Available real devices: ${devices.join(', ')}`);
1233
+ isRealDeviceUdid = devices.includes(this.opts.udid);
1234
+ }
1235
+ if (!isRealDeviceUdid) {
1236
+ try {
1237
+ const device = await getSimulator(this.opts.udid, {
1238
+ devicesSetPath: this.opts.simulatorDevicesSetPath,
1239
+ // @ts-ignore This is ok
1240
+ logger: this.log,
1241
+ });
1242
+ return {device, realDevice: false, udid: this.opts.udid};
1243
+ } catch {
1244
+ if (shouldCheckAvailableRealDevices) {
1245
+ throw new Error(`Unknown device or simulator UDID: '${this.opts.udid}'`);
1246
+ }
1247
+ this.log.debug(
1248
+ 'Skipping checking of the real devices availability since the session specifies appium:webDriverAgentUrl'
1249
+ );
1250
+ }
1251
+ }
1252
+ }
1253
+
1254
+ this.log.debug(`Creating iDevice object with udid '${this.opts.udid}'`);
1255
+ const device = new RealDevice(this.opts.udid, this.log);
1256
+ return {device, realDevice: true, udid: this.opts.udid};
1257
+ }
1258
+
1259
+ this.log.info(
1260
+ `No real device udid has been provided in capabilities. ` +
1261
+ `Will select a matching simulator to run the test.`,
1262
+ );
1263
+ await setupVersionCaps();
1264
+ if (this.opts.enforceFreshSimulatorCreation) {
1265
+ this.log.debug(
1266
+ `New simulator is requested. If this is not wanted, set 'enforceFreshSimulatorCreation' capability to false`,
1267
+ );
1268
+ } else {
1269
+ // figure out the correct simulator to use, given the desired capabilities
1270
+ const device = await getExistingSim.bind(this)();
1271
+ // check for an existing simulator
1272
+ if (device) {
1273
+ return {device, realDevice: false, udid: device.udid};
1274
+ }
1275
+ }
1276
+
1277
+ // no device of this type exists, or they request new sim, so create one
1278
+ this.log.info('Using desired caps to create a new simulator');
1279
+ const device = await this.createSim();
1280
+ return {device, realDevice: false, udid: device.udid};
1281
+ }
1282
+
1283
+ async startSim() {
1284
+ /** @type {import('@limrun/appium-ios-simulator').DevicePreferences} */
1285
+ const devicePreferences = {};
1286
+ /** @type {import('@limrun/appium-ios-simulator').RunOptions} */
1287
+ const runOpts = {
1288
+ scaleFactor: this.opts.scaleFactor,
1289
+ connectHardwareKeyboard: !!this.opts.connectHardwareKeyboard,
1290
+ pasteboardAutomaticSync: this.opts.simulatorPasteboardAutomaticSync ?? 'off',
1291
+ isHeadless: !!this.opts.isHeadless,
1292
+ tracePointer: this.opts.simulatorTracePointer,
1293
+ devicePreferences,
1294
+ };
1295
+
1296
+ // add the window center, if it is specified
1297
+ if (this.opts.simulatorWindowCenter) {
1298
+ devicePreferences.SimulatorWindowCenter = this.opts.simulatorWindowCenter;
1299
+ }
1300
+
1301
+ if (_.isInteger(this.opts.simulatorStartupTimeout)) {
1302
+ runOpts.startupTimeout = this.opts.simulatorStartupTimeout;
1303
+ }
1304
+
1305
+ // This is to workaround XCTest bug about changing Simulator
1306
+ // orientation is not synchronized to the actual window orientation
1307
+ const orientation = _.isString(this.opts.orientation) && this.opts.orientation.toUpperCase();
1308
+ switch (orientation) {
1309
+ case 'LANDSCAPE':
1310
+ devicePreferences.SimulatorWindowOrientation = 'LandscapeLeft';
1311
+ devicePreferences.SimulatorWindowRotationAngle = 90;
1312
+ break;
1313
+ case 'PORTRAIT':
1314
+ devicePreferences.SimulatorWindowOrientation = 'Portrait';
1315
+ devicePreferences.SimulatorWindowRotationAngle = 0;
1316
+ break;
1317
+ }
1318
+
1319
+ await /** @type {Simulator} */ (this.device).run(runOpts);
1320
+ }
1321
+
1322
+ async createSim() {
1323
+ this.lifecycleData.createSim = true;
1324
+ // create sim for caps
1325
+ const sim = await createSim.bind(this)();
1326
+ this.log.info(`Created simulator with udid '${sim.udid}'.`);
1327
+ return sim;
1328
+ }
1329
+
1330
+ async startWdaSession(bundleId, processArguments) {
1331
+ const args = processArguments ? _.cloneDeep(processArguments.args) || [] : [];
1332
+ if (!_.isArray(args)) {
1333
+ throw new Error(
1334
+ `processArguments.args capability is expected to be an array. ` +
1335
+ `${JSON.stringify(args)} is given instead`,
1336
+ );
1337
+ }
1338
+ const env = processArguments ? _.cloneDeep(processArguments.env) || {} : {};
1339
+ if (!_.isPlainObject(env)) {
1340
+ throw new Error(
1341
+ `processArguments.env capability is expected to be a dictionary. ` +
1342
+ `${JSON.stringify(env)} is given instead`,
1343
+ );
1344
+ }
1345
+
1346
+ if (util.hasValue(this.opts.language)) {
1347
+ args.push('-AppleLanguages', `(${this.opts.language})`);
1348
+ args.push('-NSLanguages', `(${this.opts.language})`);
1349
+ }
1350
+ if (util.hasValue(this.opts.locale)) {
1351
+ args.push('-AppleLocale', this.opts.locale);
1352
+ }
1353
+
1354
+ if (this.opts.noReset) {
1355
+ if (_.isNil(this.opts.shouldTerminateApp)) {
1356
+ this.opts.shouldTerminateApp = false;
1357
+ }
1358
+ if (_.isNil(this.opts.forceAppLaunch)) {
1359
+ this.opts.forceAppLaunch = false;
1360
+ }
1361
+ }
1362
+
1363
+ if (util.hasValue(this.opts.appTimeZone)) {
1364
+ // https://developer.apple.com/forums/thread/86951?answerId=263395022#263395022
1365
+ env.TZ = this.opts.appTimeZone;
1366
+ }
1367
+
1368
+ /** @type {import('appium-webdriveragent').WDACapabilities} */
1369
+ const wdaCaps = {
1370
+ bundleId: this.opts.autoLaunch === false ? undefined : bundleId,
1371
+ arguments: args,
1372
+ environment: env,
1373
+ eventloopIdleDelaySec: this.opts.wdaEventloopIdleDelay ?? 0,
1374
+ shouldWaitForQuiescence: this.opts.waitForQuiescence ?? true,
1375
+ shouldUseTestManagerForVisibilityDetection: this.opts.simpleIsVisibleCheck ?? false,
1376
+ maxTypingFrequency: this.opts.maxTypingFrequency ?? 60,
1377
+ shouldUseSingletonTestManager: this.opts.shouldUseSingletonTestManager ?? true,
1378
+ waitForIdleTimeout: this.opts.waitForIdleTimeout,
1379
+ // @ts-expect-error - do not assign arbitrary properties to `this.opts`
1380
+ shouldUseCompactResponses: this.opts.shouldUseCompactResponses,
1381
+ // @ts-expect-error - do not assign arbitrary properties to `this.opts`
1382
+ elementResponseFields: this.opts.elementResponseFields,
1383
+ disableAutomaticScreenshots: this.opts.disableAutomaticScreenshots,
1384
+ shouldTerminateApp: this.opts.shouldTerminateApp ?? true,
1385
+ forceAppLaunch: this.opts.forceAppLaunch ?? true,
1386
+ appLaunchStateTimeoutSec: this.opts.appLaunchStateTimeoutSec,
1387
+ useNativeCachingStrategy: this.opts.useNativeCachingStrategy ?? true,
1388
+ forceSimulatorSoftwareKeyboardPresence:
1389
+ this.opts.forceSimulatorSoftwareKeyboardPresence ??
1390
+ (this.opts.connectHardwareKeyboard === true ? false : true),
1391
+ };
1392
+ if (this.opts.autoAcceptAlerts) {
1393
+ wdaCaps.defaultAlertAction = 'accept';
1394
+ } else if (this.opts.autoDismissAlerts) {
1395
+ wdaCaps.defaultAlertAction = 'dismiss';
1396
+ }
1397
+ if (this.opts.initialDeeplinkUrl) {
1398
+ this.log.info(`The deeplink URL will be set to ${this.opts.initialDeeplinkUrl}`);
1399
+ wdaCaps.initialUrl = this.opts.initialDeeplinkUrl;
1400
+ }
1401
+
1402
+ const timer = new timing.Timer().start();
1403
+ await this.proxyCommand('/session', 'POST', {
1404
+ capabilities: {
1405
+ firstMatch: [wdaCaps],
1406
+ alwaysMatch: {},
1407
+ },
1408
+ });
1409
+ this.log.info(`WDA session startup took ${timer.getDuration().asMilliSeconds.toFixed(0)}ms`);
1410
+ }
1411
+
1412
+ // Override Proxy methods from BaseDriver
1413
+ proxyActive() {
1414
+ return Boolean(this.jwpProxyActive);
1415
+ }
1416
+
1417
+ getProxyAvoidList() {
1418
+ if (this.isWebview()) {
1419
+ return NO_PROXY_WEB_LIST;
1420
+ }
1421
+ return NO_PROXY_NATIVE_LIST;
1422
+ }
1423
+
1424
+ canProxy() {
1425
+ return true;
1426
+ }
1427
+
1428
+ /**
1429
+ * @returns {boolean}
1430
+ */
1431
+ isSafari() {
1432
+ return !!this.safari;
1433
+ }
1434
+
1435
+ /**
1436
+ * @returns {boolean}
1437
+ */
1438
+ isRealDevice() {
1439
+ return 'devicectl' in (this.device ?? {});
1440
+ }
1441
+
1442
+ /**
1443
+ * @returns {boolean}
1444
+ */
1445
+ isSimulator() {
1446
+ return 'simctl' in (this.device ?? {});
1447
+ }
1448
+
1449
+ /**
1450
+ * @param {string} strategy
1451
+ */
1452
+ validateLocatorStrategy(strategy) {
1453
+ super.validateLocatorStrategy(strategy, this.isWebContext());
1454
+ }
1455
+
1456
+ /**
1457
+ * @param {any} caps
1458
+ * @returns {caps is import('@appium/types').DriverCaps<XCUITestDriverConstraints>}
1459
+ */
1460
+ validateDesiredCaps(caps) {
1461
+ if (!super.validateDesiredCaps(caps)) {
1462
+ return false;
1463
+ }
1464
+
1465
+ // make sure that the capabilities have one of `app` or `bundleId`
1466
+ if (_.toLower(caps.browserName) !== 'safari' && !caps.app && !caps.bundleId) {
1467
+ this.log.info(
1468
+ 'The desired capabilities include neither an app nor a bundleId. ' +
1469
+ 'WebDriverAgent will be started without the default app',
1470
+ );
1471
+ }
1472
+
1473
+ if (!util.coerceVersion(String(caps.platformVersion), false)) {
1474
+ this.log.warn(
1475
+ `'platformVersion' capability ('${caps.platformVersion}') is not a valid version number. ` +
1476
+ `Consider fixing it or be ready to experience an inconsistent driver behavior.`,
1477
+ );
1478
+ }
1479
+
1480
+ let verifyProcessArgument = (processArguments) => {
1481
+ const {args, env} = processArguments;
1482
+ if (!_.isNil(args) && !_.isArray(args)) {
1483
+ throw this.log.errorWithException('processArguments.args must be an array of strings');
1484
+ }
1485
+ if (!_.isNil(env) && !_.isPlainObject(env)) {
1486
+ throw this.log.errorWithException(
1487
+ 'processArguments.env must be an object <key,value> pair {a:b, c:d}',
1488
+ );
1489
+ }
1490
+ };
1491
+
1492
+ // `processArguments` should be JSON string or an object with arguments and/ environment details
1493
+ if (caps.processArguments) {
1494
+ if (_.isString(caps.processArguments)) {
1495
+ try {
1496
+ // try to parse the string as JSON
1497
+ caps.processArguments = JSON.parse(caps.processArguments);
1498
+ verifyProcessArgument(caps.processArguments);
1499
+ } catch (err) {
1500
+ throw this.log.errorWithException(
1501
+ `processArguments must be a JSON format or an object with format {args : [], env : {a:b, c:d}}. ` +
1502
+ `Both environment and argument can be null. Error: ${err}`,
1503
+ );
1504
+ }
1505
+ } else if (_.isPlainObject(caps.processArguments)) {
1506
+ verifyProcessArgument(caps.processArguments);
1507
+ } else {
1508
+ throw this.log.errorWithException(
1509
+ `'processArguments must be an object, or a string JSON object with format {args : [], env : {a:b, c:d}}. ` +
1510
+ `Both environment and argument can be null.`,
1511
+ );
1512
+ }
1513
+ }
1514
+
1515
+ // there is no point in having `keychainPath` without `keychainPassword`
1516
+ if (
1517
+ (caps.keychainPath && !caps.keychainPassword) ||
1518
+ (!caps.keychainPath && caps.keychainPassword)
1519
+ ) {
1520
+ throw this.log.errorWithException(
1521
+ `If 'keychainPath' is set, 'keychainPassword' must also be set (and vice versa).`,
1522
+ );
1523
+ }
1524
+
1525
+ // `resetOnSessionStartOnly` should be set to true by default
1526
+ this.opts.resetOnSessionStartOnly =
1527
+ !util.hasValue(this.opts.resetOnSessionStartOnly) || this.opts.resetOnSessionStartOnly;
1528
+ this.opts.useNewWDA = util.hasValue(this.opts.useNewWDA) ? this.opts.useNewWDA : false;
1529
+
1530
+ if (caps.commandTimeouts) {
1531
+ caps.commandTimeouts = normalizeCommandTimeouts(caps.commandTimeouts);
1532
+ }
1533
+
1534
+ if (_.isString(caps.webDriverAgentUrl)) {
1535
+ const {protocol, host} = url.parse(caps.webDriverAgentUrl);
1536
+ if (_.isEmpty(protocol) || _.isEmpty(host)) {
1537
+ throw this.log.errorWithException(
1538
+ `'webDriverAgentUrl' capability is expected to contain a valid WebDriverAgent server URL. ` +
1539
+ `'${caps.webDriverAgentUrl}' is given instead`,
1540
+ );
1541
+ }
1542
+ }
1543
+
1544
+ if (caps.browserName) {
1545
+ if (caps.bundleId) {
1546
+ throw this.log.errorWithException(
1547
+ `'browserName' cannot be set together with 'bundleId' capability`
1548
+ );
1549
+ }
1550
+ // warn if the capabilities have both `app` and `browser, although this
1551
+ // is common with selenium grid
1552
+ if (caps.app) {
1553
+ this.log.warn(
1554
+ `The capabilities should generally not include both an 'app' and a 'browserName'`,
1555
+ );
1556
+ }
1557
+ }
1558
+
1559
+ if (caps.permissions) {
1560
+ try {
1561
+ for (const [bundleId, perms] of _.toPairs(JSON.parse(caps.permissions))) {
1562
+ if (!_.isString(bundleId)) {
1563
+ throw new Error(`'${JSON.stringify(bundleId)}' must be a string`);
1564
+ }
1565
+ if (!_.isPlainObject(perms)) {
1566
+ throw new Error(`'${JSON.stringify(perms)}' must be a JSON object`);
1567
+ }
1568
+ }
1569
+ } catch (e) {
1570
+ throw this.log.errorWithException(
1571
+ `'${caps.permissions}' is expected to be a valid object with format ` +
1572
+ `{"<bundleId1>": {"<serviceName1>": "<serviceStatus1>", ...}, ...}. Original error: ${e.message}`,
1573
+ );
1574
+ }
1575
+ }
1576
+
1577
+ if (caps.platformVersion && !util.coerceVersion(caps.platformVersion, false)) {
1578
+ throw this.log.errorWithException(
1579
+ `'platformVersion' must be a valid version number. ` +
1580
+ `'${caps.platformVersion}' is given instead.`,
1581
+ );
1582
+ }
1583
+
1584
+ // additionalWebviewBundleIds is an array, JSON array, or string
1585
+ if (caps.additionalWebviewBundleIds) {
1586
+ caps.additionalWebviewBundleIds = this.helpers.parseCapsArray(
1587
+ caps.additionalWebviewBundleIds,
1588
+ );
1589
+ }
1590
+
1591
+ // finally, return true since the superclass check passed, as did this
1592
+ return true;
1593
+ }
1594
+
1595
+ /**
1596
+ * Check if the given app can be installed, or should uninstall before installing it.
1597
+ *
1598
+ * @param {AutInstallationStateOptions} [opts]
1599
+ * @returns {Promise<AutInstallationState>}
1600
+ */
1601
+ async checkAutInstallationState(opts) {
1602
+ const {enforceAppInstall, fullReset, noReset, bundleId, app} = opts ?? this.opts;
1603
+
1604
+ const wasAppInstalled = await this.device.isAppInstalled(bundleId);
1605
+ if (wasAppInstalled) {
1606
+ this.log.info(`App '${bundleId}' is already installed`);
1607
+ if (noReset) {
1608
+ this.log.info('noReset is requested. The app will not be be (re)installed');
1609
+ return {
1610
+ install: false,
1611
+ skipUninstall: true,
1612
+ };
1613
+ }
1614
+ } else {
1615
+ this.log.info(`App '${bundleId}' is not installed yet or it has an offload and ` +
1616
+ 'cannot be detected, which might keep the local data.');
1617
+ }
1618
+ if (enforceAppInstall !== false || fullReset || !wasAppInstalled) {
1619
+ return {
1620
+ install: true,
1621
+ skipUninstall: !wasAppInstalled,
1622
+ };
1623
+ }
1624
+
1625
+ const candidateBundleVersion = await this.appInfosCache.extractBundleVersion(app);
1626
+ this.log.debug(`CFBundleVersion from Info.plist: ${candidateBundleVersion}`);
1627
+ if (!candidateBundleVersion) {
1628
+ return {
1629
+ install: true,
1630
+ skipUninstall: false,
1631
+ };
1632
+ }
1633
+
1634
+ const appBundleVersion = this.isRealDevice()
1635
+ ? (await /** @type {RealDevice} */ (this.device).fetchAppInfo(bundleId))?.CFBundleVersion
1636
+ : BUNDLE_VERSION_PATTERN.exec(await /** @type {Simulator} */ (this.device).simctl.appInfo(bundleId))?.[1];
1637
+ this.log.debug(`CFBundleVersion from installed app info: ${appBundleVersion}`);
1638
+ if (!appBundleVersion) {
1639
+ return {
1640
+ install: true,
1641
+ skipUninstall: false,
1642
+ };
1643
+ }
1644
+
1645
+ let shouldUpgrade;
1646
+ try {
1647
+ shouldUpgrade = util.compareVersions(candidateBundleVersion, '>', appBundleVersion);
1648
+ } catch (err) {
1649
+ this.log.warn(`App versions comparison is not possible: ${err.message}`);
1650
+ return {
1651
+ install: true,
1652
+ skipUninstall: false,
1653
+ };
1654
+ }
1655
+ if (shouldUpgrade) {
1656
+ this.log.info(
1657
+ `The installed version of ${bundleId} is lower than the candidate one ` +
1658
+ `(${candidateBundleVersion} > ${appBundleVersion}). The app will be upgraded.`,
1659
+ );
1660
+ } else {
1661
+ this.log.info(
1662
+ `The candidate version of ${bundleId} is lower than the installed one ` +
1663
+ `(${candidateBundleVersion} <= ${appBundleVersion}). The app won't be reinstalled.`,
1664
+ );
1665
+ }
1666
+ return {
1667
+ install: shouldUpgrade,
1668
+ skipUninstall: true,
1669
+ };
1670
+ }
1671
+
1672
+ async installAUT() {
1673
+ // install any other apps
1674
+ if (this.opts.otherApps) {
1675
+ await this.installOtherApps(this.opts.otherApps);
1676
+ }
1677
+
1678
+ if (this.isSafari() || !this.opts.app) {
1679
+ return;
1680
+ }
1681
+
1682
+ await verifyApplicationPlatform.bind(this)();
1683
+
1684
+ const {install, skipUninstall} = await this.checkAutInstallationState();
1685
+ if (install) {
1686
+ if (this.isRealDevice()) {
1687
+ await installToRealDevice.bind(this)(this.opts.app, this.opts.bundleId, {
1688
+ skipUninstall,
1689
+ timeout: this.opts.appPushTimeout,
1690
+ });
1691
+ } else {
1692
+ await installToSimulator.bind(this)(this.opts.app, this.opts.bundleId, {
1693
+ skipUninstall,
1694
+ newSimulator: this.lifecycleData?.createSim,
1695
+ });
1696
+ }
1697
+ if (util.hasValue(this.opts.iosInstallPause)) {
1698
+ // https://github.com/appium/appium/issues/6889
1699
+ const pauseMs = parseInt(this.opts.iosInstallPause, 10);
1700
+ this.log.debug(`iosInstallPause set. Pausing ${pauseMs} ms before continuing`);
1701
+ await B.delay(pauseMs);
1702
+ }
1703
+ this.logEvent('appInstalled');
1704
+ }
1705
+ }
1706
+
1707
+ /**
1708
+ * @param {string|string[]} otherApps
1709
+ * @returns {Promise<void>}
1710
+ */
1711
+ async installOtherApps(otherApps) {
1712
+ /** @type {string[]|undefined} */
1713
+ let appsList;
1714
+ try {
1715
+ appsList = this.helpers.parseCapsArray(otherApps);
1716
+ } catch (e) {
1717
+ throw this.log.errorWithException(`Could not parse "otherApps" capability: ${e.message}`);
1718
+ }
1719
+ if (!appsList?.length) {
1720
+ this.log.info(`Got zero apps from 'otherApps' capability value. Doing nothing`);
1721
+ return;
1722
+ }
1723
+
1724
+ /** @type {string[]} */
1725
+ const appPaths = await B.all(appsList.map((app) => this.helpers.configureApp(app, {
1726
+ onPostProcess: onPostConfigureApp.bind(this),
1727
+ onDownload: onDownloadApp.bind(this),
1728
+ supportedExtensions: SUPPORTED_EXTENSIONS,
1729
+ })));
1730
+ /** @type {string[]} */
1731
+ const appIds = await B.all(appPaths.map((appPath) => this.appInfosCache.extractBundleId(appPath)));
1732
+ for (const [appId, appPath] of _.zip(appIds, appPaths)) {
1733
+ if (this.isRealDevice()) {
1734
+ await installToRealDevice.bind(this)(
1735
+ appPath,
1736
+ appId,
1737
+ {
1738
+ skipUninstall: true, // to make the behavior as same as UIA2
1739
+ timeout: this.opts.appPushTimeout,
1740
+ },
1741
+ );
1742
+ } else {
1743
+ await installToSimulator.bind(this)(
1744
+ appPath,
1745
+ appId,
1746
+ {
1747
+ newSimulator: this.lifecycleData.createSim,
1748
+ },
1749
+ );
1750
+ }
1751
+ }
1752
+ }
1753
+
1754
+ /**
1755
+ * @param {string} orientation
1756
+ * @returns {Promise<void>}
1757
+ */
1758
+ async setInitialOrientation(orientation) {
1759
+ const dstOrientation = _.toUpper(orientation);
1760
+ if (!SUPPORTED_ORIENATIONS.includes(dstOrientation)) {
1761
+ this.log.debug(
1762
+ `The initial orientation value '${orientation}' is unknown. ` +
1763
+ `Only ${JSON.stringify(SUPPORTED_ORIENATIONS)} are supported.`,
1764
+ );
1765
+ return;
1766
+ }
1767
+
1768
+ this.log.debug(`Setting initial orientation to '${dstOrientation}'`);
1769
+ try {
1770
+ await this.proxyCommand('/orientation', 'POST', {orientation: dstOrientation});
1771
+ } catch (err) {
1772
+ this.log.warn(`Setting initial orientation failed with: ${err.message}`);
1773
+ }
1774
+ }
1775
+
1776
+ /**
1777
+ * @param {string} [cmdName]
1778
+ * @returns {number|undefined}
1779
+ */
1780
+ _getCommandTimeout(cmdName) {
1781
+ if (this.opts.commandTimeouts) {
1782
+ if (cmdName && _.has(this.opts.commandTimeouts, cmdName)) {
1783
+ return this.opts.commandTimeouts[cmdName];
1784
+ }
1785
+ return this.opts.commandTimeouts[DEFAULT_TIMEOUT_KEY];
1786
+ }
1787
+ }
1788
+
1789
+ /**
1790
+ * Reset the current session (run the delete session and create session subroutines)
1791
+ */
1792
+ async reset() {
1793
+ throw new Error(
1794
+ `The reset API has been deprecated and is not supported anymore. ` +
1795
+ `Consider using corresponding 'mobile:' extensions to manage the state of the app under test.`,
1796
+ );
1797
+ }
1798
+
1799
+ async preparePreinstalledWda() {
1800
+ if (this.isRealDevice()) {
1801
+ // Stop the existing process before starting a new one to start a fresh WDA process every session.
1802
+ await this.mobileKillApp(this.wda.bundleIdForXctest);
1803
+ }
1804
+
1805
+ if (!this.opts.prebuiltWDAPath) {
1806
+ return;
1807
+ }
1808
+
1809
+ const candidateBundleId = await this.appInfosCache.extractBundleId(this.opts.prebuiltWDAPath);
1810
+ this.wda.updatedWDABundleId = candidateBundleId.replace('.xctrunner', '');
1811
+ this.log.info(
1812
+ `Installing prebuilt WDA at '${this.opts.prebuiltWDAPath}'. ` +
1813
+ `Bundle identifier: ${candidateBundleId}.`
1814
+ );
1815
+
1816
+ // Note: The CFBundleVersion in the test bundle was always 1.
1817
+ // It may not be able to compare with the installed version.
1818
+ if (this.isRealDevice()) {
1819
+ await installToRealDevice.bind(this)(
1820
+ this.opts.prebuiltWDAPath,
1821
+ candidateBundleId,
1822
+ {
1823
+ skipUninstall: true,
1824
+ timeout: this.opts.appPushTimeout,
1825
+ },
1826
+ );
1827
+ } else {
1828
+ await installToSimulator.bind(this)(
1829
+ this.opts.prebuiltWDAPath,
1830
+ candidateBundleId
1831
+ );
1832
+ }
1833
+ }
1834
+
1835
+ /*---------------+
1836
+ | ACTIVEAPPINFO |
1837
+ +---------------+*/
1838
+
1839
+ mobileGetActiveAppInfo = activeAppInfoCommands.mobileGetActiveAppInfo;
1840
+
1841
+ /*-------+
1842
+ | ALERT |
1843
+ +-------+*/
1844
+ getAlertText = alertCommands.getAlertText;
1845
+ setAlertText = alertCommands.setAlertText;
1846
+ postAcceptAlert = alertCommands.postAcceptAlert;
1847
+ postDismissAlert = alertCommands.postDismissAlert;
1848
+ getAlertButtons = alertCommands.getAlertButtons;
1849
+ mobileHandleAlert = alertCommands.mobileHandleAlert;
1850
+
1851
+ /*---------------+
1852
+ | APPMANAGEMENT |
1853
+ +---------------+*/
1854
+
1855
+ mobileInstallApp = appManagementCommands.mobileInstallApp;
1856
+ mobileIsAppInstalled = appManagementCommands.mobileIsAppInstalled;
1857
+ mobileRemoveApp = appManagementCommands.mobileRemoveApp;
1858
+ mobileLaunchApp = appManagementCommands.mobileLaunchApp;
1859
+ mobileTerminateApp = appManagementCommands.mobileTerminateApp;
1860
+ mobileActivateApp = appManagementCommands.mobileActivateApp;
1861
+ mobileKillApp = appManagementCommands.mobileKillApp;
1862
+ mobileQueryAppState = appManagementCommands.mobileQueryAppState;
1863
+ installApp = appManagementCommands.installApp;
1864
+ activateApp = appManagementCommands.activateApp;
1865
+ isAppInstalled = appManagementCommands.isAppInstalled;
1866
+ // @ts-ignore it must return boolean
1867
+ terminateApp = appManagementCommands.terminateApp;
1868
+ queryAppState = appManagementCommands.queryAppState;
1869
+ mobileListApps = appManagementCommands.mobileListApps;
1870
+ mobileClearApp = appManagementCommands.mobileClearApp;
1871
+
1872
+ /*------------+
1873
+ | APPEARANCE |
1874
+ +------------+*/
1875
+
1876
+ mobileSetAppearance = appearanceCommands.mobileSetAppearance;
1877
+ mobileGetAppearance = appearanceCommands.mobileGetAppearance;
1878
+
1879
+ /*------------+
1880
+ | INCREASE CONTRAST |
1881
+ +------------+*/
1882
+
1883
+ mobileSetIncreaseContrast = increaseContrastCommands.mobileSetIncreaseContrast;
1884
+ mobileGetIncreaseContrast = increaseContrastCommands.mobileGetIncreaseContrast;
1885
+
1886
+ /*------------+
1887
+ | CONTENT SIZE |
1888
+ +------------+*/
1889
+
1890
+ mobileSetContentSize = contentSizeCommands.mobileSetContentSize;
1891
+ mobileGetContentSize = contentSizeCommands.mobileGetContentSize;
1892
+
1893
+ /*------------+
1894
+ | AUDIT |
1895
+ +------------+*/
1896
+
1897
+ mobilePerformAccessibilityAudit = auditCommands.mobilePerformAccessibilityAudit;
1898
+
1899
+ /*---------+
1900
+ | BATTERY |
1901
+ +---------+*/
1902
+ mobileGetBatteryInfo = batteryCommands.mobileGetBatteryInfo;
1903
+
1904
+ /*-----------+
1905
+ | BIOMETRIC |
1906
+ +-----------+*/
1907
+
1908
+ mobileEnrollBiometric = biometricCommands.mobileEnrollBiometric;
1909
+ mobileSendBiometricMatch = biometricCommands.mobileSendBiometricMatch;
1910
+ mobileIsBiometricEnrolled = biometricCommands.mobileIsBiometricEnrolled;
1911
+
1912
+ /*-------------+
1913
+ | CERTIFICATE |
1914
+ +-------------+*/
1915
+ mobileInstallCertificate = certificateCommands.mobileInstallCertificate;
1916
+ mobileListCertificates = certificateCommands.mobileListCertificates;
1917
+ mobileRemoveCertificate = certificateCommands.mobileRemoveCertificate;
1918
+
1919
+ /*-----------+
1920
+ | CLIPBOARD |
1921
+ +-----------+*/
1922
+
1923
+ setClipboard = clipboardCommands.setClipboard;
1924
+ getClipboard = clipboardCommands.getClipboard;
1925
+
1926
+ /*-----------+
1927
+ | CONDITION |
1928
+ +-----------+*/
1929
+
1930
+ listConditionInducers = conditionCommands.listConditionInducers;
1931
+ enableConditionInducer = conditionCommands.enableConditionInducer;
1932
+ disableConditionInducer = conditionCommands.disableConditionInducer;
1933
+
1934
+ /*---------+
1935
+ | CONTEXT |
1936
+ +---------+*/
1937
+
1938
+ getContexts = contextCommands.getContexts;
1939
+ getCurrentContext = contextCommands.getCurrentContext;
1940
+ // @ts-ignore This is OK
1941
+ getWindowHandle = contextCommands.getWindowHandle;
1942
+ getWindowHandles = contextCommands.getWindowHandles;
1943
+ // @ts-ignore Type mismatch: function type vs method signature
1944
+ setContext = contextCommands.setContext;
1945
+ // @ts-ignore This is OK
1946
+ setWindow = contextCommands.setWindow;
1947
+ activateRecentWebview = contextCommands.activateRecentWebview;
1948
+ connectToRemoteDebugger = contextCommands.connectToRemoteDebugger;
1949
+ getContextsAndViews = contextCommands.getContextsAndViews;
1950
+ listWebFrames = contextCommands.listWebFrames;
1951
+ mobileGetContexts = contextCommands.mobileGetContexts;
1952
+ onPageChange = contextCommands.onPageChange;
1953
+ useNewSafari = contextCommands.useNewSafari;
1954
+ getCurrentUrl = contextCommands.getCurrentUrl;
1955
+ getNewRemoteDebugger = contextCommands.getNewRemoteDebugger;
1956
+ getRecentWebviewContextId = contextCommands.getRecentWebviewContextId;
1957
+ isWebContext = contextCommands.isWebContext;
1958
+ isWebview = contextCommands.isWebview;
1959
+ setCurrentUrl = contextCommands.setCurrentUrl;
1960
+ stopRemote = contextCommands.stopRemote;
1961
+
1962
+ /*------------+
1963
+ | DEVICEINFO |
1964
+ +------------+*/
1965
+
1966
+ mobileGetDeviceInfo = deviceInfoCommands.mobileGetDeviceInfo;
1967
+
1968
+ /*---------+
1969
+ | ELEMENT |
1970
+ +---------+*/
1971
+
1972
+ elementDisplayed = elementCommands.elementDisplayed;
1973
+ elementEnabled = elementCommands.elementEnabled;
1974
+ elementSelected = elementCommands.elementSelected;
1975
+ getName = elementCommands.getName;
1976
+ getNativeAttribute = elementCommands.getNativeAttribute;
1977
+ getAttribute = elementCommands.getAttribute;
1978
+ getProperty = elementCommands.getProperty;
1979
+ getText = elementCommands.getText;
1980
+ getElementRect = elementCommands.getElementRect;
1981
+ getLocation = elementCommands.getLocation;
1982
+ getLocationInView = elementCommands.getLocationInView;
1983
+ getSize = elementCommands.getSize;
1984
+ /** @deprecated */
1985
+ setValueImmediate = elementCommands.setValueImmediate;
1986
+ setValue = elementCommands.setValue;
1987
+ setValueWithWebAtom = elementCommands.setValueWithWebAtom;
1988
+ keys = elementCommands.keys;
1989
+ clear = elementCommands.clear;
1990
+ getContentSize = elementCommands.getContentSize;
1991
+ getNativeRect = elementCommands.getNativeRect;
1992
+
1993
+ /*---------+
1994
+ | EXECUTE |
1995
+ +---------+*/
1996
+
1997
+ receiveAsyncResponse = executeCommands.receiveAsyncResponse;
1998
+ execute = executeCommands.execute;
1999
+ // @ts-ignore Type mismatch: function type vs method signature
2000
+ executeAsync = executeCommands.executeAsync;
2001
+ // Note: executeMobile is handled internally via execute method
2002
+ mobileSimctl = simctlCommands.mobileSimctl;
2003
+
2004
+ /*--------------+
2005
+ | FILEMOVEMENT |
2006
+ +--------------+*/
2007
+
2008
+ pushFile = fileMovementCommands.pushFile;
2009
+ mobilePushFile = fileMovementCommands.mobilePushFile;
2010
+ pullFile = fileMovementCommands.pullFile;
2011
+ mobilePullFile = fileMovementCommands.mobilePullFile;
2012
+ mobileDeleteFolder = fileMovementCommands.mobileDeleteFolder;
2013
+ mobileDeleteFile = fileMovementCommands.mobileDeleteFile;
2014
+ pullFolder = fileMovementCommands.pullFolder;
2015
+ mobilePullFolder = fileMovementCommands.mobilePullFolder;
2016
+
2017
+ /*--------+
2018
+ | MEMORY |
2019
+ +--------+*/
2020
+
2021
+ mobileSendMemoryWarning = memoryCommands.mobileSendMemoryWarning;
2022
+
2023
+ /*------+
2024
+ | FIND |
2025
+ +------+*/
2026
+
2027
+ findElOrEls = findCommands.findElOrEls;
2028
+ findNativeElementOrElements = findCommands.findNativeElementOrElements;
2029
+ doNativeFind = findCommands.doNativeFind;
2030
+ getFirstVisibleChild = findCommands.getFirstVisibleChild;
2031
+
2032
+ /*---------+
2033
+ | GENERAL |
2034
+ +---------+*/
2035
+
2036
+ active = generalCommands.active;
2037
+ background = appManagementCommands.background;
2038
+ touchId = generalCommands.touchId;
2039
+ toggleEnrollTouchId = generalCommands.toggleEnrollTouchId;
2040
+ getWindowSize = generalCommands.getWindowSize;
2041
+ getDeviceTime = generalCommands.getDeviceTime;
2042
+ mobileGetDeviceTime = generalCommands.mobileGetDeviceTime;
2043
+ getWindowRect = generalCommands.getWindowRect;
2044
+ getStrings = appStringsCommands.getStrings;
2045
+ removeApp = generalCommands.removeApp;
2046
+ launchApp = generalCommands.launchApp;
2047
+ closeApp = generalCommands.closeApp;
2048
+ // @ts-ignore Type mismatch: function type vs method signature
2049
+ setUrl = generalCommands.setUrl;
2050
+ getViewportRect = generalCommands.getViewportRect;
2051
+ getScreenInfo = generalCommands.getScreenInfo;
2052
+ getStatusBarHeight = generalCommands.getStatusBarHeight;
2053
+ getDevicePixelRatio = generalCommands.getDevicePixelRatio;
2054
+ mobilePressButton = generalCommands.mobilePressButton;
2055
+ mobileSiriCommand = generalCommands.mobileSiriCommand;
2056
+
2057
+ /*-------------+
2058
+ | GEOLOCATION |
2059
+ +-------------+*/
2060
+ mobileGetSimulatedLocation = geolocationCommands.mobileGetSimulatedLocation;
2061
+ mobileSetSimulatedLocation = geolocationCommands.mobileSetSimulatedLocation;
2062
+ mobileResetSimulatedLocation = geolocationCommands.mobileResetSimulatedLocation;
2063
+
2064
+ /*---------+
2065
+ | GESTURE |
2066
+ +---------+*/
2067
+ mobileShake = gestureCommands.mobileShake;
2068
+ click = gestureCommands.click;
2069
+ releaseActions = gestureCommands.releaseActions;
2070
+ performActions = gestureCommands.performActions;
2071
+ nativeClick = gestureCommands.nativeClick;
2072
+ mobileScrollToElement = gestureCommands.mobileScrollToElement;
2073
+ mobileScroll = gestureCommands.mobileScroll;
2074
+ mobileSwipe = gestureCommands.mobileSwipe;
2075
+ mobilePinch = gestureCommands.mobilePinch;
2076
+ mobileDoubleTap = gestureCommands.mobileDoubleTap;
2077
+ mobileTwoFingerTap = gestureCommands.mobileTwoFingerTap;
2078
+ mobileTouchAndHold = gestureCommands.mobileTouchAndHold;
2079
+ mobileTap = gestureCommands.mobileTap;
2080
+ mobileDragFromToForDuration = gestureCommands.mobileDragFromToForDuration;
2081
+ mobileDragFromToWithVelocity = gestureCommands.mobileDragFromToWithVelocity;
2082
+ mobileTapWithNumberOfTaps = gestureCommands.mobileTapWithNumberOfTaps;
2083
+ mobileForcePress = gestureCommands.mobileForcePress;
2084
+ mobileSelectPickerWheelValue = gestureCommands.mobileSelectPickerWheelValue;
2085
+ mobileRotateElement = gestureCommands.mobileRotateElement;
2086
+
2087
+ /*-------+
2088
+ | IOHID |
2089
+ +-------+*/
2090
+ mobilePerformIoHidEvent = iohidCommands.mobilePerformIoHidEvent;
2091
+
2092
+ /*-----------+
2093
+ | KEYCHAINS |
2094
+ +-----------+*/
2095
+
2096
+ mobileClearKeychains = keychainsCommands.mobileClearKeychains;
2097
+
2098
+ /*----------+
2099
+ | KEYBOARD |
2100
+ +----------+*/
2101
+
2102
+ hideKeyboard = keyboardCommands.hideKeyboard;
2103
+ mobileHideKeyboard = keyboardCommands.mobileHideKeyboard;
2104
+ isKeyboardShown = keyboardCommands.isKeyboardShown;
2105
+ mobileKeys = keyboardCommands.mobileKeys;
2106
+
2107
+ /*--------------+
2108
+ | LOCALIZATION |
2109
+ +--------------+*/
2110
+
2111
+ mobileConfigureLocalization = localizationCommands.mobileConfigureLocalization;
2112
+
2113
+ /*----------+
2114
+ | LOCATION |
2115
+ +----------+*/
2116
+
2117
+ getGeoLocation = locationCommands.getGeoLocation;
2118
+ setGeoLocation = locationCommands.setGeoLocation;
2119
+ mobileResetLocationService = locationCommands.mobileResetLocationService;
2120
+
2121
+ /*------+
2122
+ | LOCK |
2123
+ +------+*/
2124
+ lock = lockCommands.lock;
2125
+ unlock = lockCommands.unlock;
2126
+ isLocked = lockCommands.isLocked;
2127
+
2128
+ /*-----+
2129
+ | LOG |
2130
+ +-----+*/
2131
+
2132
+ extractLogs = logCommands.extractLogs;
2133
+ supportedLogTypes = logCommands.supportedLogTypes;
2134
+ startLogCapture = logCommands.startLogCapture;
2135
+ mobileStartLogsBroadcast = logCommands.mobileStartLogsBroadcast;
2136
+ mobileStopLogsBroadcast = logCommands.mobileStopLogsBroadcast;
2137
+
2138
+ /*------------+
2139
+ | NAVIGATION |
2140
+ +------------+*/
2141
+
2142
+ back = navigationCommands.back;
2143
+ forward = navigationCommands.forward;
2144
+ closeWindow = navigationCommands.closeWindow;
2145
+ nativeBack = navigationCommands.nativeBack;
2146
+ mobileDeepLink = navigationCommands.mobileDeepLink;
2147
+
2148
+ /*---------------+
2149
+ | NOTIFICATIONS |
2150
+ +---------------+*/
2151
+
2152
+ mobilePushNotification = notificationsCommands.mobilePushNotification;
2153
+ mobileExpectNotification = notificationsCommands.mobileExpectNotification;
2154
+
2155
+ /*------------+
2156
+ | PASTEBOARD |
2157
+ +------------+*/
2158
+
2159
+ mobileSetPasteboard = pasteboardCommands.mobileSetPasteboard;
2160
+ mobileGetPasteboard = pasteboardCommands.mobileGetPasteboard;
2161
+
2162
+ /*------+
2163
+ | PCAP |
2164
+ +------+*/
2165
+
2166
+ mobileStartPcap = pcapCommands.mobileStartPcap;
2167
+ mobileStopPcap = pcapCommands.mobileStopPcap;
2168
+
2169
+ /*-------------+
2170
+ | PERFORMANCE |
2171
+ +-------------+*/
2172
+ mobileStartPerfRecord = performanceCommands.mobileStartPerfRecord;
2173
+ mobileStopPerfRecord = performanceCommands.mobileStopPerfRecord;
2174
+
2175
+ /*-------------+
2176
+ | PERMISSIONS |
2177
+ +-------------+*/
2178
+
2179
+ mobileResetPermission = permissionsCommands.mobileResetPermission;
2180
+ mobileGetPermission = permissionsCommands.mobileGetPermission;
2181
+ mobileSetPermissions = permissionsCommands.mobileSetPermissions;
2182
+
2183
+ /*-------------+
2184
+ | PROXYHELPER |
2185
+ +-------------+*/
2186
+
2187
+ proxyCommand = proxyHelperCommands.proxyCommand;
2188
+
2189
+ /*-------------+
2190
+ | RECORDAUDIO |
2191
+ +-------------+*/
2192
+
2193
+ startAudioRecording = recordAudioCommands.startAudioRecording;
2194
+ stopAudioRecording = recordAudioCommands.stopAudioRecording;
2195
+
2196
+ /*--------------+
2197
+ | RECORDSCREEN |
2198
+ +--------------+*/
2199
+
2200
+ // Note: _recentScreenRecorder is a property, not a function, so it's handled internally in recordscreen.js
2201
+ startRecordingScreen = recordScreenCommands.startRecordingScreen;
2202
+ stopRecordingScreen = recordScreenCommands.stopRecordingScreen;
2203
+
2204
+ /*-------------+
2205
+ | SCREENSHOTS |
2206
+ +-------------+*/
2207
+ getScreenshot = screenshotCommands.getScreenshot;
2208
+ getElementScreenshot = screenshotCommands.getElementScreenshot;
2209
+ getViewportScreenshot = screenshotCommands.getViewportScreenshot;
2210
+
2211
+ /*--------+
2212
+ | SOURCE |
2213
+ +--------+*/
2214
+ getPageSource = sourceCommands.getPageSource;
2215
+ mobileGetSource = sourceCommands.mobileGetSource;
2216
+
2217
+ /*----------+
2218
+ | TIMEOUTS |
2219
+ +----------+*/
2220
+
2221
+ pageLoadTimeoutW3C = timeoutCommands.pageLoadTimeoutW3C;
2222
+ pageLoadTimeoutMJSONWP = timeoutCommands.pageLoadTimeoutMJSONWP;
2223
+ scriptTimeoutW3C = timeoutCommands.scriptTimeoutW3C;
2224
+ scriptTimeoutMJSONWP = timeoutCommands.scriptTimeoutMJSONWP;
2225
+ asyncScriptTimeout = timeoutCommands.asyncScriptTimeout;
2226
+ setPageLoadTimeout = timeoutCommands.setPageLoadTimeout;
2227
+ setAsyncScriptTimeout = timeoutCommands.setAsyncScriptTimeout;
2228
+
2229
+ /*-----+
2230
+ | WEB |
2231
+ +-----+*/
2232
+ // @ts-ignore Type mismatch: function type vs method signature
2233
+ setFrame = webCommands.setFrame;
2234
+ getCssProperty = webCommands.getCssProperty;
2235
+ submit = webCommands.submit;
2236
+ refresh = webCommands.refresh;
2237
+ getUrl = webCommands.getUrl;
2238
+ title = webCommands.title;
2239
+ getCookies = webCommands.getCookies;
2240
+ setCookie = webCommands.setCookie;
2241
+ deleteCookie = webCommands.deleteCookie;
2242
+ deleteCookies = webCommands.deleteCookies;
2243
+ cacheWebElement = webCommands.cacheWebElement;
2244
+ cacheWebElements = webCommands.cacheWebElements;
2245
+ executeAtom = webCommands.executeAtom;
2246
+ executeAtomAsync = webCommands.executeAtomAsync;
2247
+ getAtomsElement = webCommands.getAtomsElement;
2248
+ convertElementsForAtoms = webCommands.convertElementsForAtoms;
2249
+ getElementId = webCommands.getElementId;
2250
+ hasElementId = webCommands.hasElementId;
2251
+ findWebElementOrElements = webCommands.findWebElementOrElements;
2252
+ clickWebCoords = webCommands.clickWebCoords;
2253
+ getSafariIsIphone = webCommands.getSafariIsIphone;
2254
+ getSafariDeviceSize = webCommands.getSafariDeviceSize;
2255
+ getSafariIsNotched = webCommands.getSafariIsNotched;
2256
+ getExtraTranslateWebCoordsOffset = webCommands.getExtraTranslateWebCoordsOffset;
2257
+ getExtraNativeWebTapOffset = webCommands.getExtraNativeWebTapOffset;
2258
+ nativeWebTap = webCommands.nativeWebTap;
2259
+ translateWebCoords = webCommands.translateWebCoords;
2260
+ checkForAlert = webCommands.checkForAlert;
2261
+ waitForAtom = webCommands.waitForAtom;
2262
+ mobileWebNav = webCommands.mobileWebNav;
2263
+ getWdaLocalhostRoot = webCommands.getWdaLocalhostRoot;
2264
+ mobileCalibrateWebToRealCoordinatesTranslation = webCommands.mobileCalibrateWebToRealCoordinatesTranslation;
2265
+ mobileUpdateSafariPreferences = webCommands.mobileUpdateSafariPreferences;
2266
+
2267
+ /*--------+
2268
+ | XCTEST |
2269
+ +--------+*/
2270
+ mobileRunXCTest = xctestCommands.mobileRunXCTest;
2271
+ mobileInstallXCTestBundle = xctestCommands.mobileInstallXCTestBundle;
2272
+ mobileListXCTestBundles = xctestCommands.mobileListXCTestBundles;
2273
+ mobileListXCTestsInTestBundle = xctestCommands.mobileListXCTestsInTestBundle;
2274
+
2275
+ /*----------------------+
2276
+ | XCTEST SCREEN RECORD |
2277
+ +---------------------+*/
2278
+ mobileStartXctestScreenRecording = xctestRecordScreenCommands.mobileStartXctestScreenRecording;
2279
+ mobileGetXctestScreenRecordingInfo = xctestRecordScreenCommands.mobileGetXctestScreenRecordingInfo;
2280
+ mobileStopXctestScreenRecording = xctestRecordScreenCommands.mobileStopXctestScreenRecording;
2281
+ }
2282
+
2283
+ export default XCUITestDriver;
2284
+
2285
+ /**
2286
+ * @template {import('@appium/types').Constraints} C
2287
+ * @template [Ctx=string]
2288
+ * @typedef {import('@appium/types').ExternalDriver<C, Ctx>} ExternalDriver
2289
+ */
2290
+
2291
+ /**
2292
+ * @typedef {Pick<XCUITestDriverOpts, 'enforceAppInstall' | 'fullReset' | 'noReset' | 'bundleId' | 'app'>} AutInstallationStateOptions
2293
+ */
2294
+
2295
+ /**
2296
+ * @typedef {Object} AutInstallationState
2297
+ * @property {boolean} install - If the given app should install, or not need to install.
2298
+ * @property {boolean} skipUninstall - If the installed app should be uninstalled, or not.
2299
+ */
2300
+
2301
+ /**
2302
+ * @typedef {typeof desiredCapConstraints} XCUITestDriverConstraints
2303
+ * @typedef {import('@appium/types').DriverOpts<XCUITestDriverConstraints>} XCUITestDriverOpts
2304
+ * @typedef {import('./commands/types').FullContext} FullContext
2305
+ * @typedef {import('@limrun/appium-xcode').XcodeVersion} XcodeVersion
2306
+ * @typedef {import('@limrun/appium-ios-simulator').Simulator} Simulator
2307
+ */
2308
+
2309
+ /**
2310
+ * @typedef {Object} DriverLogs
2311
+ * @property {import('./device-log/ios-device-log').IOSDeviceLog|import('./device-log/ios-simulator-log').IOSSimulatorLog} [syslog]
2312
+ * @property {import('./device-log/ios-crash-log').IOSCrashLog} [crashlog]
2313
+ * @property {import('./device-log/safari-console-log').SafariConsoleLog} [safariConsole]
2314
+ * @property {import('./device-log/safari-network-log').SafariNetworkLog} [safariNetwork]
2315
+ * @property {import('./device-log/ios-performance-log').IOSPerformanceLog} [performance]
2316
+ */