@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.
- package/CHANGELOG.md +2600 -0
- package/LICENSE +201 -0
- package/README.md +55 -0
- package/build/index.d.ts +5 -0
- package/build/index.js +41 -0
- package/build/lib/app-infos-cache.d.ts +62 -0
- package/build/lib/app-infos-cache.d.ts.map +1 -0
- package/build/lib/app-infos-cache.js +180 -0
- package/build/lib/app-infos-cache.js.map +1 -0
- package/build/lib/app-utils.d.ts +89 -0
- package/build/lib/app-utils.d.ts.map +1 -0
- package/build/lib/app-utils.js +657 -0
- package/build/lib/app-utils.js.map +1 -0
- package/build/lib/commands/active-app-info.d.ts +9 -0
- package/build/lib/commands/active-app-info.d.ts.map +1 -0
- package/build/lib/commands/active-app-info.js +14 -0
- package/build/lib/commands/active-app-info.js.map +1 -0
- package/build/lib/commands/advanced-battery-types.d.ts +444 -0
- package/build/lib/commands/advanced-battery-types.d.ts.map +1 -0
- package/build/lib/commands/advanced-battery-types.js +8 -0
- package/build/lib/commands/advanced-battery-types.js.map +1 -0
- package/build/lib/commands/alert.d.ts +45 -0
- package/build/lib/commands/alert.d.ts.map +1 -0
- package/build/lib/commands/alert.js +87 -0
- package/build/lib/commands/alert.js.map +1 -0
- package/build/lib/commands/app-management.d.ts +153 -0
- package/build/lib/commands/app-management.d.ts.map +1 -0
- package/build/lib/commands/app-management.js +323 -0
- package/build/lib/commands/app-management.js.map +1 -0
- package/build/lib/commands/app-strings.d.ts +16 -0
- package/build/lib/commands/app-strings.d.ts.map +1 -0
- package/build/lib/commands/app-strings.js +30 -0
- package/build/lib/commands/app-strings.js.map +1 -0
- package/build/lib/commands/appearance.d.ts +22 -0
- package/build/lib/commands/appearance.d.ts.map +1 -0
- package/build/lib/commands/appearance.js +74 -0
- package/build/lib/commands/appearance.js.map +1 -0
- package/build/lib/commands/audit.d.ts +43 -0
- package/build/lib/commands/audit.d.ts.map +1 -0
- package/build/lib/commands/audit.js +31 -0
- package/build/lib/commands/audit.js.map +1 -0
- package/build/lib/commands/battery.d.ts +13 -0
- package/build/lib/commands/battery.d.ts.map +1 -0
- package/build/lib/commands/battery.js +49 -0
- package/build/lib/commands/battery.js.map +1 -0
- package/build/lib/commands/bidi/constants.d.ts +6 -0
- package/build/lib/commands/bidi/constants.d.ts.map +1 -0
- package/build/lib/commands/bidi/constants.js +10 -0
- package/build/lib/commands/bidi/constants.js.map +1 -0
- package/build/lib/commands/bidi/models.d.ts +9 -0
- package/build/lib/commands/bidi/models.d.ts.map +1 -0
- package/build/lib/commands/bidi/models.js +54 -0
- package/build/lib/commands/bidi/models.js.map +1 -0
- package/build/lib/commands/bidi/types.d.ts +26 -0
- package/build/lib/commands/bidi/types.d.ts.map +1 -0
- package/build/lib/commands/bidi/types.js +4 -0
- package/build/lib/commands/bidi/types.js.map +1 -0
- package/build/lib/commands/biometric.d.ts +32 -0
- package/build/lib/commands/biometric.d.ts.map +1 -0
- package/build/lib/commands/biometric.js +54 -0
- package/build/lib/commands/biometric.js.map +1 -0
- package/build/lib/commands/certificate.d.ts +50 -0
- package/build/lib/commands/certificate.d.ts.map +1 -0
- package/build/lib/commands/certificate.js +454 -0
- package/build/lib/commands/certificate.js.map +1 -0
- package/build/lib/commands/clipboard.d.ts +21 -0
- package/build/lib/commands/clipboard.d.ts.map +1 -0
- package/build/lib/commands/clipboard.js +36 -0
- package/build/lib/commands/clipboard.js.map +1 -0
- package/build/lib/commands/condition.d.ts +102 -0
- package/build/lib/commands/condition.d.ts.map +1 -0
- package/build/lib/commands/condition.js +146 -0
- package/build/lib/commands/condition.js.map +1 -0
- package/build/lib/commands/content-size.d.ts +30 -0
- package/build/lib/commands/content-size.d.ts.map +1 -0
- package/build/lib/commands/content-size.js +67 -0
- package/build/lib/commands/content-size.js.map +1 -0
- package/build/lib/commands/context.d.ts +191 -0
- package/build/lib/commands/context.d.ts.map +1 -0
- package/build/lib/commands/context.js +625 -0
- package/build/lib/commands/context.js.map +1 -0
- package/build/lib/commands/deviceInfo.d.ts +12 -0
- package/build/lib/commands/deviceInfo.d.ts.map +1 -0
- package/build/lib/commands/deviceInfo.js +25 -0
- package/build/lib/commands/deviceInfo.js.map +1 -0
- package/build/lib/commands/element.d.ts +108 -0
- package/build/lib/commands/element.d.ts.map +1 -0
- package/build/lib/commands/element.js +395 -0
- package/build/lib/commands/element.js.map +1 -0
- package/build/lib/commands/enum.d.ts +105 -0
- package/build/lib/commands/enum.d.ts.map +1 -0
- package/build/lib/commands/enum.js +113 -0
- package/build/lib/commands/enum.js.map +1 -0
- package/build/lib/commands/execute.d.ts +33 -0
- package/build/lib/commands/execute.d.ts.map +1 -0
- package/build/lib/commands/execute.js +142 -0
- package/build/lib/commands/execute.js.map +1 -0
- package/build/lib/commands/file-movement.d.ts +90 -0
- package/build/lib/commands/file-movement.d.ts.map +1 -0
- package/build/lib/commands/file-movement.js +477 -0
- package/build/lib/commands/file-movement.js.map +1 -0
- package/build/lib/commands/find.d.ts +21 -0
- package/build/lib/commands/find.d.ts.map +1 -0
- package/build/lib/commands/find.js +199 -0
- package/build/lib/commands/find.js.map +1 -0
- package/build/lib/commands/general.d.ts +137 -0
- package/build/lib/commands/general.d.ts.map +1 -0
- package/build/lib/commands/general.js +270 -0
- package/build/lib/commands/general.js.map +1 -0
- package/build/lib/commands/geolocation.d.ts +57 -0
- package/build/lib/commands/geolocation.d.ts.map +1 -0
- package/build/lib/commands/geolocation.js +58 -0
- package/build/lib/commands/geolocation.js.map +1 -0
- package/build/lib/commands/gesture.d.ts +283 -0
- package/build/lib/commands/gesture.d.ts.map +1 -0
- package/build/lib/commands/gesture.js +565 -0
- package/build/lib/commands/gesture.js.map +1 -0
- package/build/lib/commands/hid-event.d.ts +2773 -0
- package/build/lib/commands/hid-event.d.ts.map +1 -0
- package/build/lib/commands/hid-event.js +1633 -0
- package/build/lib/commands/hid-event.js.map +1 -0
- package/build/lib/commands/increase-contrast.d.ts +24 -0
- package/build/lib/commands/increase-contrast.d.ts.map +1 -0
- package/build/lib/commands/increase-contrast.js +49 -0
- package/build/lib/commands/increase-contrast.js.map +1 -0
- package/build/lib/commands/iohid.d.ts +1372 -0
- package/build/lib/commands/iohid.d.ts.map +1 -0
- package/build/lib/commands/iohid.js +63 -0
- package/build/lib/commands/iohid.js.map +1 -0
- package/build/lib/commands/keyboard.d.ts +32 -0
- package/build/lib/commands/keyboard.d.ts.map +1 -0
- package/build/lib/commands/keyboard.js +67 -0
- package/build/lib/commands/keyboard.js.map +1 -0
- package/build/lib/commands/keychains.d.ts +10 -0
- package/build/lib/commands/keychains.d.ts.map +1 -0
- package/build/lib/commands/keychains.js +22 -0
- package/build/lib/commands/keychains.js.map +1 -0
- package/build/lib/commands/localization.d.ts +17 -0
- package/build/lib/commands/localization.d.ts.map +1 -0
- package/build/lib/commands/localization.js +34 -0
- package/build/lib/commands/localization.js.map +1 -0
- package/build/lib/commands/location.d.ts +40 -0
- package/build/lib/commands/location.d.ts.map +1 -0
- package/build/lib/commands/location.js +121 -0
- package/build/lib/commands/location.js.map +1 -0
- package/build/lib/commands/lock.d.ts +23 -0
- package/build/lib/commands/lock.d.ts.map +1 -0
- package/build/lib/commands/lock.js +49 -0
- package/build/lib/commands/lock.js.map +1 -0
- package/build/lib/commands/log.d.ts +68 -0
- package/build/lib/commands/log.d.ts.map +1 -0
- package/build/lib/commands/log.js +287 -0
- package/build/lib/commands/log.js.map +1 -0
- package/build/lib/commands/memory.d.ts +11 -0
- package/build/lib/commands/memory.d.ts.map +1 -0
- package/build/lib/commands/memory.js +49 -0
- package/build/lib/commands/memory.js.map +1 -0
- package/build/lib/commands/navigation.d.ts +44 -0
- package/build/lib/commands/navigation.d.ts.map +1 -0
- package/build/lib/commands/navigation.js +121 -0
- package/build/lib/commands/navigation.js.map +1 -0
- package/build/lib/commands/notifications.d.ts +28 -0
- package/build/lib/commands/notifications.d.ts.map +1 -0
- package/build/lib/commands/notifications.js +64 -0
- package/build/lib/commands/notifications.js.map +1 -0
- package/build/lib/commands/pasteboard.d.ts +23 -0
- package/build/lib/commands/pasteboard.d.ts.map +1 -0
- package/build/lib/commands/pasteboard.js +43 -0
- package/build/lib/commands/pasteboard.js.map +1 -0
- package/build/lib/commands/pcap.d.ts +54 -0
- package/build/lib/commands/pcap.d.ts.map +1 -0
- package/build/lib/commands/pcap.js +149 -0
- package/build/lib/commands/pcap.js.map +1 -0
- package/build/lib/commands/performance.d.ts +85 -0
- package/build/lib/commands/performance.d.ts.map +1 -0
- package/build/lib/commands/performance.js +331 -0
- package/build/lib/commands/performance.js.map +1 -0
- package/build/lib/commands/permissions.d.ts +36 -0
- package/build/lib/commands/permissions.d.ts.map +1 -0
- package/build/lib/commands/permissions.js +80 -0
- package/build/lib/commands/permissions.js.map +1 -0
- package/build/lib/commands/proxy-helper.d.ts +15 -0
- package/build/lib/commands/proxy-helper.d.ts.map +1 -0
- package/build/lib/commands/proxy-helper.js +117 -0
- package/build/lib/commands/proxy-helper.js.map +1 -0
- package/build/lib/commands/record-audio.d.ts +69 -0
- package/build/lib/commands/record-audio.d.ts.map +1 -0
- package/build/lib/commands/record-audio.js +228 -0
- package/build/lib/commands/record-audio.js.map +1 -0
- package/build/lib/commands/recordscreen.d.ts +89 -0
- package/build/lib/commands/recordscreen.d.ts.map +1 -0
- package/build/lib/commands/recordscreen.js +326 -0
- package/build/lib/commands/recordscreen.js.map +1 -0
- package/build/lib/commands/screenshots.d.ts +16 -0
- package/build/lib/commands/screenshots.d.ts.map +1 -0
- package/build/lib/commands/screenshots.js +129 -0
- package/build/lib/commands/screenshots.js.map +1 -0
- package/build/lib/commands/simctl.d.ts +27 -0
- package/build/lib/commands/simctl.d.ts.map +1 -0
- package/build/lib/commands/simctl.js +65 -0
- package/build/lib/commands/simctl.js.map +1 -0
- package/build/lib/commands/source.d.ts +16 -0
- package/build/lib/commands/source.d.ts.map +1 -0
- package/build/lib/commands/source.js +128 -0
- package/build/lib/commands/source.js.map +1 -0
- package/build/lib/commands/timeouts.d.ts +53 -0
- package/build/lib/commands/timeouts.d.ts.map +1 -0
- package/build/lib/commands/timeouts.js +71 -0
- package/build/lib/commands/timeouts.js.map +1 -0
- package/build/lib/commands/types.d.ts +539 -0
- package/build/lib/commands/types.d.ts.map +1 -0
- package/build/lib/commands/types.js +3 -0
- package/build/lib/commands/types.js.map +1 -0
- package/build/lib/commands/web.d.ts +297 -0
- package/build/lib/commands/web.d.ts.map +1 -0
- package/build/lib/commands/web.js +1029 -0
- package/build/lib/commands/web.js.map +1 -0
- package/build/lib/commands/xctest-record-screen.d.ts +92 -0
- package/build/lib/commands/xctest-record-screen.d.ts.map +1 -0
- package/build/lib/commands/xctest-record-screen.js +193 -0
- package/build/lib/commands/xctest-record-screen.js.map +1 -0
- package/build/lib/commands/xctest.d.ts +71 -0
- package/build/lib/commands/xctest.d.ts.map +1 -0
- package/build/lib/commands/xctest.js +257 -0
- package/build/lib/commands/xctest.js.map +1 -0
- package/build/lib/css-converter.d.ts +10 -0
- package/build/lib/css-converter.d.ts.map +1 -0
- package/build/lib/css-converter.js +258 -0
- package/build/lib/css-converter.js.map +1 -0
- package/build/lib/desired-caps.d.ts +506 -0
- package/build/lib/desired-caps.d.ts.map +1 -0
- package/build/lib/desired-caps.js +400 -0
- package/build/lib/desired-caps.js.map +1 -0
- package/build/lib/device-connections-factory.d.ts +13 -0
- package/build/lib/device-connections-factory.d.ts.map +1 -0
- package/build/lib/device-connections-factory.js +244 -0
- package/build/lib/device-connections-factory.js.map +1 -0
- package/build/lib/device-log/helpers.d.ts +10 -0
- package/build/lib/device-log/helpers.d.ts.map +1 -0
- package/build/lib/device-log/helpers.js +37 -0
- package/build/lib/device-log/helpers.js.map +1 -0
- package/build/lib/device-log/ios-crash-log.d.ts +34 -0
- package/build/lib/device-log/ios-crash-log.d.ts.map +1 -0
- package/build/lib/device-log/ios-crash-log.js +141 -0
- package/build/lib/device-log/ios-crash-log.js.map +1 -0
- package/build/lib/device-log/ios-device-log.d.ts +19 -0
- package/build/lib/device-log/ios-device-log.d.ts.map +1 -0
- package/build/lib/device-log/ios-device-log.js +42 -0
- package/build/lib/device-log/ios-device-log.js.map +1 -0
- package/build/lib/device-log/ios-log.d.ts +24 -0
- package/build/lib/device-log/ios-log.d.ts.map +1 -0
- package/build/lib/device-log/ios-log.js +50 -0
- package/build/lib/device-log/ios-log.js.map +1 -0
- package/build/lib/device-log/ios-performance-log.d.ts +18 -0
- package/build/lib/device-log/ios-performance-log.d.ts.map +1 -0
- package/build/lib/device-log/ios-performance-log.js +43 -0
- package/build/lib/device-log/ios-performance-log.js.map +1 -0
- package/build/lib/device-log/ios-simulator-log.d.ts +38 -0
- package/build/lib/device-log/ios-simulator-log.d.ts.map +1 -0
- package/build/lib/device-log/ios-simulator-log.js +184 -0
- package/build/lib/device-log/ios-simulator-log.js.map +1 -0
- package/build/lib/device-log/line-consuming-log.d.ts +9 -0
- package/build/lib/device-log/line-consuming-log.d.ts.map +1 -0
- package/build/lib/device-log/line-consuming-log.js +16 -0
- package/build/lib/device-log/line-consuming-log.js.map +1 -0
- package/build/lib/device-log/safari-console-log.d.ts +67 -0
- package/build/lib/device-log/safari-console-log.d.ts.map +1 -0
- package/build/lib/device-log/safari-console-log.js +81 -0
- package/build/lib/device-log/safari-console-log.js.map +1 -0
- package/build/lib/device-log/safari-network-log.d.ts +75 -0
- package/build/lib/device-log/safari-network-log.d.ts.map +1 -0
- package/build/lib/device-log/safari-network-log.js +47 -0
- package/build/lib/device-log/safari-network-log.js.map +1 -0
- package/build/lib/doctor/checks.d.ts +3 -0
- package/build/lib/doctor/checks.d.ts.map +1 -0
- package/build/lib/doctor/checks.js +39 -0
- package/build/lib/doctor/checks.js.map +1 -0
- package/build/lib/doctor/optional-checks.d.ts +46 -0
- package/build/lib/doctor/optional-checks.d.ts.map +1 -0
- package/build/lib/doctor/optional-checks.js +129 -0
- package/build/lib/doctor/optional-checks.js.map +1 -0
- package/build/lib/doctor/required-checks.d.ts +42 -0
- package/build/lib/doctor/required-checks.d.ts.map +1 -0
- package/build/lib/doctor/required-checks.js +94 -0
- package/build/lib/doctor/required-checks.js.map +1 -0
- package/build/lib/doctor/utils.d.ts +8 -0
- package/build/lib/doctor/utils.d.ts.map +1 -0
- package/build/lib/doctor/utils.js +21 -0
- package/build/lib/doctor/utils.js.map +1 -0
- package/build/lib/driver.d.ts +2429 -0
- package/build/lib/driver.d.ts.map +1 -0
- package/build/lib/driver.js +1967 -0
- package/build/lib/driver.js.map +1 -0
- package/build/lib/execute-method-map.d.ts +552 -0
- package/build/lib/execute-method-map.d.ts.map +1 -0
- package/build/lib/execute-method-map.js +586 -0
- package/build/lib/execute-method-map.js.map +1 -0
- package/build/lib/ios-fs-helpers.d.ts +75 -0
- package/build/lib/ios-fs-helpers.d.ts.map +1 -0
- package/build/lib/ios-fs-helpers.js +370 -0
- package/build/lib/ios-fs-helpers.js.map +1 -0
- package/build/lib/ios-generic-simulators.d.ts +6 -0
- package/build/lib/ios-generic-simulators.d.ts.map +1 -0
- package/build/lib/ios-generic-simulators.js +14 -0
- package/build/lib/ios-generic-simulators.js.map +1 -0
- package/build/lib/logger.d.ts +3 -0
- package/build/lib/logger.d.ts.map +1 -0
- package/build/lib/logger.js +6 -0
- package/build/lib/logger.js.map +1 -0
- package/build/lib/method-map.d.ts +229 -0
- package/build/lib/method-map.d.ts.map +1 -0
- package/build/lib/method-map.js +200 -0
- package/build/lib/method-map.js.map +1 -0
- package/build/lib/real-device-clients/base-device-client.d.ts +22 -0
- package/build/lib/real-device-clients/base-device-client.d.ts.map +1 -0
- package/build/lib/real-device-clients/base-device-client.js +14 -0
- package/build/lib/real-device-clients/base-device-client.js.map +1 -0
- package/build/lib/real-device-clients/py-ios-device-client.d.ts +21 -0
- package/build/lib/real-device-clients/py-ios-device-client.d.ts.map +1 -0
- package/build/lib/real-device-clients/py-ios-device-client.js +125 -0
- package/build/lib/real-device-clients/py-ios-device-client.js.map +1 -0
- package/build/lib/real-device-management.d.ts +53 -0
- package/build/lib/real-device-management.d.ts.map +1 -0
- package/build/lib/real-device-management.js +128 -0
- package/build/lib/real-device-management.js.map +1 -0
- package/build/lib/real-device.d.ts +112 -0
- package/build/lib/real-device.d.ts.map +1 -0
- package/build/lib/real-device.js +352 -0
- package/build/lib/real-device.js.map +1 -0
- package/build/lib/simulator-management.d.ts +96 -0
- package/build/lib/simulator-management.d.ts.map +1 -0
- package/build/lib/simulator-management.js +278 -0
- package/build/lib/simulator-management.js.map +1 -0
- package/build/lib/stubs.d.ts +3 -0
- package/build/lib/stubs.d.ts.map +1 -0
- package/build/lib/stubs.js +3 -0
- package/build/lib/stubs.js.map +1 -0
- package/build/lib/types.d.ts +31 -0
- package/build/lib/types.d.ts.map +1 -0
- package/build/lib/types.js +3 -0
- package/build/lib/types.js.map +1 -0
- package/build/lib/utils.d.ts +191 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +549 -0
- package/build/lib/utils.js.map +1 -0
- package/build/lib/xcrun.d.ts +3 -0
- package/build/lib/xcrun.d.ts.map +1 -0
- package/build/lib/xcrun.js +17 -0
- package/build/lib/xcrun.js.map +1 -0
- package/index.js +7 -0
- package/lib/app-infos-cache.js +187 -0
- package/lib/app-utils.js +710 -0
- package/lib/commands/active-app-info.js +12 -0
- package/lib/commands/advanced-battery-types.ts +454 -0
- package/lib/commands/alert.js +88 -0
- package/lib/commands/app-management.js +346 -0
- package/lib/commands/app-strings.js +30 -0
- package/lib/commands/appearance.js +71 -0
- package/lib/commands/audit.js +31 -0
- package/lib/commands/battery.js +45 -0
- package/lib/commands/bidi/constants.ts +6 -0
- package/lib/commands/bidi/models.ts +55 -0
- package/lib/commands/bidi/types.ts +31 -0
- package/lib/commands/biometric.js +53 -0
- package/lib/commands/certificate.js +497 -0
- package/lib/commands/clipboard.js +35 -0
- package/lib/commands/condition.js +155 -0
- package/lib/commands/content-size.js +68 -0
- package/lib/commands/context.js +705 -0
- package/lib/commands/deviceInfo.js +27 -0
- package/lib/commands/element.js +423 -0
- package/lib/commands/enum.ts +108 -0
- package/lib/commands/execute.js +153 -0
- package/lib/commands/file-movement.js +510 -0
- package/lib/commands/find.js +205 -0
- package/lib/commands/general.js +278 -0
- package/lib/commands/geolocation.js +56 -0
- package/lib/commands/gesture.js +596 -0
- package/lib/commands/hid-event.ts +1634 -0
- package/lib/commands/increase-contrast.js +50 -0
- package/lib/commands/iohid.js +64 -0
- package/lib/commands/keyboard.js +62 -0
- package/lib/commands/keychains.js +18 -0
- package/lib/commands/localization.js +30 -0
- package/lib/commands/location.js +131 -0
- package/lib/commands/lock.js +46 -0
- package/lib/commands/log.js +327 -0
- package/lib/commands/memory.js +51 -0
- package/lib/commands/navigation.js +125 -0
- package/lib/commands/notifications.js +66 -0
- package/lib/commands/pasteboard.js +42 -0
- package/lib/commands/pcap.js +168 -0
- package/lib/commands/performance.js +392 -0
- package/lib/commands/permissions.js +85 -0
- package/lib/commands/proxy-helper.js +122 -0
- package/lib/commands/record-audio.js +264 -0
- package/lib/commands/recordscreen.js +391 -0
- package/lib/commands/screenshots.js +137 -0
- package/lib/commands/simctl.js +71 -0
- package/lib/commands/source.js +131 -0
- package/lib/commands/timeouts.js +68 -0
- package/lib/commands/types.ts +648 -0
- package/lib/commands/web.js +1113 -0
- package/lib/commands/xctest-record-screen.js +204 -0
- package/lib/commands/xctest.js +285 -0
- package/lib/css-converter.js +311 -0
- package/lib/desired-caps.js +396 -0
- package/lib/device-connections-factory.js +269 -0
- package/lib/device-log/helpers.ts +40 -0
- package/lib/device-log/ios-crash-log.ts +166 -0
- package/lib/device-log/ios-device-log.ts +51 -0
- package/lib/device-log/ios-log.ts +70 -0
- package/lib/device-log/ios-performance-log.ts +50 -0
- package/lib/device-log/ios-simulator-log.ts +202 -0
- package/lib/device-log/line-consuming-log.ts +16 -0
- package/lib/device-log/safari-console-log.ts +117 -0
- package/lib/device-log/safari-network-log.ts +120 -0
- package/lib/doctor/checks.ts +3 -0
- package/lib/doctor/optional-checks.ts +173 -0
- package/lib/doctor/required-checks.ts +120 -0
- package/lib/doctor/utils.ts +18 -0
- package/lib/driver.js +2316 -0
- package/lib/execute-method-map.ts +585 -0
- package/lib/ios-fs-helpers.js +355 -0
- package/lib/ios-generic-simulators.js +11 -0
- package/lib/logger.js +5 -0
- package/lib/method-map.js +196 -0
- package/lib/real-device-clients/base-device-client.ts +34 -0
- package/lib/real-device-clients/py-ios-device-client.ts +149 -0
- package/lib/real-device-management.js +133 -0
- package/lib/real-device.js +347 -0
- package/lib/simulator-management.js +324 -0
- package/lib/stubs.ts +3 -0
- package/lib/types.ts +33 -0
- package/lib/utils.js +551 -0
- package/lib/xcrun.js +16 -0
- package/package.json +175 -0
- package/scripts/build-docs.js +56 -0
- package/scripts/build-wda.js +42 -0
- package/scripts/download-wda-sim.mjs +68 -0
- package/scripts/image-mounter.mjs +239 -0
- package/scripts/open-wda.mjs +15 -0
- package/scripts/tunnel-creation.mjs +359 -0
- package/scripts/utils.js +16 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { Pyidevice } from '../real-device-clients/py-ios-device-client';
|
|
2
|
+
import {fs, tempDir, util} from 'appium/support';
|
|
3
|
+
import {encodeBase64OrUpload} from '../utils';
|
|
4
|
+
import {errors} from 'appium/driver';
|
|
5
|
+
|
|
6
|
+
const MAX_CAPTURE_TIME_SEC = 60 * 60 * 12;
|
|
7
|
+
const DEFAULT_EXT = '.pcap';
|
|
8
|
+
|
|
9
|
+
export class TrafficCapture {
|
|
10
|
+
/** @type {import('teen_process').SubProcess|null} */
|
|
11
|
+
mainProcess;
|
|
12
|
+
constructor(udid, log, resultPath) {
|
|
13
|
+
this.udid = udid;
|
|
14
|
+
this.log = log;
|
|
15
|
+
this.resultPath = resultPath;
|
|
16
|
+
this.mainProcess = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async start(timeoutSeconds) {
|
|
20
|
+
this.mainProcess = /** @type {import('teen_process').SubProcess} */ (
|
|
21
|
+
await new Pyidevice({
|
|
22
|
+
udid: this.udid,
|
|
23
|
+
log: this.log,
|
|
24
|
+
}).collectPcap(this.resultPath)
|
|
25
|
+
);
|
|
26
|
+
this.mainProcess.on('line-stderr', (line) => this.log.info(`[Pcap] ${line}`));
|
|
27
|
+
this.log.info(
|
|
28
|
+
`Starting network traffic capture session on the device '${this.udid}'. ` +
|
|
29
|
+
`Will timeout in ${timeoutSeconds}s`,
|
|
30
|
+
);
|
|
31
|
+
setTimeout(async () => await this.interrupt(), timeoutSeconds * 1000);
|
|
32
|
+
this.mainProcess.once('exit', (code, signal) => {
|
|
33
|
+
this.log.debug(
|
|
34
|
+
`The traffic capture session on the device '${this.udid}' has exited ` +
|
|
35
|
+
`with code ${code}, signal ${signal}`,
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
isCapturing() {
|
|
41
|
+
return !!this.mainProcess?.isRunning;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async interrupt(force = false) {
|
|
45
|
+
if (this.isCapturing()) {
|
|
46
|
+
const interruptPromise = this.mainProcess?.stop(force ? 'SIGTERM' : 'SIGINT');
|
|
47
|
+
this.mainProcess = null;
|
|
48
|
+
try {
|
|
49
|
+
await interruptPromise;
|
|
50
|
+
} catch (e) {
|
|
51
|
+
this.log.warn(
|
|
52
|
+
`Cannot ${force ? 'terminate' : 'interrupt'} the traffic capture session. ` +
|
|
53
|
+
`Original error: ${e.message}`,
|
|
54
|
+
);
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async finish() {
|
|
63
|
+
await this.interrupt();
|
|
64
|
+
return this.resultPath;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async cleanup() {
|
|
68
|
+
if (await fs.exists(this.resultPath)) {
|
|
69
|
+
await fs.rimraf(this.resultPath);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Records the given network traffic capture into a .pcap file.
|
|
76
|
+
*
|
|
77
|
+
* @param {number} timeLimitSec - The maximum recording time, in seconds. The maximum value is `43200` (12 hours).
|
|
78
|
+
* @param {boolean} forceRestart - Whether to restart traffic capture process forcefully when startPcap is called (`true`) or ignore the call until the current traffic capture is completed (`false`, the default value).
|
|
79
|
+
* @throws {Error} If network traffic capture has failed to start.
|
|
80
|
+
* @returns {Promise<void>}
|
|
81
|
+
* @this {XCUITestDriver}
|
|
82
|
+
*/
|
|
83
|
+
export async function mobileStartPcap(timeLimitSec = 180, forceRestart = false) {
|
|
84
|
+
if (this.isSimulator()) {
|
|
85
|
+
throw this.log.errorWithException('Network traffic capture only works on real devices');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this._trafficCapture?.isCapturing()) {
|
|
89
|
+
this.log.info(`There is an active traffic capture process`);
|
|
90
|
+
if (forceRestart) {
|
|
91
|
+
this.log.info(`Stopping it because 'forceRestart' option is set to true`);
|
|
92
|
+
await this._trafficCapture.interrupt(true);
|
|
93
|
+
} else {
|
|
94
|
+
this.log.info(
|
|
95
|
+
`Doing nothing. ` +
|
|
96
|
+
`Set 'forceRestart' option to true if you'd like to start a new traffic capture session`,
|
|
97
|
+
);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (this._trafficCapture) {
|
|
102
|
+
await this._trafficCapture.cleanup();
|
|
103
|
+
this._trafficCapture = null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const resultPath = await tempDir.path({
|
|
107
|
+
prefix: `appium_${util.uuidV4().substring(0, 8)}`,
|
|
108
|
+
suffix: DEFAULT_EXT,
|
|
109
|
+
});
|
|
110
|
+
const trafficCollector = new TrafficCapture(this.device.udid, this.log, resultPath);
|
|
111
|
+
|
|
112
|
+
const timeoutSeconds = parseInt(String(timeLimitSec), 10);
|
|
113
|
+
if (isNaN(timeoutSeconds) || timeoutSeconds > MAX_CAPTURE_TIME_SEC || timeoutSeconds <= 0) {
|
|
114
|
+
throw new errors.InvalidArgumentError(
|
|
115
|
+
`The timeLimitSec value must be in range [1, ${MAX_CAPTURE_TIME_SEC}] seconds. ` +
|
|
116
|
+
`The value of '${timeLimitSec}' has been passed instead.`,
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
await trafficCollector.start(timeoutSeconds);
|
|
122
|
+
} catch (e) {
|
|
123
|
+
await trafficCollector.interrupt(true);
|
|
124
|
+
await trafficCollector.cleanup();
|
|
125
|
+
throw e;
|
|
126
|
+
}
|
|
127
|
+
this._trafficCapture = trafficCollector;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Stops network traffic capture.
|
|
132
|
+
*
|
|
133
|
+
* If no traffic capture process is running, then the endpoint will try to get the recently recorded file.
|
|
134
|
+
*
|
|
135
|
+
* If no previously recorded file is found and no active traffic capture processes are running, then the method returns an empty string.
|
|
136
|
+
*
|
|
137
|
+
* @remarks Network capture files can be viewed in [Wireshark](https://www.wireshark.org/) and other similar applications.
|
|
138
|
+
* @returns {Promise<string>} Base64-encoded content of the recorded pcap file or an empty string if no traffic capture has been started before.
|
|
139
|
+
* @throws {Error} If there was an error while getting the capture file.
|
|
140
|
+
* @this {XCUITestDriver}
|
|
141
|
+
*/
|
|
142
|
+
export async function mobileStopPcap() {
|
|
143
|
+
if (!this._trafficCapture) {
|
|
144
|
+
this.log.info('Network traffic collector has not been started. There is nothing to stop');
|
|
145
|
+
return '';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let resultPath;
|
|
149
|
+
try {
|
|
150
|
+
resultPath = await this._trafficCapture.finish();
|
|
151
|
+
if (!(await fs.exists(resultPath))) {
|
|
152
|
+
throw this.log.errorWithException(
|
|
153
|
+
`The network traffic capture utility has failed ` +
|
|
154
|
+
`to store the actual traffic capture at '${resultPath}'`,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
} catch (e) {
|
|
158
|
+
await this._trafficCapture.interrupt(true);
|
|
159
|
+
await this._trafficCapture.cleanup();
|
|
160
|
+
this._trafficCapture = null;
|
|
161
|
+
throw e;
|
|
162
|
+
}
|
|
163
|
+
return await encodeBase64OrUpload(resultPath);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
|
168
|
+
*/
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import {fs, zip, logger, util, tempDir} from 'appium/support';
|
|
4
|
+
import {SubProcess, exec} from 'teen_process';
|
|
5
|
+
import {encodeBase64OrUpload} from '../utils';
|
|
6
|
+
import { XCRUN, requireXcrun } from '../xcrun';
|
|
7
|
+
import {waitForCondition} from 'asyncbox';
|
|
8
|
+
import B from 'bluebird';
|
|
9
|
+
|
|
10
|
+
const PERF_RECORD_FEAT_NAME = 'perf_record';
|
|
11
|
+
const PERF_RECORD_SECURITY_MESSAGE =
|
|
12
|
+
'Performance measurement requires relaxing security for simulator. ' +
|
|
13
|
+
`Please set '--relaxed-security' or '--allow-insecure' with '${PERF_RECORD_FEAT_NAME}' ` +
|
|
14
|
+
'referencing https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/security.md for more details.';
|
|
15
|
+
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
16
|
+
const STOP_TIMEOUT_MS = 3 * 60 * 1000;
|
|
17
|
+
const STARTUP_TIMEOUT_MS = 60 * 1000;
|
|
18
|
+
const DEFAULT_PROFILE_NAME = 'Activity Monitor';
|
|
19
|
+
const DEFAULT_EXT = '.trace';
|
|
20
|
+
const DEFAULT_PID = 'current';
|
|
21
|
+
const INSTRUMENTS = 'instruments';
|
|
22
|
+
const XCTRACE = 'xctrace';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Starts performance profiling for the device under test.
|
|
26
|
+
*
|
|
27
|
+
* Relaxing security is mandatory for simulators. It can always work for real devices.
|
|
28
|
+
*
|
|
29
|
+
* Since XCode 12 the method tries to use `xctrace` tool to record performance stats.
|
|
30
|
+
*
|
|
31
|
+
* The `instruments` developer utility is used as a fallback for this purpose if `xctrace` is not available.
|
|
32
|
+
*
|
|
33
|
+
* It is possible to record multiple profiles at the same time.
|
|
34
|
+
*
|
|
35
|
+
* Read [Recording, Pausing, and Stopping Traces](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Recording,Pausing,andStoppingTraces.html) for more details.
|
|
36
|
+
*
|
|
37
|
+
* @param {number} timeout - The maximum count of milliseconds to record the profiling information.
|
|
38
|
+
* @param {string} profileName - The name of existing performance profile to apply. Can also contain the full path to the chosen template on the server file system. Note: not all profiles are supported on mobile devices.
|
|
39
|
+
* @param {number|'current'} [pid] - The ID of the process to measure the performance for. Set it to `current` in order to measure the performance of the process, which belongs to the currently active application. All processes running on the device are measured if `pid` is unset (the default setting).
|
|
40
|
+
* @this {XCUITestDriver}
|
|
41
|
+
*/
|
|
42
|
+
export async function mobileStartPerfRecord(
|
|
43
|
+
timeout = DEFAULT_TIMEOUT_MS,
|
|
44
|
+
profileName = DEFAULT_PROFILE_NAME,
|
|
45
|
+
pid,
|
|
46
|
+
) {
|
|
47
|
+
if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) {
|
|
48
|
+
throw this.log.errorWithException(PERF_RECORD_SECURITY_MESSAGE);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!_.isEmpty(this._perfRecorders)) {
|
|
52
|
+
for (const recorder of this._perfRecorders.filter((x) => x.profileName === profileName)) {
|
|
53
|
+
if (recorder.isRunning()) {
|
|
54
|
+
this.log.debug(
|
|
55
|
+
`Performance recorder for '${profileName}' on device '${this.device.udid}' ` +
|
|
56
|
+
` is already running. Doing nothing`,
|
|
57
|
+
);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
_.pull(this._perfRecorders, recorder);
|
|
61
|
+
await recorder.stop(true);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let realPid;
|
|
66
|
+
if (pid) {
|
|
67
|
+
if (_.toLower(String(pid)) === DEFAULT_PID) {
|
|
68
|
+
const appInfo = /** @type {import('./types').ActiveAppInfo} */ (
|
|
69
|
+
await this.proxyCommand('/wda/activeAppInfo', 'GET')
|
|
70
|
+
);
|
|
71
|
+
realPid = appInfo.pid;
|
|
72
|
+
} else {
|
|
73
|
+
realPid = pid;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const recorder = new PerfRecorder(await tempDir.openDir(), this.device.udid, {
|
|
77
|
+
timeout: parseInt(String(timeout), 10),
|
|
78
|
+
profileName,
|
|
79
|
+
pid: parseInt(String(realPid), 10),
|
|
80
|
+
});
|
|
81
|
+
await recorder.start();
|
|
82
|
+
this._perfRecorders = [...(this._perfRecorders || []), recorder];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Stops performance recording operation previously started by {@linkcode XCUITestDriver.mobileStartPerfRecord mobile: startPerfRecord}.
|
|
87
|
+
*
|
|
88
|
+
* If the previous call has already been completed due to the timeout, then its result is returned immediately. An error is thrown if the performance recording failed to start.
|
|
89
|
+
*
|
|
90
|
+
* The resulting file in `.trace` format can be either returned directly as base64-encoded zip archive or uploaded to a remote location (such files can be pretty large). Afterwards it is possible to unarchive and open such files with Xcode Dev Tools.
|
|
91
|
+
*
|
|
92
|
+
* @param {string} [remotePath] - The path to the remote location, where the resulting zipped `.trace` file should be uploaded. The following protocols are supported: `http`, `https`, `ftp`. Null or empty string value (the default setting) means the content of resulting file should be zipped, encoded as Base64 and passed as the endpoint response value. An exception will be thrown if the generated file is too big to fit into the available process memory.
|
|
93
|
+
* @param {string} [user] - The name of the user for the remote authentication. Only works if `remotePath` is provided.
|
|
94
|
+
* @param {string} [pass] - The password for the remote authentication. Only works if `remotePath` is provided.
|
|
95
|
+
* @param {import('axios').Method} [method] - The http multipart upload method name. Only works if `remotePath` is provided. Defaults to `PUT`
|
|
96
|
+
* @param {string} profileName - The name of existing performance profile to stop the recording for. Multiple recorders for different profile names could be executed at the same time.
|
|
97
|
+
* @param {Record<string,any>} [headers] - Additional headers mapping for multipart http(s) uploads
|
|
98
|
+
* @param {string} [fileFieldName] - The name of the form field, where the file content BLOB should be stored for http(s) uploads. Defaults to `file`
|
|
99
|
+
* @param {Record<string,any>|([string, any])[]} [formFields] - Additional form fields for multipart http(s) uploads
|
|
100
|
+
*
|
|
101
|
+
* @returns {Promise<string>} The resulting file in `.trace` format. This file can either be returned directly as base64-encoded `.zip` archive or uploaded to a remote location (note that such files may be large), _depending on the `remotePath` argument value._ Thereafter, the file may be unarchived and opened with Xcode Developer Tools.
|
|
102
|
+
* @throws {Error} If no performance recording with given profile name/device udid combination
|
|
103
|
+
* has been started before or the resulting .trace file has not been generated properly.
|
|
104
|
+
* @this {XCUITestDriver}
|
|
105
|
+
*/
|
|
106
|
+
export async function mobileStopPerfRecord(
|
|
107
|
+
remotePath,
|
|
108
|
+
user,
|
|
109
|
+
pass,
|
|
110
|
+
method,
|
|
111
|
+
profileName = DEFAULT_PROFILE_NAME,
|
|
112
|
+
headers,
|
|
113
|
+
fileFieldName,
|
|
114
|
+
formFields,
|
|
115
|
+
) {
|
|
116
|
+
if (!this.isFeatureEnabled(PERF_RECORD_FEAT_NAME) && !this.isRealDevice()) {
|
|
117
|
+
throw this.log.errorWithException(PERF_RECORD_SECURITY_MESSAGE);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (_.isEmpty(this._perfRecorders)) {
|
|
121
|
+
this.log.info('No performance recorders have been started. Doing nothing');
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const recorders = this._perfRecorders.filter((x) => x.profileName === profileName);
|
|
126
|
+
if (_.isEmpty(recorders)) {
|
|
127
|
+
throw this.log.errorWithException(
|
|
128
|
+
`There are no records for performance profile '${profileName}' ` +
|
|
129
|
+
`and device ${this.device.udid}. Have you started the profiling before?`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const recorder = _.first(recorders);
|
|
134
|
+
const resultPath = await /** @type {PerfRecorder} */ (recorder).stop();
|
|
135
|
+
if (!(await fs.exists(resultPath))) {
|
|
136
|
+
throw this.log.errorWithException(
|
|
137
|
+
`There is no ${DEFAULT_EXT} file found for performance profile '${profileName}' ` +
|
|
138
|
+
`and device ${this.device.udid}. Make sure the selected profile is supported on this device`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const result = await encodeBase64OrUpload(resultPath, remotePath, {
|
|
143
|
+
user,
|
|
144
|
+
pass,
|
|
145
|
+
method,
|
|
146
|
+
headers,
|
|
147
|
+
fileFieldName,
|
|
148
|
+
formFields,
|
|
149
|
+
});
|
|
150
|
+
_.pull(this._perfRecorders, recorder);
|
|
151
|
+
await fs.rimraf(resultPath);
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
async function requireXctrace() {
|
|
157
|
+
const xcrunPath = await requireXcrun();
|
|
158
|
+
try {
|
|
159
|
+
await exec(xcrunPath, [XCTRACE, 'help']);
|
|
160
|
+
} catch (e) {
|
|
161
|
+
throw new Error(
|
|
162
|
+
`${XCTRACE} is not available for the active Xcode version. ` +
|
|
163
|
+
`Please make sure XCode is up to date. Original error: ${e.stderr || e.message}`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
return xcrunPath;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function requireInstruments() {
|
|
170
|
+
try {
|
|
171
|
+
return await fs.which(INSTRUMENTS);
|
|
172
|
+
} catch {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`${INSTRUMENTS} has not been found in PATH. ` +
|
|
175
|
+
`Please make sure XCode development tools are installed`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export class PerfRecorder {
|
|
181
|
+
/** @type {import('teen_process').SubProcess|null} */
|
|
182
|
+
_process;
|
|
183
|
+
constructor(reportRoot, udid, opts = {}) {
|
|
184
|
+
this._process = null;
|
|
185
|
+
this._zippedReportPath = '';
|
|
186
|
+
this._timeout = opts.timeout && opts.timeout > 0 ? opts.timeout : DEFAULT_TIMEOUT_MS;
|
|
187
|
+
this._profileName = opts.profileName || DEFAULT_PROFILE_NAME;
|
|
188
|
+
this._reportPath = path.resolve(
|
|
189
|
+
reportRoot,
|
|
190
|
+
`appium_perf__${this._profileName.replace(/\W/g, '_')}__${Date.now()}${DEFAULT_EXT}`,
|
|
191
|
+
);
|
|
192
|
+
this._pid = opts.pid;
|
|
193
|
+
this._udid = udid;
|
|
194
|
+
this._logger = logger.getLogger(
|
|
195
|
+
`${_.truncate(this._profileName, {length: 10})}@${this._udid.substring(0, 8)}`,
|
|
196
|
+
);
|
|
197
|
+
this._archivePromise = null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
get profileName() {
|
|
201
|
+
return this._profileName;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async getOriginalReportPath() {
|
|
205
|
+
return (await fs.exists(this._reportPath)) ? this._reportPath : '';
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async getZippedReportPath() {
|
|
209
|
+
// This is to prevent possible race conditions, because the archive operation
|
|
210
|
+
// could be pretty time-intensive
|
|
211
|
+
if (!this._archivePromise) {
|
|
212
|
+
this._archivePromise = (async () => {
|
|
213
|
+
const originalReportPath = await this.getOriginalReportPath();
|
|
214
|
+
if (!originalReportPath) {
|
|
215
|
+
return '';
|
|
216
|
+
}
|
|
217
|
+
const zippedReportPath = await tempDir.path({
|
|
218
|
+
prefix: path.parse(originalReportPath).name,
|
|
219
|
+
suffix: '.zip',
|
|
220
|
+
});
|
|
221
|
+
await zip.toArchive(zippedReportPath, {
|
|
222
|
+
cwd: path.dirname(this._reportPath),
|
|
223
|
+
});
|
|
224
|
+
await fs.rimraf(path.dirname(this._reportPath));
|
|
225
|
+
this._zippedReportPath = zippedReportPath;
|
|
226
|
+
return this._zippedReportPath;
|
|
227
|
+
})();
|
|
228
|
+
}
|
|
229
|
+
return await this._archivePromise;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
isRunning() {
|
|
233
|
+
return !!this._process?.isRunning;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async _enforceTermination() {
|
|
237
|
+
if (this._process && this.isRunning()) {
|
|
238
|
+
this._logger.debug('Force-stopping the currently running perf recording');
|
|
239
|
+
try {
|
|
240
|
+
await this._process.stop('SIGKILL');
|
|
241
|
+
} catch {}
|
|
242
|
+
}
|
|
243
|
+
this._process = null;
|
|
244
|
+
const performCleanup = async () => {
|
|
245
|
+
try {
|
|
246
|
+
await B.all(
|
|
247
|
+
[this._zippedReportPath, path.dirname(this._reportPath)]
|
|
248
|
+
.filter(Boolean)
|
|
249
|
+
.map((x) => fs.rimraf(x)),
|
|
250
|
+
);
|
|
251
|
+
} catch (e) {
|
|
252
|
+
this._logger.warn(e.message);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
if (this._archivePromise) {
|
|
256
|
+
(async () => {
|
|
257
|
+
try {
|
|
258
|
+
await this._archivePromise;
|
|
259
|
+
} catch {
|
|
260
|
+
} finally {
|
|
261
|
+
await performCleanup();
|
|
262
|
+
this._archivePromise = null;
|
|
263
|
+
}
|
|
264
|
+
})();
|
|
265
|
+
}
|
|
266
|
+
await performCleanup();
|
|
267
|
+
return '';
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async start() {
|
|
271
|
+
let binaryPath;
|
|
272
|
+
try {
|
|
273
|
+
binaryPath = await requireXctrace();
|
|
274
|
+
} catch (e) {
|
|
275
|
+
this._logger.debug(e.message);
|
|
276
|
+
this._logger.warn(`Defaulting to ${INSTRUMENTS} usage`);
|
|
277
|
+
binaryPath = await requireInstruments();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const args = [];
|
|
281
|
+
const toolName = path.basename(binaryPath) === XCRUN ? XCTRACE : INSTRUMENTS;
|
|
282
|
+
if (toolName === XCTRACE) {
|
|
283
|
+
args.push(
|
|
284
|
+
XCTRACE,
|
|
285
|
+
'record',
|
|
286
|
+
'--device',
|
|
287
|
+
this._udid,
|
|
288
|
+
'--template',
|
|
289
|
+
this._profileName,
|
|
290
|
+
'--output',
|
|
291
|
+
this._reportPath,
|
|
292
|
+
'--time-limit',
|
|
293
|
+
`${this._timeout}ms`,
|
|
294
|
+
);
|
|
295
|
+
if (this._pid) {
|
|
296
|
+
args.push('--attach', `${this._pid}`);
|
|
297
|
+
} else {
|
|
298
|
+
args.push('--all-processes');
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
// https://help.apple.com/instruments/mac/current/#/devb14ffaa5
|
|
302
|
+
args.push(
|
|
303
|
+
'-w',
|
|
304
|
+
this._udid,
|
|
305
|
+
'-t',
|
|
306
|
+
this._profileName,
|
|
307
|
+
'-D',
|
|
308
|
+
this._reportPath,
|
|
309
|
+
'-l',
|
|
310
|
+
`${this._timeout}`,
|
|
311
|
+
);
|
|
312
|
+
if (this._pid) {
|
|
313
|
+
args.push('-p', `${this._pid}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const fullCmd = [binaryPath, ...args];
|
|
317
|
+
this._process = new SubProcess(fullCmd[0], fullCmd.slice(1));
|
|
318
|
+
this._archivePromise = null;
|
|
319
|
+
this._logger.debug(`Starting performance recording: ${util.quote(fullCmd)}`);
|
|
320
|
+
for (const streamName of ['stdout', 'stderr']) {
|
|
321
|
+
this._process.on(`line-${streamName}`, (line) => this._logger.debug(`[${toolName}] ${line}`));
|
|
322
|
+
}
|
|
323
|
+
this._process.once('exit', async (code, signal) => {
|
|
324
|
+
this._process = null;
|
|
325
|
+
if (code === 0) {
|
|
326
|
+
this._logger.debug('Performance recording exited without errors');
|
|
327
|
+
try {
|
|
328
|
+
// cache zipped report
|
|
329
|
+
await this.getZippedReportPath();
|
|
330
|
+
} catch (e) {
|
|
331
|
+
this._logger.warn(e);
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
await this._enforceTermination();
|
|
335
|
+
this._logger.warn(`Performance recording exited with error code ${code}, signal ${signal}`);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
await this._process.start(0);
|
|
339
|
+
try {
|
|
340
|
+
await waitForCondition(
|
|
341
|
+
async () => {
|
|
342
|
+
if (await this.getOriginalReportPath()) {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
if (!this._process) {
|
|
346
|
+
throw new Error(`${toolName} process died unexpectedly`);
|
|
347
|
+
}
|
|
348
|
+
return false;
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
waitMs: STARTUP_TIMEOUT_MS,
|
|
352
|
+
intervalMs: 500,
|
|
353
|
+
},
|
|
354
|
+
);
|
|
355
|
+
} catch {
|
|
356
|
+
await this._enforceTermination();
|
|
357
|
+
const listProfilesCommand =
|
|
358
|
+
toolName === XCTRACE ? `${XCRUN} ${XCTRACE} list templates` : `${INSTRUMENTS} -s`;
|
|
359
|
+
throw this._logger.errorWithException(
|
|
360
|
+
`There is no ${DEFAULT_EXT} file found for performance profile ` +
|
|
361
|
+
`'${this._profileName}'. Make sure the profile is supported on this device. ` +
|
|
362
|
+
`You could use '${listProfilesCommand}' command to see the list of all available profiles. ` +
|
|
363
|
+
`Check the server log for more details`,
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
this._logger.info(`The performance recording has started. Will timeout in ${this._timeout}ms`);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
async stop(force = false) {
|
|
370
|
+
if (force) {
|
|
371
|
+
return await this._enforceTermination();
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (!this.isRunning()) {
|
|
375
|
+
this._logger.debug('Performance recording is not running. Returning the recent result');
|
|
376
|
+
return await this.getZippedReportPath();
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
await this._process?.stop('SIGINT', STOP_TIMEOUT_MS);
|
|
381
|
+
} catch {
|
|
382
|
+
throw this._logger.errorWithException(
|
|
383
|
+
`Performance recording has failed to exit after ${STOP_TIMEOUT_MS}ms`,
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
return await this.getZippedReportPath();
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
|
392
|
+
*/
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import {PermissionService} from './enum';
|
|
3
|
+
import {assertSimulator as _assertSimulator} from '../utils';
|
|
4
|
+
|
|
5
|
+
const assertSimulator = _.partial(_assertSimulator, 'Permission-related operations');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Resets the given permission for the active application under test.
|
|
9
|
+
* Works for both Simulator and real devices using Xcode SDK 11.4+
|
|
10
|
+
*
|
|
11
|
+
* @param {PermissionService|number} service - One of the available service names. This could also be an integer protected resource identifier; see [this list](https://developer.apple.com/documentation/xctest/xcuiprotectedresource?language=objc)
|
|
12
|
+
* @throws {Error} If permission reset fails on the device.
|
|
13
|
+
* @this {XCUITestDriver}
|
|
14
|
+
*/
|
|
15
|
+
export async function mobileResetPermission(service) {
|
|
16
|
+
if (!service) {
|
|
17
|
+
throw new Error(`The 'service' option is expected to be present`);
|
|
18
|
+
}
|
|
19
|
+
let resource;
|
|
20
|
+
if (_.isString(service)) {
|
|
21
|
+
resource = PermissionService[_.toLower(service)];
|
|
22
|
+
if (!resource) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
`The 'service' value must be one of ` + `${JSON.stringify(_.keys(PermissionService))}`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
} else if (_.isInteger(service)) {
|
|
28
|
+
resource = service;
|
|
29
|
+
} else {
|
|
30
|
+
throw new Error(
|
|
31
|
+
`The 'service' value must be either a string or an integer. ` +
|
|
32
|
+
`'${service}' is passed instead`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
await this.proxyCommand('/wda/resetAppAuth', 'POST', {resource});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Gets application permission state on a simulated device.
|
|
41
|
+
*
|
|
42
|
+
* **This method requires [WIX applesimutils](https://github.com/wix/AppleSimulatorUtils) to be installed on the Appium server host.**
|
|
43
|
+
*
|
|
44
|
+
* @param {string} bundleId - Bundle identifier of the target application
|
|
45
|
+
* @param {import('./enum').PermissionService} service - Service name
|
|
46
|
+
* @returns {Promise<import('./types').PermissionState>} Either 'yes', 'no', 'unset' or 'limited'
|
|
47
|
+
* @throws {Error} If permission getting fails or the device is not a Simulator.
|
|
48
|
+
* @this {XCUITestDriver}
|
|
49
|
+
* @group Simulator Only
|
|
50
|
+
*/
|
|
51
|
+
export async function mobileGetPermission(bundleId, service) {
|
|
52
|
+
if (!service) {
|
|
53
|
+
throw new Error(`The 'service' option is expected to be present`);
|
|
54
|
+
}
|
|
55
|
+
assertSimulator(this);
|
|
56
|
+
|
|
57
|
+
return /** @type {import('./types').PermissionState} */ (
|
|
58
|
+
await /** @type {import('../driver').Simulator} */ (this.device).getPermission(
|
|
59
|
+
bundleId, String(service)
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Set application permission state on Simulator.
|
|
66
|
+
*
|
|
67
|
+
* @param {Record<Partial<import('./types').AccessRule>, import('./types').PermissionState>} access - One or more access rules to set.
|
|
68
|
+
* @param {string} bundleId - Bundle identifier of the target application
|
|
69
|
+
* @since Xcode SDK 11.4
|
|
70
|
+
* @throws {Error} If permission setting fails or the device is not a Simulator.
|
|
71
|
+
* @group Simulator Only
|
|
72
|
+
* @this {XCUITestDriver}
|
|
73
|
+
*/
|
|
74
|
+
export async function mobileSetPermissions(access, bundleId) {
|
|
75
|
+
if (!_.isPlainObject(access)) {
|
|
76
|
+
throw new Error(`The 'access' option is expected to be a map`);
|
|
77
|
+
}
|
|
78
|
+
assertSimulator(this);
|
|
79
|
+
|
|
80
|
+
await /** @type {import('../driver').Simulator} */ (this.device).setPermissions(bundleId, access);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @typedef {import('../driver').XCUITestDriver} XCUITestDriver
|
|
85
|
+
*/
|