@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
@@ -0,0 +1,710 @@
1
+ import _ from 'lodash';
2
+ import path from 'path';
3
+ import {plist, fs, util, tempDir, zip, timing} from 'appium/support';
4
+ import log from './logger.js';
5
+ import os from 'node:os';
6
+ import {exec} from 'teen_process';
7
+ import B from 'bluebird';
8
+ import {spawn} from 'node:child_process';
9
+ import assert from 'node:assert';
10
+ import { isTvOs } from './utils.js';
11
+
12
+ const STRINGSDICT_RESOURCE = '.stringsdict';
13
+ const STRINGS_RESOURCE = '.strings';
14
+ export const SAFARI_BUNDLE_ID = 'com.apple.mobilesafari';
15
+ export const APP_EXT = '.app';
16
+ export const IPA_EXT = '.ipa';
17
+ const ZIP_EXT = '.zip';
18
+ const SAFARI_OPTS_ALIASES_MAP = /** @type {const} */ ({
19
+ safariAllowPopups: [
20
+ ['WebKitJavaScriptCanOpenWindowsAutomatically', 'JavaScriptCanOpenWindowsAutomatically'],
21
+ (x) => Number(Boolean(x)),
22
+ ],
23
+ safariIgnoreFraudWarning: [['WarnAboutFraudulentWebsites'], (x) => Number(!x)],
24
+ safariOpenLinksInBackground: [['OpenLinksInBackground'], (x) => Number(Boolean(x))],
25
+ });
26
+ const MAX_ARCHIVE_SCAN_DEPTH = 1;
27
+ export const SUPPORTED_EXTENSIONS = [IPA_EXT, APP_EXT];
28
+ const MACOS_RESOURCE_FOLDER = '__MACOSX';
29
+ const SANITIZE_REPLACEMENT = '-';
30
+ const INTEL_ARCH = 'x86_64';
31
+
32
+ /**
33
+ * Verify whether the given application is compatible to the
34
+ * platform where it is going to be installed and tested.
35
+ *
36
+ * @this {XCUITestDriver}
37
+ * @returns {Promise<void>}
38
+ * @throws {Error} If bundle architecture does not match the expected device architecture.
39
+ */
40
+ export async function verifyApplicationPlatform() {
41
+ this.log.debug('Verifying application platform');
42
+
43
+ const supportedPlatforms = await this.appInfosCache.extractAppPlatforms(this.opts.app);
44
+ const isTvOS = isTvOs(this.opts.platformName);
45
+ const prefix = isTvOS ? 'AppleTV' : 'iPhone';
46
+ const suffix = this.isSimulator() ? 'Simulator' : 'OS';
47
+ const dstPlatform = `${prefix}${suffix}`;
48
+ if (!supportedPlatforms.includes(dstPlatform)) {
49
+ throw new Error(
50
+ `${
51
+ this.isSimulator() ? 'Simulator' : 'Real device'
52
+ } architecture is not supported by the ${this.opts.bundleId} application. ` +
53
+ `Make sure the correct deployment target has been selected for its compilation in Xcode.`,
54
+ );
55
+ }
56
+ if (this.isRealDevice()) {
57
+ return;
58
+ }
59
+
60
+ const executablePath = path.resolve(
61
+ this.opts.app,
62
+ await this.appInfosCache.extractExecutableName(this.opts.app)
63
+ );
64
+ const [resFile, resUname] = await B.all([
65
+ exec('lipo', ['-info', executablePath]),
66
+ exec('uname', ['-m']),
67
+ ]);
68
+ const bundleExecutableInfo = _.trim(resFile.stdout);
69
+ this.log.debug(bundleExecutableInfo);
70
+ const processArch = _.trim(resUname.stdout);
71
+ this.log.debug(`Current process architecture: ${processArch}`);
72
+ const isAppleSiliconCpu = isAppleSilicon();
73
+ this.log.debug(`Is Apple Silicon CPU: ${isAppleSiliconCpu}`);
74
+ if (isAppleSiliconCpu && processArch === INTEL_ARCH) {
75
+ this.log.warn(
76
+ `It looks like the Appium server process is running under Rosetta emulation. ` +
77
+ `This might lead to various performance/compatibility issues while running tests on Simulator. ` +
78
+ `Consider using binaries compiled natively for the ARM64 architecture to run Appium server ` +
79
+ `with this driver.`
80
+ );
81
+ }
82
+ if (_.includes(bundleExecutableInfo, processArch)) {
83
+ return;
84
+ }
85
+ const hasRosetta = isAppleSiliconCpu && await isRosettaInstalled();
86
+ const isIntelApp = _.includes(bundleExecutableInfo, INTEL_ARCH);
87
+ // We cannot run Simulator builds compiled for arm64 on Intel machines
88
+ // Rosetta allows only to run Intel ones on arm64
89
+ if (
90
+ (isIntelApp && (!isAppleSiliconCpu || hasRosetta)) || (!isIntelApp && isAppleSiliconCpu)
91
+ ) {
92
+ return;
93
+ }
94
+ const advice = isIntelApp && isAppleSiliconCpu && !hasRosetta
95
+ ? `Please install Rosetta and try again.`
96
+ : `Please rebuild your application to support the ${processArch} platform.`;
97
+ throw new Error(
98
+ `The ${this.opts.bundleId} application does not support the ${processArch} Simulator ` +
99
+ `architecture:\n${bundleExecutableInfo}\n\n${advice}`
100
+ );
101
+ }
102
+
103
+ /**
104
+ *
105
+ * @param {string} resourcePath
106
+ * @returns {Promise<import('@appium/types').StringRecord>}
107
+ */
108
+ async function readResource(resourcePath) {
109
+ const data = await plist.parsePlistFile(resourcePath);
110
+ const result = {};
111
+ for (const [key, value] of _.toPairs(data)) {
112
+ result[key] = _.isString(value) ? value : JSON.stringify(value);
113
+ }
114
+ return result;
115
+ }
116
+
117
+ /**
118
+ * @typedef {Object} LocalizableStringsOptions
119
+ * @property {string} [app]
120
+ * @property {string} [language='en']
121
+ * @property {string} [localizableStringsDir]
122
+ * @property {string} [stringFile]
123
+ * @property {boolean} [strictMode]
124
+ */
125
+
126
+ /**
127
+ * Extracts string resources from an app
128
+ *
129
+ * @this {XCUITestDriver}
130
+ * @param {LocalizableStringsOptions} opts
131
+ * @returns {Promise<import('@appium/types').StringRecord>}
132
+ */
133
+ export async function parseLocalizableStrings(opts = {}) {
134
+ const {app, language = 'en', localizableStringsDir, stringFile, strictMode} = opts;
135
+ if (!app) {
136
+ const message = `Strings extraction is not supported if 'app' capability is not set`;
137
+ if (strictMode) {
138
+ throw new Error(message);
139
+ }
140
+ this.log.info(message);
141
+ return {};
142
+ }
143
+
144
+ let bundleRoot = app;
145
+ const isArchive = (await fs.stat(app)).isFile();
146
+ let tmpRoot;
147
+ try {
148
+ if (isArchive) {
149
+ tmpRoot = await tempDir.openDir();
150
+ this.log.info(`Extracting '${app}' into a temporary location to parse its resources`);
151
+ await zip.extractAllTo(app, tmpRoot);
152
+ const relativeBundleRoot = /** @type {string} */ (_.first(await findApps(tmpRoot, [APP_EXT])));
153
+ this.log.info(`Selecting '${relativeBundleRoot}'`);
154
+ bundleRoot = path.join(tmpRoot, relativeBundleRoot);
155
+ }
156
+
157
+ /** @type {string|undefined} */
158
+ let lprojRoot;
159
+ for (const subfolder of [`${language}.lproj`, localizableStringsDir, ''].filter(_.isString)) {
160
+ lprojRoot = path.resolve(bundleRoot, /** @type {string} */ (subfolder));
161
+ if (await fs.exists(lprojRoot)) {
162
+ break;
163
+ }
164
+ const message = `No '${lprojRoot}' resources folder has been found`;
165
+ if (strictMode) {
166
+ throw new Error(message);
167
+ }
168
+ this.log.debug(message);
169
+ }
170
+ if (!lprojRoot) {
171
+ return {};
172
+ }
173
+
174
+ this.log.info(`Retrieving resource strings from '${lprojRoot}'`);
175
+ const resourcePaths = [];
176
+ if (stringFile) {
177
+ const dstPath = path.resolve(/** @type {string} */ (lprojRoot), stringFile);
178
+ if (await fs.exists(dstPath)) {
179
+ resourcePaths.push(dstPath);
180
+ } else {
181
+ const message = `No '${dstPath}' resource file has been found for '${app}'`;
182
+ if (strictMode) {
183
+ throw new Error(message);
184
+ }
185
+ this.log.info(message);
186
+ }
187
+ }
188
+
189
+ if (_.isEmpty(resourcePaths) && (await fs.exists(lprojRoot))) {
190
+ const resourceFiles = (await fs.readdir(lprojRoot))
191
+ .filter((name) => _.some([STRINGS_RESOURCE, STRINGSDICT_RESOURCE], (x) => name.endsWith(x)))
192
+ .map((name) => path.resolve(lprojRoot, name));
193
+ resourcePaths.push(...resourceFiles);
194
+ }
195
+ this.log.info(`Got ${util.pluralize('resource file', resourcePaths.length, true)} in '${lprojRoot}'`);
196
+
197
+ if (_.isEmpty(resourcePaths)) {
198
+ return {};
199
+ }
200
+
201
+ const resultStrings = {};
202
+ const toAbsolutePath = (/** @type {string} */ p) => path.isAbsolute(p) ? p : path.resolve(process.cwd(), p);
203
+ for (const resourcePath of resourcePaths) {
204
+ if (!util.isSubPath(toAbsolutePath(resourcePath), toAbsolutePath(bundleRoot))) {
205
+ // security precaution
206
+ throw new Error(`'${resourcePath}' is expected to be located under '${bundleRoot}'`);
207
+ }
208
+ try {
209
+ const data = await readResource(resourcePath);
210
+ this.log.debug(`Parsed ${util.pluralize('string', _.keys(data).length, true)} from '${resourcePath}'`);
211
+ _.merge(resultStrings, data);
212
+ } catch (e) {
213
+ this.log.warn(`Cannot parse '${resourcePath}' resource. Original error: ${e.message}`);
214
+ }
215
+ }
216
+
217
+ this.log.info(`Retrieved ${util.pluralize('string', _.keys(resultStrings).length, true)} from '${lprojRoot}'`);
218
+ return resultStrings;
219
+ } finally {
220
+ if (tmpRoot) {
221
+ await fs.rimraf(tmpRoot);
222
+ }
223
+ }
224
+ }
225
+
226
+ /**
227
+ * Check whether the given path on the file system points to the .app bundle root
228
+ *
229
+ * @param {string} appPath Possible .app bundle root
230
+ * @returns {Promise<boolean>} Whether the given path points to an .app bundle
231
+ */
232
+ async function isAppBundle(appPath) {
233
+ return (
234
+ _.endsWith(_.toLower(appPath), APP_EXT) &&
235
+ (await fs.stat(appPath)).isDirectory() &&
236
+ (await fs.exists(path.join(appPath, 'Info.plist')))
237
+ );
238
+ }
239
+
240
+ /**
241
+ * Check whether the given path on the file system points to the .ipa file
242
+ *
243
+ * @param {string} appPath Possible .ipa file
244
+ * @returns {Promise<boolean>} Whether the given path points to an .ipa bundle
245
+ */
246
+ async function isIpaBundle(appPath) {
247
+ return _.endsWith(_.toLower(appPath), IPA_EXT) && (await fs.stat(appPath)).isFile();
248
+ }
249
+
250
+ /**
251
+ * @typedef {Object} UnzipInfo
252
+ * @property {string} rootDir
253
+ * @property {number} archiveSize
254
+ */
255
+
256
+ /**
257
+ * Unzips a ZIP archive on the local file system.
258
+ *
259
+ * @param {string} archivePath Full path to a .zip archive
260
+ * @returns {Promise<UnzipInfo>} temporary folder root where the archive has been extracted
261
+ */
262
+ export async function unzipFile(archivePath) {
263
+ const useSystemUnzipEnv = process.env.APPIUM_PREFER_SYSTEM_UNZIP;
264
+ const useSystemUnzip =
265
+ _.isEmpty(useSystemUnzipEnv) || !['0', 'false'].includes(_.toLower(useSystemUnzipEnv));
266
+ const tmpRoot = await tempDir.openDir();
267
+ try {
268
+ await zip.extractAllTo(archivePath, tmpRoot, {
269
+ useSystemUnzip,
270
+ // https://github.com/appium/appium/issues/14100
271
+ fileNamesEncoding: 'utf8',
272
+ });
273
+ } catch (e) {
274
+ await fs.rimraf(tmpRoot);
275
+ throw e;
276
+ }
277
+ return {
278
+ rootDir: tmpRoot,
279
+ archiveSize: (await fs.stat(archivePath)).size,
280
+ };
281
+ }
282
+
283
+ /**
284
+ * Unzips a ZIP archive from a stream.
285
+ * Uses bdstar tool for this purpose.
286
+ * This allows to optimize the time needed to prepare the app under test
287
+ * to MAX(download, unzip) instead of SUM(download, unzip)
288
+ *
289
+ * @param {import('node:stream').Readable} zipStream
290
+ * @returns {Promise<UnzipInfo>}
291
+ */
292
+ export async function unzipStream(zipStream) {
293
+ const tmpRoot = await tempDir.openDir();
294
+ const bsdtarProcess = spawn(await fs.which('bsdtar'), [
295
+ '-x',
296
+ '--exclude', MACOS_RESOURCE_FOLDER,
297
+ '--exclude', `${MACOS_RESOURCE_FOLDER}/*`,
298
+ '-',
299
+ ], {
300
+ cwd: tmpRoot,
301
+ });
302
+ let archiveSize = 0;
303
+ bsdtarProcess.stderr.on('data', (chunk) => {
304
+ const stderr = chunk.toString();
305
+ if (_.trim(stderr)) {
306
+ log.warn(stderr);
307
+ }
308
+ });
309
+ zipStream.on('data', (chunk) => {
310
+ archiveSize += _.size(chunk);
311
+ });
312
+ zipStream.pipe(bsdtarProcess.stdin);
313
+ try {
314
+ await new B((resolve, reject) => {
315
+ zipStream.once('error', reject);
316
+ bsdtarProcess.once('exit', (code, signal) => {
317
+ zipStream.unpipe(bsdtarProcess.stdin);
318
+ log.debug(`bsdtar process exited with code ${code}, signal ${signal}`);
319
+ if (code === 0) {
320
+ resolve();
321
+ } else {
322
+ reject(new Error('Is it a valid ZIP archive?'));
323
+ }
324
+ });
325
+ bsdtarProcess.once('error', (e) => {
326
+ zipStream.unpipe(bsdtarProcess.stdin);
327
+ reject(e);
328
+ });
329
+ });
330
+ } catch (err) {
331
+ bsdtarProcess.kill(9);
332
+ await fs.rimraf(tmpRoot);
333
+ throw new Error(`The response data cannot be unzipped: ${err.message}`);
334
+ } finally {
335
+ bsdtarProcess.removeAllListeners();
336
+ zipStream.removeAllListeners();
337
+ }
338
+ return {
339
+ rootDir: tmpRoot,
340
+ archiveSize,
341
+ };
342
+ }
343
+
344
+ /**
345
+ * Used to parse the file name value from response headers
346
+ *
347
+ * @param {import('@appium/types').HTTPHeaders} headers
348
+ * @returns {string?}
349
+ */
350
+ function parseFileName(headers) {
351
+ const contentDisposition = headers['content-disposition'];
352
+ if (!_.isString(contentDisposition)) {
353
+ return null;
354
+ }
355
+
356
+ if (/^attachment/i.test(/** @type {string} */ (contentDisposition))) {
357
+ const match = /filename="([^"]+)/i.exec(/** @type {string} */ (contentDisposition));
358
+ if (match) {
359
+ return fs.sanitizeName(match[1], {replacement: SANITIZE_REPLACEMENT});
360
+ }
361
+ }
362
+ return null;
363
+ }
364
+
365
+ /**
366
+ * Downloads and verifies remote applications for real devices
367
+ *
368
+ * @this {XCUITestDriver}
369
+ * @param {import('node:stream').Readable} stream
370
+ * @param {import('@appium/types').HTTPHeaders} headers
371
+ * @returns {Promise<string>}
372
+ */
373
+ async function downloadIpa(stream, headers) {
374
+ const timer = new timing.Timer().start();
375
+
376
+ const logPerformance = (/** @type {string} */ dstPath, /** @type {number} */ fileSize, /** @type {string} */ action) => {
377
+ const secondsElapsed = timer.getDuration().asSeconds;
378
+ this.log.info(
379
+ `The remote file (${util.toReadableSizeString(fileSize)}) ` +
380
+ `has been ${action} to '${dstPath}' in ${secondsElapsed.toFixed(3)}s`
381
+ );
382
+ if (secondsElapsed >= 1) {
383
+ const bytesPerSec = Math.floor(fileSize / secondsElapsed);
384
+ this.log.debug(`Approximate speed: ${util.toReadableSizeString(bytesPerSec)}/s`);
385
+ }
386
+ };
387
+
388
+ // Check if the file to be downloaded is a .zip rather than .ipa
389
+ const fileName = parseFileName(headers) ?? `appium-app-${new Date().getTime()}${IPA_EXT}`;
390
+ if (fileName.toLowerCase().endsWith(ZIP_EXT)) {
391
+ const {rootDir, archiveSize} = await unzipStream(stream);
392
+ logPerformance(rootDir, archiveSize, 'downloaded and unzipped');
393
+ try {
394
+ const matchedPaths = await findApps(rootDir, [IPA_EXT]);
395
+ if (!_.isEmpty(matchedPaths)) {
396
+ this.log.debug(
397
+ `Found ${util.pluralize(`${IPA_EXT} application`, matchedPaths.length, true)} in ` +
398
+ `'${path.basename(rootDir)}': ${matchedPaths}`
399
+ );
400
+ }
401
+ for (const matchedPath of matchedPaths) {
402
+ try {
403
+ await this.appInfosCache.put(matchedPath);
404
+ } catch (e) {
405
+ this.log.info(e.message);
406
+ continue;
407
+ }
408
+ this.log.debug(`Selecting the application at '${matchedPath}'`);
409
+ const isolatedPath = path.join(await tempDir.openDir(), path.basename(matchedPath));
410
+ await fs.mv(matchedPath, isolatedPath);
411
+ return isolatedPath;
412
+ }
413
+ throw new Error(`The remote archive does not contain any valid ${IPA_EXT} applications`);
414
+ } finally {
415
+ await fs.rimraf(rootDir);
416
+ }
417
+ }
418
+
419
+ const ipaPath = await tempDir.path({
420
+ prefix: fileName,
421
+ suffix: fileName.toLowerCase().endsWith(IPA_EXT) ? '' : IPA_EXT,
422
+ });
423
+ try {
424
+ const writer = fs.createWriteStream(ipaPath);
425
+ stream.pipe(writer);
426
+
427
+ await new B((resolve, reject) => {
428
+ stream.once('error', reject);
429
+ writer.once('finish', resolve);
430
+ writer.once('error', (e) => {
431
+ stream.unpipe(writer);
432
+ reject(e);
433
+ });
434
+ });
435
+ } catch (err) {
436
+ throw new Error(`Cannot fetch the remote file: ${err.message}`);
437
+ }
438
+ const {size} = await fs.stat(ipaPath);
439
+ logPerformance(ipaPath, size, 'downloaded');
440
+ try {
441
+ await this.appInfosCache.put(ipaPath);
442
+ } catch (e) {
443
+ await fs.rimraf(ipaPath);
444
+ throw e;
445
+ }
446
+ return ipaPath;
447
+ }
448
+
449
+ /**
450
+ * Looks for items with given extensions in the given folder
451
+ *
452
+ * @param {string} appPath Full path to an app bundle
453
+ * @param {Array<string>} appExtensions List of matching item extensions
454
+ * @returns {Promise<string[]>} List of relative paths to matched items
455
+ */
456
+ async function findApps(appPath, appExtensions) {
457
+ const globPattern = `**/*.+(${appExtensions.map((ext) => ext.replace(/^\./, '')).join('|')})`;
458
+ const sortedBundleItems = (
459
+ await fs.glob(globPattern, {
460
+ cwd: appPath,
461
+ })
462
+ ).sort((a, b) => a.split(path.sep).length - b.split(path.sep).length);
463
+ return sortedBundleItems;
464
+ }
465
+
466
+ /**
467
+ * Moves the application bundle to a newly created temporary folder
468
+ *
469
+ * @param {string} appPath Full path to the .app or .ipa bundle
470
+ * @returns {Promise<string>} The new path to the app bundle.
471
+ * The name of the app bundle remains the same
472
+ */
473
+ async function isolateApp(appPath) {
474
+ const appFileName = path.basename(appPath);
475
+ if ((await fs.stat(appPath)).isFile()) {
476
+ const isolatedPath = await tempDir.path({
477
+ prefix: appFileName,
478
+ suffix: '',
479
+ });
480
+ await fs.mv(appPath, isolatedPath, {mkdirp: true});
481
+ return isolatedPath;
482
+ }
483
+
484
+ const tmpRoot = await tempDir.openDir();
485
+ const isolatedRoot = path.join(tmpRoot, appFileName);
486
+ await fs.mv(appPath, isolatedRoot, {mkdirp: true});
487
+ return isolatedRoot;
488
+ }
489
+
490
+ /**
491
+ * Builds Safari preferences object based on the given session capabilities
492
+ *
493
+ * @param {import('./driver').XCUITestDriverOpts} opts
494
+ * @return {Promise<import('@appium/types').StringRecord>}
495
+ */
496
+ export function buildSafariPreferences(opts) {
497
+ const safariSettings = _.cloneDeep(opts?.safariGlobalPreferences ?? {});
498
+
499
+ for (const [name, [aliases, valueConverter]] of _.toPairs(SAFARI_OPTS_ALIASES_MAP)) {
500
+ if (!_.has(opts, name)) {
501
+ continue;
502
+ }
503
+
504
+ for (const alias of aliases) {
505
+ safariSettings[alias] = valueConverter(opts[name]);
506
+ }
507
+ }
508
+ return safariSettings;
509
+ }
510
+
511
+ /**
512
+ * Unzip the given archive and find a matching .app bundle in it
513
+ *
514
+ * @this {XCUITestDriver}
515
+ * @param {string|import('node:stream').Readable} appPathOrZipStream The path to the archive.
516
+ * @param {number} depth [0] the current nesting depth. App bundles whose nesting level
517
+ * is greater than 1 are not supported.
518
+ * @returns {Promise<string>} Full path to the first matching .app bundle..
519
+ * @throws If no matching .app bundles were found in the provided archive.
520
+ */
521
+ async function unzipApp(appPathOrZipStream, depth = 0) {
522
+ const errMsg = `The archive did not have any matching ${APP_EXT} or ${IPA_EXT} ` +
523
+ `bundles. Please make sure the provided package is valid and contains at least one matching ` +
524
+ `application bundle which is not nested.`;
525
+ if (depth > MAX_ARCHIVE_SCAN_DEPTH) {
526
+ throw new Error(errMsg);
527
+ }
528
+
529
+ const timer = new timing.Timer().start();
530
+ /** @type {string} */
531
+ let rootDir;
532
+ /** @type {number} */
533
+ let archiveSize;
534
+ try {
535
+ if (_.isString(appPathOrZipStream)) {
536
+ ({rootDir, archiveSize} = await unzipFile(/** @type {string} */ (appPathOrZipStream)));
537
+ } else {
538
+ if (depth > 0) {
539
+ assert.fail('Streaming unzip cannot be invoked for nested archive items');
540
+ }
541
+ ({rootDir, archiveSize} = await unzipStream(
542
+ /** @type {import('node:stream').Readable} */ (appPathOrZipStream))
543
+ );
544
+ }
545
+ } catch (e) {
546
+ this.log.debug(e.stack);
547
+ throw new Error(
548
+ `Cannot prepare the application for testing. Original error: ${e.message}`
549
+ );
550
+ }
551
+ const secondsElapsed = timer.getDuration().asSeconds;
552
+ this.log.info(
553
+ `The file (${util.toReadableSizeString(archiveSize)}) ` +
554
+ `has been ${_.isString(appPathOrZipStream) ? 'extracted' : 'downloaded and extracted'} ` +
555
+ `to '${rootDir}' in ${secondsElapsed.toFixed(3)}s`
556
+ );
557
+ // it does not make much sense to approximate the speed for short downloads
558
+ if (secondsElapsed >= 1) {
559
+ const bytesPerSec = Math.floor(archiveSize / secondsElapsed);
560
+ this.log.debug(`Approximate decompression speed: ${util.toReadableSizeString(bytesPerSec)}/s`);
561
+ }
562
+
563
+ const isCompatibleWithCurrentPlatform = async (/** @type {string} */ appPath) => {
564
+ let platforms;
565
+ try {
566
+ platforms = await this.appInfosCache.extractAppPlatforms(appPath);
567
+ } catch (e) {
568
+ this.log.info(e.message);
569
+ return false;
570
+ }
571
+ if (this.isSimulator() && !platforms.some((p) => _.includes(p, 'Simulator'))) {
572
+ this.log.info(
573
+ `'${appPath}' does not have Simulator devices in the list of supported platforms ` +
574
+ `(${platforms.join(',')}). Skipping it`
575
+ );
576
+ return false;
577
+ }
578
+ if (this.isRealDevice() && !platforms.some((p) => _.includes(p, 'OS'))) {
579
+ this.log.info(
580
+ `'${appPath}' does not have real devices in the list of supported platforms ` +
581
+ `(${platforms.join(',')}). Skipping it`
582
+ );
583
+ return false;
584
+ }
585
+ return true;
586
+ };
587
+
588
+ const matchedPaths = await findApps(rootDir, SUPPORTED_EXTENSIONS);
589
+ if (_.isEmpty(matchedPaths)) {
590
+ this.log.debug(`'${path.basename(rootDir)}' has no bundles`);
591
+ } else {
592
+ this.log.debug(
593
+ `Found ${util.pluralize('bundle', matchedPaths.length, true)} in ` +
594
+ `'${path.basename(rootDir)}': ${matchedPaths}`,
595
+ );
596
+ }
597
+ try {
598
+ for (const matchedPath of matchedPaths) {
599
+ const fullPath = path.join(rootDir, matchedPath);
600
+ if (
601
+ (await isAppBundle(fullPath) || (this.isRealDevice() && await isIpaBundle(fullPath)))
602
+ && await isCompatibleWithCurrentPlatform(fullPath)
603
+ ) {
604
+ this.log.debug(`Selecting the application at '${matchedPath}'`);
605
+ return await isolateApp(fullPath);
606
+ }
607
+ }
608
+ } finally {
609
+ await fs.rimraf(rootDir);
610
+ }
611
+ throw new Error(errMsg);
612
+ }
613
+
614
+ /**
615
+ * The callback invoked by configureApp helper
616
+ * when it is necessary to download the remote application.
617
+ * We assume the remote file could be anythingm, but only
618
+ * .zip and .ipa formats are supported.
619
+ * A .zip archive can contain one or more
620
+ *
621
+ * @this {XCUITestDriver}
622
+ * @param {import('@appium/types').DownloadAppOptions} opts
623
+ * @returns {Promise<string>}
624
+ */
625
+ export async function onDownloadApp({stream, headers}) {
626
+ return this.isRealDevice()
627
+ ? await downloadIpa.bind(this)(stream, headers)
628
+ : await unzipApp.bind(this)(stream);
629
+ }
630
+
631
+ /**
632
+ * @this {XCUITestDriver}
633
+ * @param {import('@appium/types').PostProcessOptions} opts
634
+ * @returns {Promise<import('@appium/types').PostProcessResult|false>}
635
+ */
636
+ export async function onPostConfigureApp({cachedAppInfo, isUrl, appPath}) {
637
+ // Pick the previously cached entry if its integrity has been preserved
638
+ /** @type {import('@appium/types').CachedAppInfo|undefined} */
639
+ const appInfo = _.isPlainObject(cachedAppInfo) ? cachedAppInfo : undefined;
640
+ const cachedPath = appInfo ? /** @type {string} */ (appInfo.fullPath) : undefined;
641
+
642
+ const shouldUseCachedApp = async () => {
643
+ if (!appInfo || !cachedPath || !await fs.exists(cachedPath)) {
644
+ return false;
645
+ }
646
+
647
+ const isCachedPathAFile = (await fs.stat(cachedPath)).isFile();
648
+ if (isCachedPathAFile) {
649
+ return await fs.hash(cachedPath) === /** @type {any} */ (appInfo.integrity)?.file;
650
+ }
651
+ // If the cached path is a folder then it is expected to be previously extracted from
652
+ // an archive located under appPath whose hash is stored as `cachedAppInfo.packageHash`
653
+ if (
654
+ !isCachedPathAFile
655
+ && cachedAppInfo?.packageHash
656
+ && await fs.exists(/** @type {string} */ (appPath))
657
+ && (await fs.stat(/** @type {string} */ (appPath))).isFile()
658
+ && cachedAppInfo.packageHash === await fs.hash(/** @type {string} */ (appPath))
659
+ ) {
660
+ /** @type {number|undefined} */
661
+ const nestedItemsCountInCache = /** @type {any} */ (appInfo.integrity)?.folder;
662
+ if (nestedItemsCountInCache !== undefined) {
663
+ return (await fs.glob('**/*', {cwd: cachedPath})).length >= nestedItemsCountInCache;
664
+ }
665
+ }
666
+
667
+ return false;
668
+ };
669
+
670
+ if (await shouldUseCachedApp()) {
671
+ this.log.info(`Using '${cachedPath}' which was cached from '${appPath}'`);
672
+ return {appPath: /** @type {string} */ (cachedPath)};
673
+ }
674
+
675
+ const isLocalIpa = await isIpaBundle(/** @type {string} */(appPath));
676
+ const isLocalApp = !isLocalIpa && await isAppBundle(/** @type {string} */(appPath));
677
+ const isPackageReadyForInstall = isLocalApp || (this.isRealDevice() && isLocalIpa);
678
+ if (isPackageReadyForInstall) {
679
+ await this.appInfosCache.put(/** @type {string} */(appPath));
680
+ }
681
+ // Only local .app bundles (real device/Simulator)
682
+ // and .ipa packages for real devices should not be cached
683
+ if (!isUrl && isPackageReadyForInstall) {
684
+ return false;
685
+ }
686
+ // Cache the app while unpacking the bundle if necessary
687
+ return {
688
+ appPath: isPackageReadyForInstall
689
+ ? appPath
690
+ : await unzipApp.bind(this)(/** @type {string} */(appPath))
691
+ };
692
+ }
693
+
694
+ /**
695
+ * @returns {Promise<boolean>}
696
+ */
697
+ async function isRosettaInstalled() {
698
+ return await fs.exists('/Library/Apple/usr/share/rosetta/rosetta');
699
+ }
700
+
701
+ /**
702
+ * @returns {boolean}
703
+ */
704
+ function isAppleSilicon() {
705
+ return os.cpus()[0].model.includes('Apple');
706
+ }
707
+
708
+ /**
709
+ * @typedef {import('./driver').XCUITestDriver} XCUITestDriver
710
+ */