appium-xcuitest-driver 3.43.0 → 3.46.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/README.md +311 -18
- package/build/index.js +12 -9
- package/build/lib/app-utils.js +188 -0
- package/build/lib/commands/certificate.js +2 -4
- package/build/lib/commands/context.js +223 -18
- package/build/lib/commands/element.js +48 -6
- package/build/lib/commands/execute.js +35 -10
- package/build/lib/commands/file-movement.js +2 -4
- package/build/lib/commands/general.js +86 -13
- package/build/lib/commands/gesture.js +100 -75
- package/build/lib/commands/index.js +4 -2
- package/build/lib/commands/localization.js +34 -0
- package/build/lib/commands/log.js +52 -11
- package/build/lib/commands/timeouts.js +49 -5
- package/build/lib/commands/web.js +349 -6
- package/build/lib/cookies.js +82 -0
- package/build/lib/desired-caps.js +91 -17
- package/build/lib/device-log/ios-crash-log.js +31 -5
- package/build/lib/device-log/ios-performance-log.js +66 -0
- package/build/lib/driver.js +17 -7
- package/build/lib/simulator-management.js +189 -1
- package/build/lib/utils.js +40 -41
- package/index.js +6 -3
- package/lib/app-utils.js +159 -0
- package/lib/commands/certificate.js +1 -2
- package/lib/commands/context.js +205 -17
- package/lib/commands/element.js +41 -5
- package/lib/commands/execute.js +34 -11
- package/lib/commands/file-movement.js +1 -2
- package/lib/commands/general.js +83 -11
- package/lib/commands/gesture.js +89 -58
- package/lib/commands/index.js +2 -1
- package/lib/commands/localization.js +46 -0
- package/lib/commands/log.js +51 -9
- package/lib/commands/timeouts.js +38 -3
- package/lib/commands/web.js +297 -4
- package/lib/cookies.js +96 -0
- package/lib/desired-caps.js +93 -11
- package/lib/device-log/ios-crash-log.js +31 -5
- package/lib/device-log/ios-performance-log.js +54 -0
- package/lib/driver.js +21 -9
- package/lib/simulator-management.js +171 -2
- package/lib/utils.js +34 -49
- package/package.json +9 -8
package/README.md
CHANGED
|
@@ -111,8 +111,8 @@ Capability | Description
|
|
|
111
111
|
`appium:app` | Full path to the application to be tested (the app must be located on the same machine where the server is running). `.ipa` and `.app` application extensions are supported. Zipped `.app` bundles are supported as well. Could also be an URL to a remote location. If neither of the `app` or `bundleId` capabilities are provided then the driver starts from the Home screen and expects the test to know what to do next. Do not provide both `app` and `browserName` capabilities at once.
|
|
112
112
|
`appium:localizableStringsDir` | Where to look for localizable strings in the application bundle. Defaults to `en.lproj`
|
|
113
113
|
`appium:otherApps` | App or list of apps (as a JSON array) to install prior to running tests. Note that it will not work with iOS real devices. Fore example: `["http://appium.github.io/appium/assets/TestApp9.4.app.zip", "/path/to/app-b.app"]`
|
|
114
|
-
`appium:language` | Language to set for iOS, for example `fr
|
|
115
|
-
`appium:locale` | Locale to set for iOS, for example `fr_CA
|
|
114
|
+
`appium:language` | Language to set for iOS, for example `fr`. Please read [Language IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html) to get more details abuot available values for this capability.
|
|
115
|
+
`appium:locale` | Locale to set for iOS, for example `fr_CA`. Please read [Locale IDs](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPInternational/LanguageandLocaleIDs/LanguageandLocaleIDs.html#//apple_ref/doc/uid/10000171i-CH15-SW9) to get more details abuot available values for this capability.
|
|
116
116
|
`appium:appPushTimeout` | The timeout for application upload in milliseconds. Works for real devices only. The default value is `30000`ms
|
|
117
117
|
|
|
118
118
|
### WebDriverAgent
|
|
@@ -341,7 +341,7 @@ one to select or value selection suing `sendKeys` API does not work because of a
|
|
|
341
341
|
|
|
342
342
|
Name | Type | Required | Description | Example
|
|
343
343
|
--- | --- | --- | --- | ---
|
|
344
|
-
element | string | yes | PickerWheel's internal element id (as hexadecimal hash string) to perform value selection on. The element must be of type XCUIElementTypePickerWheel | abcdef12-1111-2222-3333-444444
|
|
344
|
+
elementId (`element` before version 1.22) | string | yes | PickerWheel's internal element id (as hexadecimal hash string) to perform value selection on. The element must be of type XCUIElementTypePickerWheel | abcdef12-1111-2222-3333-444444
|
|
345
345
|
order | string | yes | Either `next` to select the value next to the current one from the target picker wheel or `previous` to select the previous one. | next
|
|
346
346
|
offset | number | no | The value in range [0.01, 0.5]. It defines how far from picker wheel's center the click should happen. The actual distance is calculated by multiplying this value to the actual picker wheel height. Too small offset value may not change the picker wheel value and too high value may cause the wheel to switch two or more values at once. Usually the optimal value is located in range [0.15, 0.3]. `0.2` by default | 0.15
|
|
347
347
|
|
|
@@ -617,13 +617,15 @@ Check the `+ (id<FBResponsePayload>)handleActiveAppInfo:(FBRouteRequest *)reques
|
|
|
617
617
|
|
|
618
618
|
### mobile: pressButton
|
|
619
619
|
|
|
620
|
-
Emulates press action on the given physical device button.
|
|
620
|
+
Emulates press action on the given physical device button. iOS is [pressButton:](https://developer.apple.com/documentation/xctest/xcuidevice/1619052-pressbutton), tvOS is [pressButton:](https://developer.apple.com/documentation/xctest/xcuiremote/1627475-pressbutton) or [pressButton:forDuration:](https://developer.apple.com/documentation/xctest/xcuiremote/1627476-pressbutton).
|
|
621
|
+
[mobile: performIoHidEvent](#mobile-performiohidevent) calls a more universal API to perform press with duration on any supported device.
|
|
621
622
|
|
|
622
623
|
#### Arguments
|
|
623
624
|
|
|
624
625
|
Name | Type | Required | Description | Example
|
|
625
626
|
--- | --- | --- | --- | ---
|
|
626
627
|
name | string | yes | The name of the button to be pressed. Supported button names for iOS-based devices are (case-insensitive): `home`, `volumeup`, `volumedown`. For tvOS-based devices (case-insensitive): `home`, `up`, `down`, `left`, `right`, `menu`, `playpause`, `select` | home
|
|
628
|
+
durationSeconds | number | no | Duration in float seconds for tvOS-based devices since Appium 1.22.0 | 10
|
|
627
629
|
|
|
628
630
|
### mobile: pushNotification
|
|
629
631
|
|
|
@@ -637,7 +639,7 @@ command for more details.
|
|
|
637
639
|
Name | Type | Required | Description | Example
|
|
638
640
|
--- | --- | --- | --- | ---
|
|
639
641
|
bundleId | string | yes | The bundle identifier of the target application | com.apple.Preferences
|
|
640
|
-
payload | map | yes | Valid Apple Push Notification values. Read the `Create the JSON Payload` topic of the [official Apple documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc) for more details on the payload creation. | `{"aps": {"alert": "This is a simulated notification!", "badge": 3, "sound": "default"} }`
|
|
642
|
+
payload | map | yes | Valid Apple Push Notification values. Read the `Create the JSON Payload` topic of the [official Apple documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification?language=objc) for more details on the payload creation. | `{"aps": {"alert": {"title": "This is a simulated notification!"}, "badge": 3, "sound": "default"} }`
|
|
641
643
|
|
|
642
644
|
### mobile: expectNotification
|
|
643
645
|
|
|
@@ -800,6 +802,28 @@ Name | Type | Required | Description | Example
|
|
|
800
802
|
--- | --- | --- | --- | ---
|
|
801
803
|
remotePath | string | yes | Same value as for `mobile: deleteFile` except of the fact it should be pointing to a folder and should end with a single slash `/` | @com.mycompany.myapp:documents/myfolder/
|
|
802
804
|
|
|
805
|
+
### mobile: configureLocalization
|
|
806
|
+
|
|
807
|
+
Change localization settings on the currently booted Simulator.
|
|
808
|
+
The changed settings are only applied for the *newly started* applications/activities.
|
|
809
|
+
Currently running applications will stay unchanged. This means, for example, that the keyboard
|
|
810
|
+
should be hidden and shown again in order to observe the changed layout, and curresponding
|
|
811
|
+
apps must be restarted in order to observe their interface using the newly set locale/language.
|
|
812
|
+
Be careful while setting the actual arguments since their actual values are not strictly checked.
|
|
813
|
+
This could lead to an unexpected behavior if an incorrect/unsupported language or locale abbreviation is provided.
|
|
814
|
+
|
|
815
|
+
#### Arguments
|
|
816
|
+
|
|
817
|
+
Name | Type | Required | Description | Example
|
|
818
|
+
--- | --- | --- | --- | ---
|
|
819
|
+
keyboard | map | no | On-screen keyboard properties. The `name` key is required and should be set to a valid locale abbreviation. The `layout` key is also required. The `hardware` key is optional and could be omitted or set to `Automated`. You could switch the keyboard layout in system preferences of your booted simulator, run `xcrun simctl spawn booted defaults read .GlobalPreferences.plist`, and inspect the value of `AppleKeyboards` to see possible combinations. | `{"name": "de_CH", "layout": "QWERTZ", "hardware": "Automated"}`
|
|
820
|
+
language | map | no | System language properties. The `name` key is required and should be set to a valid language abbreviation. You could switch the system language in preferences of your booted simulator, run `xcrun simctl spawn booted defaults read .GlobalPreferences.plist`, and inspect the value of `AppleLanguages` to see possible combinations. | `{"name": "zh-Hant-CN"}`
|
|
821
|
+
locale | map | no | System locale properties. The `name` key is required and should be set to a valid language abbreviation. The `calendar`key is optonal and could be set to a valid calendar format name. You could switch the system locale/calendar format in preferences of your booted simulator, run `xcrun simctl spawn booted defaults read .GlobalPreferences.plist`, and inspect the value of `AppleLocale` to see possible combinations. | `{"name": "uk_UA", "calendar": "gregorian"}`
|
|
822
|
+
|
|
823
|
+
#### Returned Result
|
|
824
|
+
|
|
825
|
+
`true` if any of settings has been successfully changed.
|
|
826
|
+
|
|
803
827
|
### mobile: startAudioRecording
|
|
804
828
|
|
|
805
829
|
Records the given hardware audio input into an .mp4 file. You must allow the `audio_record` security feature in order to use this extension. Also it is required that [FFMpeg](https://ffmpeg.org/) is installed on the machibe where Appium server is running.
|
|
@@ -910,24 +934,293 @@ The response looks like `{"value":{"statusBarSize":{"width":414,"height":48},"sc
|
|
|
910
934
|
`statusBarSize` contains status bar dimensions. It is the result of [status bar](https://developer.apple.com/documentation/xctest/xcuielementtypequeryprovider/1500428-statusbars).
|
|
911
935
|
`scale` is [screen scale](https://developer.apple.com/documentation/uikit/uiscreen/1617836-scale).
|
|
912
936
|
|
|
937
|
+
### mobile: swipe
|
|
938
|
+
|
|
939
|
+
This gesture performs a simple "swipe" gesture on the particular screen element or
|
|
940
|
+
on the application element, which is usually the whole screen. This method does not
|
|
941
|
+
accept coordinates and simply emulates single swipe with one finger. It might be
|
|
942
|
+
useful for such cases like album pagination, switching views, etc. More advanced
|
|
943
|
+
cases may require to call [mobile: dragFromToForDuration](#mobile-dragfromtoforduration),
|
|
944
|
+
where one can supply coordinates and duration.
|
|
945
|
+
|
|
946
|
+
#### Arguments
|
|
947
|
+
|
|
948
|
+
Name | Type | Required | Description | Example
|
|
949
|
+
--- | --- | --- | --- | ---
|
|
950
|
+
elementId ("element" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to swipe on. Application element will be used instead if this argument is not provided | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
951
|
+
direction | Either 'up', 'down', 'left' or 'right' | yes | The direction in which to swipe | up
|
|
952
|
+
velocity | number | no | This argument is optional and is only supported since Appium server version 1.19 and Xcode SDK version 11.4+. The value is measured in pixels per second and same values could behave differently on different devices depending on their display density. Higher values make swipe gesture faster (which usually scrolls larger areas if we apply it to a list) and lower values slow it down. Only values greater than zero have effect. | 250
|
|
953
|
+
|
|
954
|
+
#### Examples
|
|
955
|
+
|
|
956
|
+
```java
|
|
957
|
+
// Java
|
|
958
|
+
JavascriptExecutor js = (JavascriptExecutor) driver;
|
|
959
|
+
Map<String, Object> params = new HashMap<>();
|
|
960
|
+
params.put("direction", "down");
|
|
961
|
+
params.put("velocity", 2500);
|
|
962
|
+
params.put("element", ((RemoteWebElement) element).getId());
|
|
963
|
+
js.executeScript("mobile: swipe", params);
|
|
964
|
+
```
|
|
965
|
+
|
|
966
|
+
#### References
|
|
967
|
+
|
|
968
|
+
- [swipeDown](https://developer.apple.com/documentation/xctest/xcuielement/1618664-swipedown?language=objc)
|
|
969
|
+
- [swipeDownWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551694-swipedownwithvelocity?language=objc)
|
|
970
|
+
- [swipeUp](https://developer.apple.com/documentation/xctest/xcuielement/1618667-swipeup?language=objc)
|
|
971
|
+
- [swipeUpWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551697-swipeupwithvelocity?language=objc)
|
|
972
|
+
- [swipeLeft](https://developer.apple.com/documentation/xctest/xcuielement/1618668-swipeleft?language=objc)
|
|
973
|
+
- [swipeLeftWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551695-swipeleftwithvelocity?language=objc)
|
|
974
|
+
- [swipeRight](https://developer.apple.com/documentation/xctest/xcuielement/1618674-swiperight?language=objc)
|
|
975
|
+
- [swipeRightWithVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/3551696-swiperightwithvelocity?language=objc)
|
|
976
|
+
|
|
977
|
+
### mobile: scroll
|
|
978
|
+
|
|
979
|
+
Scrolls the element or the whole screen. Different scrolling strategies are supported.
|
|
980
|
+
Arguments define the choosen strategy: either 'name', 'direction', 'predicateString' or
|
|
981
|
+
'toVisible' in that order. All strategies are exclusive and only one strategy
|
|
982
|
+
can be applied at a single moment of time. Use "mobile: scroll" to emulate precise
|
|
983
|
+
scrolling in tables or collection views, where it is already known to which element
|
|
984
|
+
the scrolling should be performed. Although, there is one known limitation there: in case
|
|
985
|
+
it is necessary to perform too many scroll gestures on parent container to reach the
|
|
986
|
+
necessary child element (tens of them) then the method call may fail.
|
|
987
|
+
_Important_: The implemntation of this extension relies on several undocumented XCTest features, which might not always be reliable. Thus it might *not* always work as expected.
|
|
988
|
+
|
|
989
|
+
#### Arguments
|
|
990
|
+
|
|
991
|
+
Name | Type | Required | Description | Example
|
|
992
|
+
--- | --- | --- | --- | ---
|
|
993
|
+
elementId ("element" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to scroll on (e.g. the container). Application element will be used if this argument is not set | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
994
|
+
name | string | no | The accessibility id of the child element, to which scrolling is performed. The same result can be achieved by setting _predicateString_ argument to 'name == accessibilityId'. Has no effect if _elementId_ is not a container | cell12
|
|
995
|
+
direction | Either 'up', 'down', 'left' or 'right' | yes | The main difference from [swipe](#mobile-swipe) call with the same argument is that _scroll_ will try to move the current viewport exactly to the next/previous page (the term "page" means the content, which fits into a single device screen) | down
|
|
996
|
+
predicateString | string | no | The NSPredicate locator of the child element, to which the scrolling should be performed. Has no effect if _elementId_ is not a container | label == "foo"
|
|
997
|
+
toVisible | boolean | no | If set to _true_ then asks to scroll to the first visible _elementId_ in the parent container. Has no effect if _elementId_ is not set | true
|
|
998
|
+
|
|
999
|
+
#### Examples
|
|
1000
|
+
|
|
1001
|
+
```python
|
|
1002
|
+
# Python
|
|
1003
|
+
driver.execute_script('mobile: scroll', {'direction': 'down'});
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
### mobile: pinch
|
|
1007
|
+
|
|
1008
|
+
Performs pinch gesture on the given element or on the application element.
|
|
1009
|
+
|
|
1010
|
+
#### Arguments
|
|
1011
|
+
|
|
1012
|
+
Name | Type | Required | Description | Example
|
|
1013
|
+
--- | --- | --- | --- | ---
|
|
1014
|
+
elementId ("element" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to pinch on. Application element will be used instead if this parameter is not provided | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1015
|
+
scale | number | yes | Pinch scale of type float. Use a scale between 0 and 1 to "pinch close" or zoom out and a scale greater than 1 to "pinch open" or zoom in. | 0.5
|
|
1016
|
+
velocity | number | yes | The velocity of the pinch in scale factor per second (float value) | 2.2
|
|
1017
|
+
|
|
1018
|
+
#### Examples
|
|
1019
|
+
|
|
1020
|
+
```ruby
|
|
1021
|
+
# Ruby
|
|
1022
|
+
execute_script 'mobile: pinch', scale: 0.5, velocity: 1.1, element: element.ref
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
#### Reference
|
|
1026
|
+
|
|
1027
|
+
[pinchWithScale:velocity:](https://developer.apple.com/documentation/xctest/xcuielement/1618669-pinchwithscale?language=objc)
|
|
1028
|
+
|
|
1029
|
+
### mobile: doubleTap
|
|
1030
|
+
|
|
1031
|
+
Performs double tap gesture on the given element or on the screen.
|
|
1032
|
+
|
|
1033
|
+
#### Arguments
|
|
1034
|
+
|
|
1035
|
+
Name | Type | Required | Description | Example
|
|
1036
|
+
--- | --- | --- | --- | ---
|
|
1037
|
+
elementId ("element" prior to Appium v 1.22) | string | no if x and y are set | The internal element identifier (as hexadecimal hash string) to double tap on | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1038
|
+
x | number | no if elementId is set | Screen x tap coordinate of type float. | 100
|
|
1039
|
+
y | number | no if elementId is set | Screen y tap coordinate of type float. | 100
|
|
1040
|
+
|
|
1041
|
+
#### Examples
|
|
1042
|
+
|
|
1043
|
+
```javascript
|
|
1044
|
+
// javascript
|
|
1045
|
+
driver.execute('mobile: doubleTap', {element: element.value.ELEMENT});
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
### mobile: touchAndHold
|
|
1049
|
+
|
|
1050
|
+
Performs long press gesture on the given element or on the screen.
|
|
1051
|
+
|
|
1052
|
+
#### Arguments
|
|
1053
|
+
|
|
1054
|
+
Name | Type | Required | Description | Example
|
|
1055
|
+
--- | --- | --- | --- | ---
|
|
1056
|
+
elementId ("element" prior to Appium v 1.22) | string | no if x and y are set | The internal element identifier (as hexadecimal hash string) to long tap on | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1057
|
+
duration | number | yes | The float duration of press action in seconds | 1.5
|
|
1058
|
+
x | number | no if elementId is set | Screen x tap coordinate of type float. | 100
|
|
1059
|
+
y | number | no if elementId is set | Screen y tap coordinate of type float. | 100
|
|
1060
|
+
|
|
1061
|
+
#### Examples
|
|
1062
|
+
|
|
1063
|
+
```csharp
|
|
1064
|
+
// c#
|
|
1065
|
+
Dictionary<string, object> tfLongTap = new Dictionary<string, object>();
|
|
1066
|
+
tfLongTap.Add("element", element.Id);
|
|
1067
|
+
tfLongTap.Add("duration", 2.0);
|
|
1068
|
+
((IJavaScriptExecutor)driver).ExecuteScript("mobile: touchAndHold", tfLongTap);
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
#### Reference
|
|
913
1072
|
|
|
1073
|
+
[pressForDuration:](https://developer.apple.com/documentation/xctest/xcuielement/1618663-pressforduration?language=objc)
|
|
914
1074
|
|
|
915
|
-
###
|
|
1075
|
+
### mobile: twoFingerTap
|
|
916
1076
|
|
|
917
|
-
|
|
1077
|
+
Performs two finger tap gesture on the given element or on the application element.
|
|
918
1078
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1079
|
+
#### Arguments
|
|
1080
|
+
|
|
1081
|
+
Name | Type | Required | Description | Example
|
|
1082
|
+
--- | --- | --- | --- | ---
|
|
1083
|
+
elementId ("element" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to tap on. Application element will be used instead if this parameter is not provided | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1084
|
+
|
|
1085
|
+
#### Examples
|
|
1086
|
+
|
|
1087
|
+
```csharp
|
|
1088
|
+
// c#
|
|
1089
|
+
Dictionary<string, object> tfTap = new Dictionary<string, object>();
|
|
1090
|
+
tfTap.Add("element", element.Id);
|
|
1091
|
+
((IJavaScriptExecutor)driver).ExecuteScript("mobile: twoFingerTap", tfTap);
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
#### Reference
|
|
1095
|
+
|
|
1096
|
+
[twoFingerTap](https://developer.apple.com/documentation/xctest/xcuielement/1618675-twofingertap?language=objc)
|
|
1097
|
+
|
|
1098
|
+
### mobile: tap
|
|
1099
|
+
|
|
1100
|
+
Performs tap gesture by coordinates on the given element or on the screen.
|
|
1101
|
+
|
|
1102
|
+
#### Arguments
|
|
1103
|
+
|
|
1104
|
+
Name | Type | Required | Description | Example
|
|
1105
|
+
--- | --- | --- | --- | ---
|
|
1106
|
+
elementId ("element" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to tap on. _x_ and _y_ tap coordinates will be calulated relatively to the current element position on the screen if this argument is provided. Otherwise they should be calculated relatively to the active application element. | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1107
|
+
x | number | yes | Screen x tap coordinate of type float. | 100
|
|
1108
|
+
y | number | yes | Screen y tap coordinate of type float. | 100
|
|
1109
|
+
|
|
1110
|
+
### mobile: dragFromToForDuration
|
|
1111
|
+
|
|
1112
|
+
Performs drag and drop gesture by coordinates. This can be done either on an element or
|
|
1113
|
+
on the screen
|
|
1114
|
+
|
|
1115
|
+
#### Arguments
|
|
1116
|
+
|
|
1117
|
+
Name | Type | Required | Description | Example
|
|
1118
|
+
--- | --- | --- | --- | ---
|
|
1119
|
+
elementId ("element" prior to Appium v 1.22) | string | no | The internal element identifier (as hexadecimal hash string) to perform drag on. All the coordinates will be calculated relatively this this element position on the screen. Absolute screen coordinates are expected if this argument is not set | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1120
|
+
duration | number | yes | Float number of seconds in range [0.5, 60]. How long the tap gesture at starting drag point should be before to start dragging | 5.3
|
|
1121
|
+
fromX | number | yes | The x coordinate of starting drag point | 100
|
|
1122
|
+
fromY | number | yes | The y coordinate of starting drag point | 100
|
|
1123
|
+
toX | number | yes | The x coordinate of ending drag point | 200
|
|
1124
|
+
toY | number | yes | The y coordinate of ending drag point | 200
|
|
1125
|
+
|
|
1126
|
+
#### Examples
|
|
1127
|
+
|
|
1128
|
+
```java
|
|
1129
|
+
// Java
|
|
1130
|
+
JavascriptExecutor js = (JavascriptExecutor) driver;
|
|
1131
|
+
Map<String, Object> params = new HashMap<>();
|
|
1132
|
+
params.put("duration", 1.0);
|
|
1133
|
+
params.put("fromX", 100);
|
|
1134
|
+
params.put("fromY", 100);
|
|
1135
|
+
params.put("toX", 200);
|
|
1136
|
+
params.put("toY", 200);
|
|
1137
|
+
params.put("element", ((RemoteWebElement) element).getId());
|
|
1138
|
+
js.executeScript("mobile: dragFromToForDuration", params);
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
#### Reference
|
|
1142
|
+
|
|
1143
|
+
[clickForDuration:thenDragToElement:](https://developer.apple.com/documentation/xctest/xcuielement/1500989-clickforduration?language=objc)
|
|
1144
|
+
|
|
1145
|
+
### mobile: selectPickerWheelValue
|
|
1146
|
+
|
|
1147
|
+
Performs selection of the next or previous picker wheel value. This might
|
|
1148
|
+
be useful if these values are populated dynamically, so you don't know which
|
|
1149
|
+
one to select or value selection does not work because of XCTest bug.
|
|
1150
|
+
|
|
1151
|
+
#### Arguments
|
|
1152
|
+
|
|
1153
|
+
Name | Type | Required | Description | Example
|
|
1154
|
+
--- | --- | --- | --- | ---
|
|
1155
|
+
elementId ("element" prior to Appium v 1.22) | string | yes | PickerWheel's internal element id (as hexadecimal hash string) to perform value selection on. The element must be of type XCUIElementTypePickerWheel | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1156
|
+
order | string | yes | Either _next_ to select the value next to the current one from the target picker wheel or _previous_ to select the previous one | next
|
|
1157
|
+
offset | number | no | The value in range [0.01, 0.5]. It defines how far from picker wheel's center the click should happen. The actual distance is calculated by multiplying this value to the actual picker wheel height. Too small offset value may not change the picker wheel value and too high value may cause the wheel to switch two or more values at once. Usually the optimal value is located in range [0.15, 0.3]. _0.2_ by default | 0.3
|
|
1158
|
+
|
|
1159
|
+
#### Examples
|
|
1160
|
+
|
|
1161
|
+
```java
|
|
1162
|
+
// Java
|
|
1163
|
+
JavascriptExecutor js = (JavascriptExecutor) driver;
|
|
1164
|
+
Map<String, Object> params = new HashMap<>();
|
|
1165
|
+
params.put("order", "next");
|
|
1166
|
+
params.put("offset", 0.15);
|
|
1167
|
+
params.put("element", ((RemoteWebElement) element).getId());
|
|
1168
|
+
js.executeScript("mobile: selectPickerWheelValue", params);
|
|
1169
|
+
```
|
|
1170
|
+
|
|
1171
|
+
### mobile: rotateElement
|
|
1172
|
+
|
|
1173
|
+
Performs [rotate](https://developer.apple.com/documentation/xctest/xcuielement/1618665-rotate?language=objc) gesture on the given element.
|
|
1174
|
+
|
|
1175
|
+
#### Arguments
|
|
1176
|
+
|
|
1177
|
+
Name | Type | Required | Description | Example
|
|
1178
|
+
--- | --- | --- | --- | ---
|
|
1179
|
+
elementId ("element" prior to Appium v 1.22) | string | yes | Internal element id (as hexadecimal hash string) to perform rotation on | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1180
|
+
rotation | number | yes | The rotation of the gesture in radians | Math.PI
|
|
1181
|
+
velocity | number | yes | The velocity of the rotation gesture in radians per second | Math.PI / 4
|
|
1182
|
+
|
|
1183
|
+
#### Examples
|
|
1184
|
+
|
|
1185
|
+
```java
|
|
1186
|
+
// Java
|
|
1187
|
+
JavascriptExecutor js = (JavascriptExecutor) driver;
|
|
1188
|
+
js.executeScript("mobile: rotateElement", ImmutableMap.of(
|
|
1189
|
+
// rotate clockwise, 90 degrees
|
|
1190
|
+
"rotation", -Math.PI / 2,
|
|
1191
|
+
// in approximately two seconds
|
|
1192
|
+
"velocity", Math.PI / 4,
|
|
1193
|
+
"element", ((RemoteWebElement) element).getId()
|
|
1194
|
+
));
|
|
1195
|
+
```
|
|
1196
|
+
|
|
1197
|
+
#### Reference
|
|
1198
|
+
|
|
1199
|
+
[rotate:withVelocity:](https://developer.apple.com/documentation/xctest/xcuielement/1618665-rotate?language=objc)
|
|
1200
|
+
|
|
1201
|
+
### mobile: tapWithNumberOfTaps
|
|
1202
|
+
|
|
1203
|
+
Sends one or more taps with one or more touch points since Appium 1.17.1.
|
|
1204
|
+
|
|
1205
|
+
#### Arguments
|
|
1206
|
+
|
|
1207
|
+
Name | Type | Required | Description | Example
|
|
1208
|
+
--- | --- | --- | --- | ---
|
|
1209
|
+
elementId ("element" prior to Appium v 1.22) | string | yes | The internal element identifier (as hexadecimal hash string) to perform one or more taps. | fe50b60b-916d-420b-8728-ee2072ec53eb
|
|
1210
|
+
numberOfTaps | number | yes | The number of taps | 2
|
|
1211
|
+
numberOfTouches | number | yes | The number of touch points | 2
|
|
1212
|
+
|
|
1213
|
+
#### Examples
|
|
1214
|
+
|
|
1215
|
+
```ruby
|
|
1216
|
+
# Ruby
|
|
1217
|
+
e = @driver.find_element :id, 'target element'
|
|
1218
|
+
# Taps the element with a single touch point twice
|
|
1219
|
+
@driver.execute_script 'mobile: tapWithNumberOfTaps', {element: e.ref, numberOfTaps: 2, numberOfTouches: 1}
|
|
1220
|
+
```
|
|
929
1221
|
|
|
930
|
-
|
|
1222
|
+
#### Reference
|
|
1223
|
+
[tapWithNumberOfTaps:numberOfTouches:](https://developer.apple.com/documentation/xctest/xcuielement/1618671-tapwithnumberoftaps)
|
|
931
1224
|
|
|
932
1225
|
|
|
933
1226
|
## Known issues
|
package/build/index.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
|
|
4
|
-
|
|
5
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
6
|
-
|
|
7
3
|
Object.defineProperty(exports, "__esModule", {
|
|
8
4
|
value: true
|
|
9
5
|
});
|
|
@@ -11,14 +7,16 @@ exports.default = exports.startServer = exports.XCUITestDriver = void 0;
|
|
|
11
7
|
|
|
12
8
|
require("source-map-support/register");
|
|
13
9
|
|
|
14
|
-
var _yargs = _interopRequireDefault(require("yargs"));
|
|
15
|
-
|
|
16
10
|
var _asyncbox = require("asyncbox");
|
|
17
11
|
|
|
18
12
|
var driver = _interopRequireWildcard(require("./lib/driver"));
|
|
19
13
|
|
|
20
14
|
var server = _interopRequireWildcard(require("./lib/server"));
|
|
21
15
|
|
|
16
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
17
|
+
|
|
18
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
19
|
+
|
|
22
20
|
const {
|
|
23
21
|
XCUITestDriver
|
|
24
22
|
} = driver;
|
|
@@ -31,8 +29,13 @@ const DEFAULT_HOST = 'localhost';
|
|
|
31
29
|
const DEFAULT_PORT = 4723;
|
|
32
30
|
|
|
33
31
|
async function main() {
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
const getArgValue = argName => {
|
|
33
|
+
const argIndex = process.argv.indexOf(argName);
|
|
34
|
+
return argIndex > 0 ? process.argv[argIndex + 1] : null;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const port = parseInt(getArgValue('--port'), 10) || DEFAULT_PORT;
|
|
38
|
+
const host = getArgValue('--host') || DEFAULT_HOST;
|
|
36
39
|
return await startServer(port, host);
|
|
37
40
|
}
|
|
38
41
|
|
|
@@ -44,4 +47,4 @@ var _default = XCUITestDriver;
|
|
|
44
47
|
exports.default = _default;require('source-map-support').install();
|
|
45
48
|
|
|
46
49
|
|
|
47
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,
|
|
50
|
+
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbIlhDVUlUZXN0RHJpdmVyIiwiZHJpdmVyIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXIiLCJERUZBVUxUX0hPU1QiLCJERUZBVUxUX1BPUlQiLCJtYWluIiwiZ2V0QXJnVmFsdWUiLCJhcmdOYW1lIiwiYXJnSW5kZXgiLCJwcm9jZXNzIiwiYXJndiIsImluZGV4T2YiLCJwb3J0IiwicGFyc2VJbnQiLCJob3N0IiwicmVxdWlyZSIsIm1vZHVsZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBRUE7O0FBQ0E7O0FBQ0E7Ozs7OztBQUdBLE1BQU07QUFBRUEsRUFBQUE7QUFBRixJQUFxQkMsTUFBM0I7O0FBQ0EsTUFBTTtBQUFFQyxFQUFBQTtBQUFGLElBQWtCQyxNQUF4Qjs7QUFFQSxNQUFNQyxZQUFZLEdBQUcsV0FBckI7QUFDQSxNQUFNQyxZQUFZLEdBQUcsSUFBckI7O0FBRUEsZUFBZUMsSUFBZixHQUF1QjtBQUNyQixRQUFNQyxXQUFXLEdBQUlDLE9BQUQsSUFBYTtBQUMvQixVQUFNQyxRQUFRLEdBQUdDLE9BQU8sQ0FBQ0MsSUFBUixDQUFhQyxPQUFiLENBQXFCSixPQUFyQixDQUFqQjtBQUNBLFdBQU9DLFFBQVEsR0FBRyxDQUFYLEdBQWVDLE9BQU8sQ0FBQ0MsSUFBUixDQUFhRixRQUFRLEdBQUcsQ0FBeEIsQ0FBZixHQUE0QyxJQUFuRDtBQUNELEdBSEQ7O0FBSUEsUUFBTUksSUFBSSxHQUFHQyxRQUFRLENBQUNQLFdBQVcsQ0FBQyxRQUFELENBQVosRUFBd0IsRUFBeEIsQ0FBUixJQUF1Q0YsWUFBcEQ7QUFDQSxRQUFNVSxJQUFJLEdBQUdSLFdBQVcsQ0FBQyxRQUFELENBQVgsSUFBeUJILFlBQXRDO0FBQ0EsU0FBTyxNQUFNRixXQUFXLENBQUNXLElBQUQsRUFBT0UsSUFBUCxDQUF4QjtBQUNEOztBQUVELElBQUlDLE9BQU8sQ0FBQ1YsSUFBUixLQUFpQlcsTUFBckIsRUFBNkI7QUFDM0IsMEJBQVNYLElBQVQ7QUFDRDs7ZUFHY04sYyIsInNvdXJjZXNDb250ZW50IjpbIi8vIHRyYW5zcGlsZTptYWluXG5cbmltcG9ydCB7IGFzeW5jaWZ5IH0gZnJvbSAnYXN5bmNib3gnO1xuaW1wb3J0ICogYXMgZHJpdmVyIGZyb20gJy4vbGliL2RyaXZlcic7XG5pbXBvcnQgKiBhcyBzZXJ2ZXIgZnJvbSAnLi9saWIvc2VydmVyJztcblxuXG5jb25zdCB7IFhDVUlUZXN0RHJpdmVyIH0gPSBkcml2ZXI7XG5jb25zdCB7IHN0YXJ0U2VydmVyIH0gPSBzZXJ2ZXI7XG5cbmNvbnN0IERFRkFVTFRfSE9TVCA9ICdsb2NhbGhvc3QnO1xuY29uc3QgREVGQVVMVF9QT1JUID0gNDcyMztcblxuYXN5bmMgZnVuY3Rpb24gbWFpbiAoKSB7XG4gIGNvbnN0IGdldEFyZ1ZhbHVlID0gKGFyZ05hbWUpID0+IHtcbiAgICBjb25zdCBhcmdJbmRleCA9IHByb2Nlc3MuYXJndi5pbmRleE9mKGFyZ05hbWUpO1xuICAgIHJldHVybiBhcmdJbmRleCA+IDAgPyBwcm9jZXNzLmFyZ3ZbYXJnSW5kZXggKyAxXSA6IG51bGw7XG4gIH07XG4gIGNvbnN0IHBvcnQgPSBwYXJzZUludChnZXRBcmdWYWx1ZSgnLS1wb3J0JyksIDEwKSB8fCBERUZBVUxUX1BPUlQ7XG4gIGNvbnN0IGhvc3QgPSBnZXRBcmdWYWx1ZSgnLS1ob3N0JykgfHwgREVGQVVMVF9IT1NUO1xuICByZXR1cm4gYXdhaXQgc3RhcnRTZXJ2ZXIocG9ydCwgaG9zdCk7XG59XG5cbmlmIChyZXF1aXJlLm1haW4gPT09IG1vZHVsZSkge1xuICBhc3luY2lmeShtYWluKTtcbn1cblxuZXhwb3J0IHsgWENVSVRlc3REcml2ZXIsIHN0YXJ0U2VydmVyIH07XG5leHBvcnQgZGVmYXVsdCBYQ1VJVGVzdERyaXZlcjtcbiJdLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiLi4ifQ==
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
Object.defineProperty(exports, "__esModule", {
|
|
6
|
+
value: true
|
|
7
|
+
});
|
|
8
|
+
exports.extractBundleId = extractBundleId;
|
|
9
|
+
exports.verifyApplicationPlatform = verifyApplicationPlatform;
|
|
10
|
+
exports.parseLocalizableStrings = parseLocalizableStrings;
|
|
11
|
+
|
|
12
|
+
require("source-map-support/register");
|
|
13
|
+
|
|
14
|
+
var _lodash = _interopRequireDefault(require("lodash"));
|
|
15
|
+
|
|
16
|
+
var _path = _interopRequireDefault(require("path"));
|
|
17
|
+
|
|
18
|
+
var _appiumSupport = require("appium-support");
|
|
19
|
+
|
|
20
|
+
var _logger = _interopRequireDefault(require("./logger.js"));
|
|
21
|
+
|
|
22
|
+
const STRINGSDICT_RESOURCE = '.stringsdict';
|
|
23
|
+
const STRINGS_RESOURCE = '.strings';
|
|
24
|
+
|
|
25
|
+
async function extractPlistEntry(app, entryName) {
|
|
26
|
+
const plistPath = _path.default.resolve(app, 'Info.plist');
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
return (await _appiumSupport.plist.parsePlistFile(plistPath))[entryName];
|
|
30
|
+
} catch (err) {
|
|
31
|
+
throw new Error(`Could not extract Info.plist from '${_path.default.basename(app)}': ${err.message}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function extractBundleId(app) {
|
|
36
|
+
const bundleId = await extractPlistEntry(app, 'CFBundleIdentifier');
|
|
37
|
+
|
|
38
|
+
_logger.default.debug(`Getting bundle ID from app '${app}': '${bundleId}'`);
|
|
39
|
+
|
|
40
|
+
return bundleId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function verifyApplicationPlatform(app, expectedPlatform) {
|
|
44
|
+
_logger.default.debug('Verifying application platform');
|
|
45
|
+
|
|
46
|
+
let supportedPlatforms;
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
supportedPlatforms = await extractPlistEntry(app, 'CFBundleSupportedPlatforms');
|
|
50
|
+
} catch (err) {
|
|
51
|
+
_logger.default.debug(err.message);
|
|
52
|
+
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_logger.default.debug(`CFBundleSupportedPlatforms: ${JSON.stringify(supportedPlatforms)}`);
|
|
57
|
+
|
|
58
|
+
if (!_lodash.default.isArray(supportedPlatforms)) {
|
|
59
|
+
_logger.default.debug(`CFBundleSupportedPlatforms key does not exist in '${_path.default.basename(app)}'`);
|
|
60
|
+
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const {
|
|
65
|
+
isSimulator,
|
|
66
|
+
isTvOS
|
|
67
|
+
} = expectedPlatform;
|
|
68
|
+
const prefix = isTvOS ? 'AppleTV' : 'iPhone';
|
|
69
|
+
const suffix = isSimulator ? 'Simulator' : 'OS';
|
|
70
|
+
const dstPlatform = `${prefix}${suffix}`;
|
|
71
|
+
|
|
72
|
+
if (!supportedPlatforms.includes(dstPlatform)) {
|
|
73
|
+
throw new Error(`${isSimulator ? 'Simulator' : 'Real device'} architecture is unsupported by the '${app}' application. ` + `Make sure the correct deployment target has been selected for its compilation in Xcode.`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function readResource(resourcePath) {
|
|
78
|
+
const data = await _appiumSupport.plist.parsePlistFile(resourcePath);
|
|
79
|
+
const result = {};
|
|
80
|
+
|
|
81
|
+
for (const [key, value] of _lodash.default.toPairs(data)) {
|
|
82
|
+
result[key] = _lodash.default.isString(value) ? value : JSON.stringify(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function parseLocalizableStrings(opts) {
|
|
89
|
+
const {
|
|
90
|
+
app,
|
|
91
|
+
language = 'en',
|
|
92
|
+
localizableStringsDir,
|
|
93
|
+
stringFile,
|
|
94
|
+
strictMode
|
|
95
|
+
} = opts;
|
|
96
|
+
|
|
97
|
+
if (!app) {
|
|
98
|
+
const message = `Strings extraction is not supported if 'app' capability is not set`;
|
|
99
|
+
|
|
100
|
+
if (strictMode) {
|
|
101
|
+
throw new Error(message);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
_logger.default.info(message);
|
|
105
|
+
|
|
106
|
+
return {};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let lprojRoot;
|
|
110
|
+
|
|
111
|
+
for (const subfolder of [`${language}.lproj`, localizableStringsDir, '']) {
|
|
112
|
+
lprojRoot = _path.default.resolve(app, subfolder);
|
|
113
|
+
|
|
114
|
+
if (await _appiumSupport.fs.exists(lprojRoot)) {
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const message = `No '${lprojRoot}' resources folder has been found`;
|
|
119
|
+
|
|
120
|
+
if (strictMode) {
|
|
121
|
+
throw new Error(message);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
_logger.default.debug(message);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
_logger.default.info(`Will extract resource strings from '${lprojRoot}'`);
|
|
128
|
+
|
|
129
|
+
const resourcePaths = [];
|
|
130
|
+
|
|
131
|
+
if (stringFile) {
|
|
132
|
+
const dstPath = _path.default.resolve(lprojRoot, stringFile);
|
|
133
|
+
|
|
134
|
+
if (await _appiumSupport.fs.exists(dstPath)) {
|
|
135
|
+
resourcePaths.push(dstPath);
|
|
136
|
+
} else {
|
|
137
|
+
const message = `No '${dstPath}' resource file has been found for '${app}'`;
|
|
138
|
+
|
|
139
|
+
if (strictMode) {
|
|
140
|
+
throw new Error(message);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
_logger.default.info(message);
|
|
144
|
+
|
|
145
|
+
_logger.default.info(`Getting all the available strings from '${lprojRoot}'`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (_lodash.default.isEmpty(resourcePaths) && (await _appiumSupport.fs.exists(lprojRoot))) {
|
|
150
|
+
const resourceFiles = (await _appiumSupport.fs.readdir(lprojRoot)).filter(name => _lodash.default.some([STRINGS_RESOURCE, STRINGSDICT_RESOURCE], x => name.endsWith(x))).map(name => _path.default.resolve(lprojRoot, name));
|
|
151
|
+
resourcePaths.push(...resourceFiles);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
_logger.default.info(`Got ${resourcePaths.length} resource file(s) in '${lprojRoot}'`);
|
|
155
|
+
|
|
156
|
+
if (_lodash.default.isEmpty(resourcePaths)) {
|
|
157
|
+
return {};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const resultStrings = {};
|
|
161
|
+
|
|
162
|
+
const toAbsolutePath = function (p) {
|
|
163
|
+
return _path.default.isAbsolute(p) ? p : _path.default.resolve(process.cwd(), p);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
for (const resourcePath of resourcePaths) {
|
|
167
|
+
if (!_appiumSupport.util.isSubPath(toAbsolutePath(resourcePath), toAbsolutePath(app))) {
|
|
168
|
+
throw new Error(`'${resourcePath}' is expected to be located under '${app}'`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
try {
|
|
172
|
+
const data = await readResource(resourcePath);
|
|
173
|
+
|
|
174
|
+
_logger.default.debug(`Parsed ${_lodash.default.keys(data).length} string(s) from '${resourcePath}'`);
|
|
175
|
+
|
|
176
|
+
_lodash.default.merge(resultStrings, data);
|
|
177
|
+
} catch (e) {
|
|
178
|
+
_logger.default.warn(`Cannot parse '${resourcePath}' resource. Original error: ${e.message}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
_logger.default.info(`Got ${_lodash.default.keys(resultStrings).length} string(s) from '${lprojRoot}'`);
|
|
183
|
+
|
|
184
|
+
return resultStrings;
|
|
185
|
+
}require('source-map-support').install();
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImxpYi9hcHAtdXRpbHMuanMiXSwibmFtZXMiOlsiU1RSSU5HU0RJQ1RfUkVTT1VSQ0UiLCJTVFJJTkdTX1JFU09VUkNFIiwiZXh0cmFjdFBsaXN0RW50cnkiLCJhcHAiLCJlbnRyeU5hbWUiLCJwbGlzdFBhdGgiLCJwYXRoIiwicmVzb2x2ZSIsInBsaXN0IiwicGFyc2VQbGlzdEZpbGUiLCJlcnIiLCJFcnJvciIsImJhc2VuYW1lIiwibWVzc2FnZSIsImV4dHJhY3RCdW5kbGVJZCIsImJ1bmRsZUlkIiwibG9nIiwiZGVidWciLCJ2ZXJpZnlBcHBsaWNhdGlvblBsYXRmb3JtIiwiZXhwZWN0ZWRQbGF0Zm9ybSIsInN1cHBvcnRlZFBsYXRmb3JtcyIsIkpTT04iLCJzdHJpbmdpZnkiLCJfIiwiaXNBcnJheSIsImlzU2ltdWxhdG9yIiwiaXNUdk9TIiwicHJlZml4Iiwic3VmZml4IiwiZHN0UGxhdGZvcm0iLCJpbmNsdWRlcyIsInJlYWRSZXNvdXJjZSIsInJlc291cmNlUGF0aCIsImRhdGEiLCJyZXN1bHQiLCJrZXkiLCJ2YWx1ZSIsInRvUGFpcnMiLCJpc1N0cmluZyIsInBhcnNlTG9jYWxpemFibGVTdHJpbmdzIiwib3B0cyIsImxhbmd1YWdlIiwibG9jYWxpemFibGVTdHJpbmdzRGlyIiwic3RyaW5nRmlsZSIsInN0cmljdE1vZGUiLCJpbmZvIiwibHByb2pSb290Iiwic3ViZm9sZGVyIiwiZnMiLCJleGlzdHMiLCJyZXNvdXJjZVBhdGhzIiwiZHN0UGF0aCIsInB1c2giLCJpc0VtcHR5IiwicmVzb3VyY2VGaWxlcyIsInJlYWRkaXIiLCJmaWx0ZXIiLCJuYW1lIiwic29tZSIsIngiLCJlbmRzV2l0aCIsIm1hcCIsImxlbmd0aCIsInJlc3VsdFN0cmluZ3MiLCJ0b0Fic29sdXRlUGF0aCIsInAiLCJpc0Fic29sdXRlIiwicHJvY2VzcyIsImN3ZCIsInV0aWwiLCJpc1N1YlBhdGgiLCJrZXlzIiwibWVyZ2UiLCJlIiwid2FybiJdLCJtYXBwaW5ncyI6Ijs7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QUs0RCxVQUFMLENBQWdCRCxDQUFoQixJQUFxQkEsQ0FBckIsR0FBeUIzRCxjQUFLQyxPQUFMLENBQWE0RCxPQUFPLENBQUNDLEdBQVIsRUFBYixFQUE0QkgsQ0FBNUIsQ0FBaEM7QUFDRCxHQUZEOztBQUdBLE9BQUssTUFBTWpDLFlBQVgsSUFBMkJrQixhQUEzQixFQUEwQztBQUN4QyxRQUFJLENBQUNtQixvQkFBS0MsU0FBTCxDQUFlTixjQUFjLENBQUNoQyxZQUFELENBQTdCLEVBQTZDZ0MsY0FBYyxDQUFDN0QsR0FBRCxDQUEzRCxDQUFMLEVBQXdFO0FBRXRFLFlBQU0sSUFBSVEsS0FBSixDQUFXLElBQUdxQixZQUFhLHNDQUFxQzdCLEdBQUksR0FBcEUsQ0FBTjtBQUNEOztBQUNELFFBQUk7QUFDRixZQUFNOEIsSUFBSSxHQUFHLE1BQU1GLFlBQVksQ0FBQ0MsWUFBRCxDQUEvQjs7QUFDQWhCLHNCQUFJQyxLQUFKLENBQVcsVUFBU00sZ0JBQUVnRCxJQUFGLENBQU90QyxJQUFQLEVBQWE2QixNQUFPLG9CQUFtQjlCLFlBQWEsR0FBeEU7O0FBQ0FULHNCQUFFaUQsS0FBRixDQUFRVCxhQUFSLEVBQXVCOUIsSUFBdkI7QUFDRCxLQUpELENBSUUsT0FBT3dDLENBQVAsRUFBVTtBQUNWekQsc0JBQUkwRCxJQUFKLENBQVUsaUJBQWdCMUMsWUFBYSwrQkFBOEJ5QyxDQUFDLENBQUM1RCxPQUFRLEVBQS9FO0FBQ0Q7QUFDRjs7QUFFREcsa0JBQUk2QixJQUFKLENBQVUsT0FBTXRCLGdCQUFFZ0QsSUFBRixDQUFPUixhQUFQLEVBQXNCRCxNQUFPLG9CQUFtQmhCLFNBQVUsR0FBMUU7O0FBQ0EsU0FBT2lCLGFBQVA7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IHBsaXN0LCBmcywgdXRpbCB9IGZyb20gJ2FwcGl1bS1zdXBwb3J0JztcbmltcG9ydCBsb2cgZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5jb25zdCBTVFJJTkdTRElDVF9SRVNPVVJDRSA9ICcuc3RyaW5nc2RpY3QnO1xuY29uc3QgU1RSSU5HU19SRVNPVVJDRSA9ICcuc3RyaW5ncyc7XG5cblxuYXN5bmMgZnVuY3Rpb24gZXh0cmFjdFBsaXN0RW50cnkgKGFwcCwgZW50cnlOYW1lKSB7XG4gIGNvbnN0IHBsaXN0UGF0aCA9IHBhdGgucmVzb2x2ZShhcHAsICdJbmZvLnBsaXN0Jyk7XG4gIHRyeSB7XG4gICAgcmV0dXJuIChhd2FpdCBwbGlzdC5wYXJzZVBsaXN0RmlsZShwbGlzdFBhdGgpKVtlbnRyeU5hbWVdO1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENvdWxkIG5vdCBleHRyYWN0IEluZm8ucGxpc3QgZnJvbSAnJHtwYXRoLmJhc2VuYW1lKGFwcCl9JzogJHtlcnIubWVzc2FnZX1gKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBleHRyYWN0QnVuZGxlSWQgKGFwcCkge1xuICBjb25zdCBidW5kbGVJZCA9IGF3YWl0IGV4dHJhY3RQbGlzdEVudHJ5KGFwcCwgJ0NGQnVuZGxlSWRlbnRpZmllcicpO1xuICBsb2cuZGVidWcoYEdldHRpbmcgYnVuZGxlIElEIGZyb20gYXBwICcke2FwcH0nOiAnJHtidW5kbGVJZH0nYCk7XG4gIHJldHVybiBidW5kbGVJZDtcbn1cblxuLyoqXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBQbGF0Zm9ybU9wdHNcbiAqXG4gKiBAcHJvcGVydHkge2Jvb2xlYW59IGlzU2ltdWxhdG9yIC0gV2hldGhlciB0aGUgZGVzdGluYXRpb24gcGxhdGZvcm0gaXMgYSBTaW11bGF0b3JcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gaXNUdk9TIC0gV2hldGhlciB0aGUgZGVzdGluYXRpb24gcGxhdGZvcm0gaXMgYSBTaW11bGF0b3JcbiAqL1xuXG4vKipcbiAqIFZlcmlmeSB3aGV0aGVyIHRoZSBnaXZlbiBhcHBsaWNhdGlvbiBpcyBjb21wYXRpYmxlIHRvIHRoZVxuICogcGxhdGZvcm0gd2hlcmUgaXQgaXMgZ29pbmcgdG8gYmUgaW5zdGFsbGVkIGFuZCB0ZXN0ZWQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFwcCAtIFRoZSBhY3R1YWwgcGF0aCB0byB0aGUgYXBwbGljYXRpb24gYnVuZGxlXG4gKiBAcGFyYW0ge1BsYXRmb3JtT3B0c30gZXhwZWN0ZWRQbGF0Zm9ybVxuICogQHRocm93cyB7RXJyb3J9IElmIGJ1bmRsZSBhcmNoaXRlY3R1cmUgZG9lcyBub3QgbWF0Y2ggdGhlIGV4cGVjdGVkIGRldmljZSBhcmNoaXRlY3R1cmUuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHZlcmlmeUFwcGxpY2F0aW9uUGxhdGZvcm0gKGFwcCwgZXhwZWN0ZWRQbGF0Zm9ybSkge1xuICBsb2cuZGVidWcoJ1ZlcmlmeWluZyBhcHBsaWNhdGlvbiBwbGF0Zm9ybScpO1xuXG4gIGxldCBzdXBwb3J0ZWRQbGF0Zm9ybXM7XG4gIHRyeSB7XG4gICAgc3VwcG9ydGVkUGxhdGZvcm1zID0gYXdhaXQgZXh0cmFjdFBsaXN0RW50cnkoYXBwLCAnQ0ZCdW5kbGVTdXBwb3J0ZWRQbGF0Zm9ybXMnKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgbG9nLmRlYnVnKGVyci5tZXNzYWdlKTtcbiAgICByZXR1cm47XG4gIH1cbiAgbG9nLmRlYnVnKGBDRkJ1bmRsZVN1cHBvcnRlZFBsYXRmb3JtczogJHtKU09OLnN0cmluZ2lmeShzdXBwb3J0ZWRQbGF0Zm9ybXMpfWApO1xuICBpZiAoIV8uaXNBcnJheShzdXBwb3J0ZWRQbGF0Zm9ybXMpKSB7XG4gICAgbG9nLmRlYnVnKGBDRkJ1bmRsZVN1cHBvcnRlZFBsYXRmb3JtcyBrZXkgZG9lcyBub3QgZXhpc3QgaW4gJyR7cGF0aC5iYXNlbmFtZShhcHApfSdgKTtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCB7XG4gICAgaXNTaW11bGF0b3IsXG4gICAgaXNUdk9TLFxuICB9ID0gZXhwZWN0ZWRQbGF0Zm9ybTtcbiAgY29uc3QgcHJlZml4ID0gaXNUdk9TID8gJ0FwcGxlVFYnIDogJ2lQaG9uZSc7XG4gIGNvbnN0IHN1ZmZpeCA9IGlzU2ltdWxhdG9yID8gJ1NpbXVsYXRvcicgOiAnT1MnO1xuICBjb25zdCBkc3RQbGF0Zm9ybSA9IGAke3ByZWZpeH0ke3N1ZmZpeH1gO1xuICBpZiAoIXN1cHBvcnRlZFBsYXRmb3Jtcy5pbmNsdWRlcyhkc3RQbGF0Zm9ybSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYCR7aXNTaW11bGF0b3IgPyAnU2ltdWxhdG9yJyA6ICdSZWFsIGRldmljZSd9IGFyY2hpdGVjdHVyZSBpcyB1bnN1cHBvcnRlZCBieSB0aGUgJyR7YXBwfScgYXBwbGljYXRpb24uIGAgK1xuICAgICAgYE1ha2Ugc3VyZSB0aGUgY29ycmVjdCBkZXBsb3ltZW50IHRhcmdldCBoYXMgYmVlbiBzZWxlY3RlZCBmb3IgaXRzIGNvbXBpbGF0aW9uIGluIFhjb2RlLmApO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJlYWRSZXNvdXJjZSAocmVzb3VyY2VQYXRoKSB7XG4gIGNvbnN0IGRhdGEgPSBhd2FpdCBwbGlzdC5wYXJzZVBsaXN0RmlsZShyZXNvdXJjZVBhdGgpO1xuICBjb25zdCByZXN1bHQgPSB7fTtcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgXy50b1BhaXJzKGRhdGEpKSB7XG4gICAgcmVzdWx0W2tleV0gPSBfLmlzU3RyaW5nKHZhbHVlKSA/IHZhbHVlIDogSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHBhcnNlTG9jYWxpemFibGVTdHJpbmdzIChvcHRzKSB7XG4gIGNvbnN0IHtcbiAgICBhcHAsXG4gICAgbGFuZ3VhZ2UgPSAnZW4nLFxuICAgIGxvY2FsaXphYmxlU3RyaW5nc0RpcixcbiAgICBzdHJpbmdGaWxlLFxuICAgIHN0cmljdE1vZGUsXG4gIH0gPSBvcHRzO1xuXG4gIGlmICghYXBwKSB7XG4gICAgY29uc3QgbWVzc2FnZSA9IGBTdHJpbmdzIGV4dHJhY3Rpb24gaXMgbm90IHN1cHBvcnRlZCBpZiAnYXBwJyBjYXBhYmlsaXR5IGlzIG5vdCBzZXRgO1xuICAgIGlmIChzdHJpY3RNb2RlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgfVxuICAgIGxvZy5pbmZvKG1lc3NhZ2UpO1xuICAgIHJldHVybiB7fTtcbiAgfVxuXG4gIGxldCBscHJvalJvb3Q7XG4gIGZvciAoY29uc3Qgc3ViZm9sZGVyIG9mIFtgJHtsYW5ndWFnZX0ubHByb2pgLCBsb2NhbGl6YWJsZVN0cmluZ3NEaXIsICcnXSkge1xuICAgIGxwcm9qUm9vdCA9IHBhdGgucmVzb2x2ZShhcHAsIHN1YmZvbGRlcik7XG4gICAgaWYgKGF3YWl0IGZzLmV4aXN0cyhscHJvalJvb3QpKSB7XG4gICAgICBicmVhaztcbiAgICB9XG4gICAgY29uc3QgbWVzc2FnZSA9IGBObyAnJHtscHJvalJvb3R9JyByZXNvdXJjZXMgZm9sZGVyIGhhcyBiZWVuIGZvdW5kYDtcbiAgICBpZiAoc3RyaWN0TW9kZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgIH1cbiAgICBsb2cuZGVidWcobWVzc2FnZSk7XG4gIH1cbiAgbG9nLmluZm8oYFdpbGwgZXh0cmFjdCByZXNvdXJjZSBzdHJpbmdzIGZyb20gJyR7bHByb2pSb290fSdgKTtcblxuICBjb25zdCByZXNvdXJjZVBhdGhzID0gW107XG4gIGlmIChzdHJpbmdGaWxlKSB7XG4gICAgY29uc3QgZHN0UGF0aCA9IHBhdGgucmVzb2x2ZShscHJvalJvb3QsIHN0cmluZ0ZpbGUpO1xuICAgIGlmIChhd2FpdCBmcy5leGlzdHMoZHN0UGF0aCkpIHtcbiAgICAgIHJlc291cmNlUGF0aHMucHVzaChkc3RQYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbWVzc2FnZSA9IGBObyAnJHtkc3RQYXRofScgcmVzb3VyY2UgZmlsZSBoYXMgYmVlbiBmb3VuZCBmb3IgJyR7YXBwfSdgO1xuICAgICAgaWYgKHN0cmljdE1vZGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgICAgfVxuICAgICAgbG9nLmluZm8obWVzc2FnZSk7XG4gICAgICBsb2cuaW5mbyhgR2V0dGluZyBhbGwgdGhlIGF2YWlsYWJsZSBzdHJpbmdzIGZyb20gJyR7bHByb2pSb290fSdgKTtcbiAgICB9XG4gIH1cblxuICBpZiAoXy5pc0VtcHR5KHJlc291cmNlUGF0aHMpICYmIGF3YWl0IGZzLmV4aXN0cyhscHJvalJvb3QpKSB7XG4gICAgY29uc3QgcmVzb3VyY2VGaWxlcyA9IChhd2FpdCBmcy5yZWFkZGlyKGxwcm9qUm9vdCkpXG4gICAgICAuZmlsdGVyKChuYW1lKSA9PiBfLnNvbWUoW1NUUklOR1NfUkVTT1VSQ0UsIFNUUklOR1NESUNUX1JFU09VUkNFXSwgKHgpID0+IG5hbWUuZW5kc1dpdGgoeCkpKVxuICAgICAgLm1hcCgobmFtZSkgPT4gcGF0aC5yZXNvbHZlKGxwcm9qUm9vdCwgbmFtZSkpO1xuICAgIHJlc291cmNlUGF0aHMucHVzaCguLi5yZXNvdXJjZUZpbGVzKTtcbiAgfVxuICBsb2cuaW5mbyhgR290ICR7cmVzb3VyY2VQYXRocy5sZW5ndGh9IHJlc291cmNlIGZpbGUocykgaW4gJyR7bHByb2pSb290fSdgKTtcblxuICBpZiAoXy5pc0VtcHR5KHJlc291cmNlUGF0aHMpKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgY29uc3QgcmVzdWx0U3RyaW5ncyA9IHt9O1xuICBjb25zdCB0b0Fic29sdXRlUGF0aCA9IGZ1bmN0aW9uIChwKSB7XG4gICAgcmV0dXJuIHBhdGguaXNBYnNvbHV0ZShwKSA/IHAgOiBwYXRoLnJlc29sdmUocHJvY2Vzcy5jd2QoKSwgcCk7XG4gIH07XG4gIGZvciAoY29uc3QgcmVzb3VyY2VQYXRoIG9mIHJlc291cmNlUGF0aHMpIHtcbiAgICBpZiAoIXV0aWwuaXNTdWJQYXRoKHRvQWJzb2x1dGVQYXRoKHJlc291cmNlUGF0aCksIHRvQWJzb2x1dGVQYXRoKGFwcCkpKSB7XG4gICAgICAvLyBzZWN1cml0eSBwcmVjYXV0aW9uXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYCcke3Jlc291cmNlUGF0aH0nIGlzIGV4cGVjdGVkIHRvIGJlIGxvY2F0ZWQgdW5kZXIgJyR7YXBwfSdgKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZWFkUmVzb3VyY2UocmVzb3VyY2VQYXRoKTtcbiAgICAgIGxvZy5kZWJ1ZyhgUGFyc2VkICR7Xy5rZXlzKGRhdGEpLmxlbmd0aH0gc3RyaW5nKHMpIGZyb20gJyR7cmVzb3VyY2VQYXRofSdgKTtcbiAgICAgIF8ubWVyZ2UocmVzdWx0U3RyaW5ncywgZGF0YSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgbG9nLndhcm4oYENhbm5vdCBwYXJzZSAnJHtyZXNvdXJjZVBhdGh9JyByZXNvdXJjZS4gT3JpZ2luYWwgZXJyb3I6ICR7ZS5tZXNzYWdlfWApO1xuICAgIH1cbiAgfVxuXG4gIGxvZy5pbmZvKGBHb3QgJHtfLmtleXMocmVzdWx0U3RyaW5ncykubGVuZ3RofSBzdHJpbmcocykgZnJvbSAnJHtscHJvalJvb3R9J2ApO1xuICByZXR1cm4gcmVzdWx0U3RyaW5ncztcbn1cblxuZXhwb3J0IHsgZXh0cmFjdEJ1bmRsZUlkLCB2ZXJpZnlBcHBsaWNhdGlvblBsYXRmb3JtLCBwYXJzZUxvY2FsaXphYmxlU3RyaW5ncyB9O1xuIl0sImZpbGUiOiJsaWIvYXBwLXV0aWxzLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uIn0=
|