testa_appium_driver 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.idea/deployment.xml +2 -9
- data/.idea/webServers.xml +1 -1
- data/README.md +365 -52
- data/lib/testa_appium_driver/android/locator.rb +16 -4
- data/lib/testa_appium_driver/android/locator/attributes.rb +2 -2
- data/lib/testa_appium_driver/common/constants.rb +2 -0
- data/lib/testa_appium_driver/common/helpers.rb +26 -28
- data/lib/testa_appium_driver/common/locator.rb +46 -4
- data/lib/testa_appium_driver/common/locator/scroll_actions.rb +23 -7
- data/lib/testa_appium_driver/common/scroll_actions.rb +8 -27
- data/lib/testa_appium_driver/common/selenium_element.rb +19 -0
- data/lib/testa_appium_driver/driver.rb +11 -33
- data/lib/testa_appium_driver/ios/locator.rb +14 -2
- data/lib/testa_appium_driver/version.rb +1 -1
- data/testa_appium_driver.gemspec +40 -40
- data/testa_appium_driver.iml +1 -35
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e65b137d1cb9c0486402e7e9e6a4d5148ceb64a77b921cd77cefbd2af1f4dfe
|
4
|
+
data.tar.gz: 52291aa9e594d60c2c0903ee54f2ad77f324421b62ed66057499c87f7fc43ce6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 42069df54528be14370204db3e2918a767bdc280b663b9a26369d88dd246a0430e4b141b6ec0076052d394daa27e19d4ddab956b604cda0c43210338df5235e9
|
7
|
+
data.tar.gz: 43138275c2b499c4edda27c817e096cdba33a18f8be6a57b8fe92d69f8b42a18426d47edbba376d69723a675a4a87af3bd6d65d22a631198551649e4d7752e3d
|
data/.gitignore
CHANGED
data/.idea/deployment.xml
CHANGED
@@ -1,21 +1,14 @@
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8"?>
|
2
2
|
<project version="4">
|
3
|
-
<component name="PublishConfigData"
|
3
|
+
<component name="PublishConfigData">
|
4
4
|
<serverData>
|
5
5
|
<paths name="supertesta.com">
|
6
6
|
<serverdata>
|
7
7
|
<mappings>
|
8
|
-
<mapping
|
8
|
+
<mapping local="$PROJECT_DIR$" web="/" />
|
9
9
|
</mappings>
|
10
|
-
<excludedPaths>
|
11
|
-
<excludedPath local="true" path="$PROJECT_DIR$/.idea" />
|
12
|
-
<excludedPath local="true" path="$PROJECT_DIR$/tmp" />
|
13
|
-
<excludedPath local="true" path="$PROJECT_DIR$/testa_appium_driver.iml" />
|
14
|
-
<excludedPath local="true" path="$PROJECT_DIR$/Gemfile.lock" />
|
15
|
-
</excludedPaths>
|
16
10
|
</serverdata>
|
17
11
|
</paths>
|
18
12
|
</serverData>
|
19
|
-
<option name="myAutoUpload" value="ON_EXPLICIT_SAVE" />
|
20
13
|
</component>
|
21
14
|
</project>
|
data/.idea/webServers.xml
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
<project version="4">
|
3
3
|
<component name="WebServers">
|
4
4
|
<option name="servers">
|
5
|
-
<webServer id="b1f6f214-0ed7-4869-998b-43dc6e5c154a" name="supertesta.com">
|
5
|
+
<webServer id="b1f6f214-0ed7-4869-998b-43dc6e5c154a" name="supertesta.com" url="http://something">
|
6
6
|
<fileTransfer rootFolder="/ruby_apps" accessType="SFTP" host="supertesta.com" port="22" sshConfigId="ea45cb27-d516-4292-a1f7-430f02857685" sshConfig="Supertesta.com">
|
7
7
|
<advancedOptions>
|
8
8
|
<advancedOptions dataProtectionLevel="Private" keepAliveTimeout="0" passiveMode="true" shareSSLContext="true" />
|
data/README.md
CHANGED
@@ -1,52 +1,365 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
also
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
1
|
+
# Testa Appium Driver
|
2
|
+
|
3
|
+
Testa appium driver is a wrapper around the `ruby_lib_core` driver for appium.
|
4
|
+
It leverages all driver features and makes them simple and easy to use.
|
5
|
+
|
6
|
+
There are two key concepts in the testa driver
|
7
|
+
#### 1. Elements are fetched only when needed
|
8
|
+
It allows you to chain all the selectors and use the adjacent selectors without finding each element in the chain.
|
9
|
+
For example `driver.linear_layout.list_view.view_group.button` will not execute any find element commands
|
10
|
+
because element command is not given. If `click`, `send_keys` or any attribute method is added to the end of chain
|
11
|
+
it will execute find_element before triggering the given element command.
|
12
|
+
|
13
|
+
This concept allows you to store the selectors and reuse them later on. For example
|
14
|
+
```ruby
|
15
|
+
# element is not fetched yet
|
16
|
+
my_fancy_progress_bar = driver.linear_layout.progress_bar
|
17
|
+
|
18
|
+
puts my_fancy_progress_bar.text # will fetch the element and print the text (output: "You are on the first page")
|
19
|
+
driver.button(text: "next page").click # go to the next page that has the same progress bar locator
|
20
|
+
|
21
|
+
# will fetch the element again and print the text (output: "You are on the second page")
|
22
|
+
# without TestaAppiumDriver, a Stale Object Exception would be thronw
|
23
|
+
puts my_fancy_progress_bar.text
|
24
|
+
```
|
25
|
+
|
26
|
+
|
27
|
+
#### 2. The Best element find / scroll strategy is automatically determined
|
28
|
+
When given an element locator such as the progress_bar in the first concept, testa appium driver automatically determines
|
29
|
+
the best find element strategy. The only thing to keep in mind is that you cannot mix strategy specific selectors.
|
30
|
+
Strategy specific selectors are `from_parent` for uiautomator or `parent`, `siblings` or `children` for xpath strategy.
|
31
|
+
|
32
|
+
There are also multiple scroll strategies. Android supports both `uiautomator` and `w3c`, while iOS only supports `w3c`
|
33
|
+
scroll strategy. Uiautomator scroll strategy is more fluent and faster but it cannot be limited with single direction
|
34
|
+
element finding, and it does not have sufficient deadzone support.
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
## Installation
|
40
|
+
|
41
|
+
Add this line to your application's Gemfile:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
gem 'testa_appium_driver'
|
45
|
+
```
|
46
|
+
|
47
|
+
And then execute:
|
48
|
+
|
49
|
+
$ bundle install
|
50
|
+
|
51
|
+
Or install it yourself as:
|
52
|
+
|
53
|
+
$ gem install testa_appium_driver
|
54
|
+
|
55
|
+
|
56
|
+
For the android platform, make sure you are using the latest version of uiautomator server. Versions older than 4.21.2 have breaking issues.
|
57
|
+
To get the latest server version execute:
|
58
|
+
```shell script
|
59
|
+
npm install appium-uiautomator2-server
|
60
|
+
```
|
61
|
+
And apks will be located in `./node_modules/appium-uiautomator2-server/apks`. Install both apks on the target device
|
62
|
+
and make sure you have the `skipServerInstallation: true` capability when starting the driver.
|
63
|
+
## Usage
|
64
|
+
|
65
|
+
### Initialization
|
66
|
+
```ruby
|
67
|
+
opts = {
|
68
|
+
caps: {
|
69
|
+
platformName: "Android",
|
70
|
+
deviceName: "MyPhone",
|
71
|
+
app: "/path/to/your/apk",
|
72
|
+
udid: "your_phone_udid",
|
73
|
+
automationName: "uiautomator2",
|
74
|
+
skipServerInstallation: true, # if uiautomator server is manually installed
|
75
|
+
enableMultiWindows: true, # enables appium to see some otherwise "hidden" elements
|
76
|
+
}
|
77
|
+
}
|
78
|
+
driver = TestaAppiumDriver::Driver.new(opts)
|
79
|
+
```
|
80
|
+
|
81
|
+
#### Example 1
|
82
|
+
```ruby
|
83
|
+
driver.linear_layout.button(id: "com.package.name:id/myElementId").click
|
84
|
+
```
|
85
|
+
Looks for the first linear layout and a button within the linear layout that has the provided id.
|
86
|
+
Only 1 find element is executed with the resolved strategy (xpath or uiautomator):<br>
|
87
|
+
underlying selectors:<br>
|
88
|
+
xpath: `//android.widget.LinearLayout[1]//android.widget.Button[@resource-id="com.package.name:id/myElementId"]` <br>
|
89
|
+
uiautomator: `new UiSelector().className("android.widget.LinearLayout").instance(0).childSelector(new UiSelector.className("android.widget.Button").resourceId("com.package.name:id/myElementId")));`<br>
|
90
|
+
|
91
|
+
#### Example 2
|
92
|
+
```ruby
|
93
|
+
driver.linear_layout(id: "myShortIdExample").parent.text_view.wait_until_exists(10).text
|
94
|
+
```
|
95
|
+
Testa driver converts shorthand ids(that dont have :id/) to full ids
|
96
|
+
by reading the current package under test and prepending it to the shorthand id. If you don't want to prepend the package
|
97
|
+
name to the id, use = sign before the id, for example `id: "=idWithoutAPackageName"`.
|
98
|
+
|
99
|
+
After adding the `parent` and `text_view` selectors and before retrieving the text value `wait_until_exists(10)` is used to
|
100
|
+
wait up to 10 seconds for the element to appear in the page before exception is thrown.
|
101
|
+
|
102
|
+
underlying selectors:<br>
|
103
|
+
xpath: `//android.widget.LinearLayout[@resource-id="com.package.name:id/myShortIdExample"][1]/../android.widget.TextView[1]` <br>
|
104
|
+
uiautomator: `exception: parent selector cannot be used with uiautomator strategy`
|
105
|
+
|
106
|
+
#### Example 3
|
107
|
+
```ruby
|
108
|
+
driver.list_view(top: 200).edit_text(text: "Looking for this text").scroll_to.align!(:bottom).enabled?
|
109
|
+
```
|
110
|
+
If the element cannot be found in the current view, `scroll_to` action will scroll to start of the scrollable container,
|
111
|
+
and start scrolling to the end until the element is found or end is reached. Once found the `align!(:bottom)` command
|
112
|
+
will align the element to the bottom of the scrollable container.
|
113
|
+
Finally, once the element is scrolled into view and aligned, it will check if the edit_text is enabled.
|
114
|
+
|
115
|
+
The scrollable container is resolved by looking the chain of selectors.
|
116
|
+
Selector can be a scrollable container if `scrollable: true` or is one of the scrollable classes:
|
117
|
+
- android.widget.ListView
|
118
|
+
- android.widget.ScrollView
|
119
|
+
- android.widget.HorizontalScrollView
|
120
|
+
- androidx.recyclerview.widget.RecyclerView
|
121
|
+
- XCUIElementTypeScrollView
|
122
|
+
|
123
|
+
If the selector chain does not contain a scrollable container, a `driver.scrollabe` command will be executed to
|
124
|
+
retrieve the first scrollable element in page.
|
125
|
+
|
126
|
+
Scrollable selectors can accept the `top`, `right`, `bottom` and `left` parameters as deadzone to prevent that edge of the
|
127
|
+
container be used as scrollable surface.
|
128
|
+
Custom views can also be used as scrollable containers with `as_scrollable` command.
|
129
|
+
The command marks the last selector as scrollable container.
|
130
|
+
`driver.view(id: "myCustomScrollableView").as_scrollable(top: 200).page_down`
|
131
|
+
|
132
|
+
|
133
|
+
|
134
|
+
|
135
|
+
|
136
|
+
#### Example 4
|
137
|
+
```ruby
|
138
|
+
driver.buttons.each do |element|
|
139
|
+
puts element.text
|
140
|
+
end
|
141
|
+
```
|
142
|
+
The `each` method is one of the scrollable actions. It will start from the beginning of the scrollable container,
|
143
|
+
in this case `driver.scrollable`, and find every button in the screen. It will scroll the page until the end of scrollable
|
144
|
+
container is reached and all buttons are found.
|
145
|
+
|
146
|
+
|
147
|
+
|
148
|
+
#### Example 5 (Invalid combination)
|
149
|
+
```ruby
|
150
|
+
driver.frame_layout.from_parent.button(text: "My Cool text").siblings
|
151
|
+
```
|
152
|
+
This example demonstrates a invalid selector because it cannot be resolved with xpath nor uiautomator strategy.
|
153
|
+
It will raise StrategyMixException because from_parent selector can only be used with uiautomator strategy and
|
154
|
+
siblings selector can only be used with xpath strategy.
|
155
|
+
|
156
|
+
|
157
|
+
# Methods
|
158
|
+
|
159
|
+
## Android
|
160
|
+
### Class Selectors
|
161
|
+
- element
|
162
|
+
- elements
|
163
|
+
- scrollable
|
164
|
+
- scrollables
|
165
|
+
- image_view
|
166
|
+
- image_views
|
167
|
+
- frame_layout
|
168
|
+
- frame_layouts
|
169
|
+
- linear_layout
|
170
|
+
- linear_layouts
|
171
|
+
- view
|
172
|
+
- views
|
173
|
+
- edit_text
|
174
|
+
- edit_texts
|
175
|
+
- view_group
|
176
|
+
- view_groups
|
177
|
+
- relative_layout
|
178
|
+
- relative_layouts
|
179
|
+
- recycler_view
|
180
|
+
- recycler_views
|
181
|
+
- button
|
182
|
+
- buttons
|
183
|
+
- image_button
|
184
|
+
- image_buttons
|
185
|
+
- horizontal_scroll_view
|
186
|
+
- horizontal_scroll_views
|
187
|
+
- scroll_view
|
188
|
+
- scroll_views
|
189
|
+
- view_pager
|
190
|
+
- view_pagers
|
191
|
+
- check_box
|
192
|
+
- check_boxes
|
193
|
+
- list_view
|
194
|
+
- list_views
|
195
|
+
- progress_bar
|
196
|
+
- progress_bars
|
197
|
+
- radio_button
|
198
|
+
- radio_buttons
|
199
|
+
- radio_group
|
200
|
+
- radio_groups
|
201
|
+
- search_view
|
202
|
+
- search_views
|
203
|
+
- spinner
|
204
|
+
- spinners
|
205
|
+
- toast
|
206
|
+
- toasts
|
207
|
+
- toolbar
|
208
|
+
- toolbars
|
209
|
+
- text_view
|
210
|
+
- text_views
|
211
|
+
|
212
|
+
Adjacent selectors
|
213
|
+
- from_parent
|
214
|
+
- parent
|
215
|
+
- child
|
216
|
+
- children
|
217
|
+
- siblings
|
218
|
+
- preceding_sibling
|
219
|
+
- preceding_siblings
|
220
|
+
- following_sibling
|
221
|
+
- following_siblings
|
222
|
+
|
223
|
+
|
224
|
+
Class Selector arguments
|
225
|
+
- id
|
226
|
+
- long_clickable
|
227
|
+
- desc
|
228
|
+
- class
|
229
|
+
- text
|
230
|
+
- package
|
231
|
+
- checkable
|
232
|
+
- checked
|
233
|
+
- clickable
|
234
|
+
- enabled
|
235
|
+
- focusable
|
236
|
+
- focused
|
237
|
+
- index
|
238
|
+
- selected
|
239
|
+
- scrollable
|
240
|
+
|
241
|
+
### Attributes
|
242
|
+
- text
|
243
|
+
- package
|
244
|
+
- class_name
|
245
|
+
- checkable?
|
246
|
+
- checked?
|
247
|
+
- clickable?
|
248
|
+
- desc
|
249
|
+
- enabled?
|
250
|
+
- focusable?
|
251
|
+
- focused?
|
252
|
+
- long_clickable?
|
253
|
+
- password?
|
254
|
+
- id
|
255
|
+
- scrollable?
|
256
|
+
- selected?
|
257
|
+
- displayed?
|
258
|
+
- selection_start
|
259
|
+
- selection_end
|
260
|
+
- bounds
|
261
|
+
- index
|
262
|
+
|
263
|
+
# iOS
|
264
|
+
## Type Selectors
|
265
|
+
- element
|
266
|
+
- elements
|
267
|
+
- window
|
268
|
+
- windows
|
269
|
+
- other
|
270
|
+
- others
|
271
|
+
- navigation_bar
|
272
|
+
- navigation_bars
|
273
|
+
- button
|
274
|
+
- buttons
|
275
|
+
- image
|
276
|
+
- images
|
277
|
+
- static_text
|
278
|
+
- static_texts
|
279
|
+
- scrollable
|
280
|
+
- scrollables
|
281
|
+
- scroll_view
|
282
|
+
- scroll_views
|
283
|
+
- table
|
284
|
+
- tables
|
285
|
+
- cell
|
286
|
+
- cells
|
287
|
+
|
288
|
+
Adjacent selectors
|
289
|
+
- parent
|
290
|
+
- child
|
291
|
+
- children
|
292
|
+
- siblings
|
293
|
+
- preceding_sibling
|
294
|
+
- preceding_siblings
|
295
|
+
- following_sibling
|
296
|
+
- following_siblings
|
297
|
+
|
298
|
+
Type Selector arguments
|
299
|
+
- enabled
|
300
|
+
- type, class
|
301
|
+
- label
|
302
|
+
- width
|
303
|
+
- height
|
304
|
+
- visible
|
305
|
+
- name, id
|
306
|
+
- value
|
307
|
+
|
308
|
+
|
309
|
+
## Attributes
|
310
|
+
- accessibility_container
|
311
|
+
- accessible?
|
312
|
+
- class_name
|
313
|
+
- enabled?
|
314
|
+
- frame
|
315
|
+
- index
|
316
|
+
- label, text
|
317
|
+
- name
|
318
|
+
- rect, bounds
|
319
|
+
- selected?
|
320
|
+
- type
|
321
|
+
- value
|
322
|
+
- visible?
|
323
|
+
|
324
|
+
# Scroll actions
|
325
|
+
- each
|
326
|
+
- align!
|
327
|
+
- align_top!
|
328
|
+
- align_bottom!
|
329
|
+
- align_left!
|
330
|
+
- align_right!
|
331
|
+
- align
|
332
|
+
- align_top
|
333
|
+
- align_bottom
|
334
|
+
- align_left
|
335
|
+
- align_right
|
336
|
+
- scroll_to
|
337
|
+
- scroll_down_to
|
338
|
+
- scroll_up_to
|
339
|
+
- scroll_right_to
|
340
|
+
- scroll_left_to
|
341
|
+
- scroll_to_start
|
342
|
+
- scroll_to_end
|
343
|
+
- page_down
|
344
|
+
- page_up
|
345
|
+
- page_left
|
346
|
+
- page_right
|
347
|
+
- fling_down
|
348
|
+
- fling_up
|
349
|
+
- fling_left
|
350
|
+
- fling_right
|
351
|
+
- drag_to
|
352
|
+
- drag_by
|
353
|
+
|
354
|
+
# Helpers
|
355
|
+
- as_scrollable
|
356
|
+
- wait_until_exists
|
357
|
+
- wait_while_exists
|
358
|
+
- exists?
|
359
|
+
- long_tap
|
360
|
+
|
361
|
+
## License
|
362
|
+
|
363
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
364
|
+
|
365
|
+
|
@@ -19,6 +19,15 @@ module TestaAppiumDriver
|
|
19
19
|
else
|
20
20
|
@scroll_orientation = :vertical
|
21
21
|
end
|
22
|
+
|
23
|
+
if !params[:top].nil? || !params[:bottom].nil? || !params[:right].nil? || !params[:left].nil?
|
24
|
+
@scroll_deadzone = {}
|
25
|
+
@scroll_deadzone[:top] = params[:top].to_f unless params[:top].nil?
|
26
|
+
@scroll_deadzone[:bottom] = params[:bottom].to_f unless params[:bottom].nil?
|
27
|
+
@scroll_deadzone[:right] = params[:right].to_f unless params[:right].nil?
|
28
|
+
@scroll_deadzone[:left] = params[:left].to_f unless params[:left].nil?
|
29
|
+
end
|
30
|
+
|
22
31
|
params[:scrollable_locator] = self.dup
|
23
32
|
end
|
24
33
|
|
@@ -27,16 +36,18 @@ module TestaAppiumDriver
|
|
27
36
|
|
28
37
|
|
29
38
|
# resolve selector which will be used for finding element
|
30
|
-
def
|
39
|
+
def strategy_and_selector
|
40
|
+
if @can_use_id_strategy
|
41
|
+
return FIND_STRATEGY_ID, @can_use_id_strategy
|
42
|
+
end
|
31
43
|
if (@strategy.nil? && @default_find_strategy == FIND_STRATEGY_UIAUTOMATOR) || @strategy == FIND_STRATEGY_UIAUTOMATOR
|
32
|
-
ui_selector
|
44
|
+
[FIND_STRATEGY_UIAUTOMATOR, ui_selector]
|
33
45
|
elsif (@strategy.nil? && @default_find_strategy == FIND_STRATEGY_XPATH) || @strategy == FIND_STRATEGY_XPATH
|
34
|
-
@xpath_selector
|
46
|
+
[FIND_STRATEGY_XPATH, @xpath_selector]
|
35
47
|
end
|
36
48
|
end
|
37
49
|
|
38
50
|
|
39
|
-
|
40
51
|
# @param [Boolean] include_semicolon should the semicolon be included at the end
|
41
52
|
# @return ui_selector for uiautomator find strategy
|
42
53
|
def ui_selector(include_semicolon = true)
|
@@ -71,6 +82,7 @@ module TestaAppiumDriver
|
|
71
82
|
raise "Cannot add child selector to Array" if single && !@single
|
72
83
|
|
73
84
|
locator = self.dup
|
85
|
+
locator.can_use_id_strategy = false
|
74
86
|
if (@strategy.nil? && !single) || @strategy == FIND_STRATEGY_XPATH
|
75
87
|
locator.strategy = FIND_STRATEGY_XPATH
|
76
88
|
locator.strategy_reason = "multiple child selector"
|
@@ -29,27 +29,17 @@ module TestaAppiumDriver
|
|
29
29
|
def hash_to_uiautomator(hash, single = true)
|
30
30
|
command = "new UiSelector()"
|
31
31
|
|
32
|
-
|
33
|
-
# shorthand ids like myId make full ids => my.app.package:id/myId
|
34
|
-
|
35
|
-
if hash[:id][0] == "="
|
36
|
-
id = hash[:id][1..-1]
|
37
|
-
else
|
38
|
-
id = "#{@driver.current_package}:id/#{hash[:id]}"
|
39
|
-
end
|
40
|
-
else
|
41
|
-
id = hash[:id]
|
42
|
-
end
|
32
|
+
id = resolve_id(hash[:id])
|
43
33
|
command = "#{ command }.resourceId(\"#{ %(#{ id }) }\")" if id && id.kind_of?(String)
|
44
|
-
command = "#{ command }.resourceIdMatches(\"
|
34
|
+
command = "#{ command }.resourceIdMatches(\".*#{ %(#{ id.source }) }.*\")" if id && id.kind_of?(Regexp)
|
45
35
|
command = "#{ command }.description(\"#{ %(#{ hash[:desc] }) }\")" if hash[:desc] && hash[:desc].kind_of?(String)
|
46
|
-
command = "#{ command }.descriptionMatches(\"
|
36
|
+
command = "#{ command }.descriptionMatches(\".*#{ %(#{ hash[:desc].source }) }.*\")" if hash[:desc] && hash[:desc].kind_of?(Regexp)
|
47
37
|
command = "#{ command }.className(\"#{ %(#{ hash[:class] }) }\")" if hash[:class] && hash[:class].kind_of?(String)
|
48
|
-
command = "#{ command }.classNameMatches(\"
|
38
|
+
command = "#{ command }.classNameMatches(\".*#{ %(#{ hash[:class].source }) }.*\")" if hash[:class] && hash[:class].kind_of?(Regexp)
|
49
39
|
command = "#{ command }.text(\"#{ %(#{ hash[:text] }) }\")" if hash[:text] && hash[:text].kind_of?(String)
|
50
|
-
command = "#{ command }.textMatches(\"
|
40
|
+
command = "#{ command }.textMatches(\".*#{ %(#{ hash[:text].source }) }.*\")" if hash[:text] && hash[:text].kind_of?(Regexp)
|
51
41
|
command = "#{ command }.packageName(\"#{ %(#{ hash[:package] }) }\")" if hash[:package] && hash[:package].kind_of?(String)
|
52
|
-
command = "#{ command }.packageNameMatches(\"
|
42
|
+
command = "#{ command }.packageNameMatches(\".*#{ %(#{ hash[:package].source }) }.*\")" if hash[:package] && hash[:package].kind_of?(Regexp)
|
53
43
|
|
54
44
|
command = "#{ command }.longClickable(#{ hash[:long_clickable] })" if hash[:long_clickable]
|
55
45
|
command = "#{ command }.checkable(#{ hash[:checkable] })" unless hash[:checkable].nil?
|
@@ -99,18 +89,10 @@ module TestaAppiumDriver
|
|
99
89
|
|
100
90
|
command = "//"
|
101
91
|
|
102
|
-
|
103
|
-
# shorthand ids like myId make full ids => my.app.package:id/myId
|
104
|
-
if hash[:id][0] == "="
|
105
|
-
id = hash[:id][1..-1]
|
106
|
-
else
|
107
|
-
id = "#{@driver.current_package}:id/#{hash[:id]}"
|
108
|
-
end
|
109
|
-
else
|
110
|
-
id = hash[:id]
|
111
|
-
end
|
92
|
+
|
112
93
|
|
113
94
|
if for_android
|
95
|
+
id = resolve_id(hash[:id])
|
114
96
|
if hash[:class] && hash[:class].kind_of?(String)
|
115
97
|
command = "#{ command }#{hash[:class] }"
|
116
98
|
elsif hash[:class] && hash[:class].kind_of?(Regexp)
|
@@ -140,6 +122,8 @@ module TestaAppiumDriver
|
|
140
122
|
command = "#{ command }[@selected=\"#{ hash[:selected] }\"]" unless hash[:selected].nil?
|
141
123
|
command = "#{ command }[@scrollable=\"#{ hash[:scrollable] }\"]" unless hash[:scrollable].nil?
|
142
124
|
else
|
125
|
+
|
126
|
+
hash[:type] = hash[:class] unless hash[:class].nil?
|
143
127
|
if hash[:type] && hash[:type].kind_of?(String)
|
144
128
|
command = "#{ command }#{hash[:type] }"
|
145
129
|
elsif hash[:type] && hash[:type].kind_of?(Regexp)
|
@@ -196,7 +180,7 @@ module TestaAppiumDriver
|
|
196
180
|
def extract_selectors_from_params(params = {})
|
197
181
|
selectors = params.select { |key, value| [
|
198
182
|
:id,
|
199
|
-
:
|
183
|
+
:long_clickable,
|
200
184
|
:desc,
|
201
185
|
:class,
|
202
186
|
:text,
|
@@ -220,7 +204,7 @@ module TestaAppiumDriver
|
|
220
204
|
:height,
|
221
205
|
:visible,
|
222
206
|
:name,
|
223
|
-
:value
|
207
|
+
:value,
|
224
208
|
].include?(key) }
|
225
209
|
params = Hash[params.to_a - selectors.to_a]
|
226
210
|
|
@@ -238,5 +222,19 @@ module TestaAppiumDriver
|
|
238
222
|
|
239
223
|
return params, selectors
|
240
224
|
end
|
225
|
+
|
226
|
+
|
227
|
+
def resolve_id(id)
|
228
|
+
if id && id.kind_of?(String) && !id.match?(/.*:id\//)
|
229
|
+
# shorthand ids like myId make full ids => my.app.package:id/myId
|
230
|
+
if id[0] == "="
|
231
|
+
return id[1..-1]
|
232
|
+
else
|
233
|
+
return "#{@driver.current_package}:id/#{id}"
|
234
|
+
end
|
235
|
+
else
|
236
|
+
id
|
237
|
+
end
|
238
|
+
end
|
241
239
|
end
|
242
240
|
end
|
@@ -13,6 +13,7 @@ module TestaAppiumDriver
|
|
13
13
|
attr_accessor :strategy
|
14
14
|
attr_accessor :strategy_reason
|
15
15
|
attr_accessor :last_selector_adjacent
|
16
|
+
attr_accessor :can_use_id_strategy
|
16
17
|
|
17
18
|
attr_accessor :from_element
|
18
19
|
attr_accessor :scroll_orientation
|
@@ -37,11 +38,11 @@ module TestaAppiumDriver
|
|
37
38
|
@driver = driver
|
38
39
|
|
39
40
|
params, selectors = extract_selectors_from_params(params)
|
40
|
-
|
41
41
|
single = params[:single]
|
42
42
|
|
43
43
|
@single = single
|
44
44
|
|
45
|
+
selectors[:id] = selectors[:name] unless selectors[:name].nil?
|
45
46
|
if from_element.instance_of?(Selenium::WebDriver::Element)
|
46
47
|
@xpath_selector = "//*" # to select current element
|
47
48
|
@xpath_selector += hash_to_xpath(@driver.device, selectors, single)[1..-1]
|
@@ -54,6 +55,15 @@ module TestaAppiumDriver
|
|
54
55
|
@default_find_strategy = params[:default_find_strategy]
|
55
56
|
@default_scroll_strategy = params[:default_scroll_strategy]
|
56
57
|
|
58
|
+
@can_use_id_strategy = selectors.keys.count == 1 && !selectors[:id].nil?
|
59
|
+
if @can_use_id_strategy
|
60
|
+
if @driver.device == :android
|
61
|
+
@can_use_id_strategy = resolve_id(selectors[:id])
|
62
|
+
else
|
63
|
+
@can_use_id_strategy = selectors[:id]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
57
67
|
|
58
68
|
@strategy = params[:strategy]
|
59
69
|
@strategy_reason = params[:strategy_reason]
|
@@ -84,7 +94,12 @@ module TestaAppiumDriver
|
|
84
94
|
if @xpath_selector == "//*/*[1]" && @from_element.instance_of?(Selenium::WebDriver::Element)
|
85
95
|
return @from_element
|
86
96
|
end
|
87
|
-
|
97
|
+
|
98
|
+
|
99
|
+
strategy, selector = strategy_and_selector
|
100
|
+
|
101
|
+
|
102
|
+
@driver.execute(@from_element, selector, @single, strategy, @default_find_strategy, skip_cache)
|
88
103
|
end
|
89
104
|
|
90
105
|
|
@@ -128,15 +143,34 @@ module TestaAppiumDriver
|
|
128
143
|
found
|
129
144
|
end
|
130
145
|
|
146
|
+
# @return [TestaAppiumDriver::Locator]
|
147
|
+
def first
|
148
|
+
self[0]
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [TestaAppiumDriver::Locator]
|
152
|
+
def second
|
153
|
+
self[1]
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [TestaAppiumDriver::Locator]
|
157
|
+
def third
|
158
|
+
self[2]
|
159
|
+
end
|
160
|
+
|
161
|
+
# @return [TestaAppiumDriver::Locator]
|
162
|
+
def last
|
163
|
+
self[-1]
|
164
|
+
end
|
131
165
|
|
132
166
|
def [](instance)
|
133
167
|
raise "Cannot add index selector to non-Array" if @single
|
134
|
-
|
135
|
-
if (@strategy.nil? && !@last_selector_adjacent) || @strategy == FIND_STRATEGY_UIAUTOMATOR
|
168
|
+
if ((@strategy.nil? && !@last_selector_adjacent) || @strategy == FIND_STRATEGY_UIAUTOMATOR) && instance >= 0
|
136
169
|
locator = self.dup
|
137
170
|
locator.strategy = FIND_STRATEGY_UIAUTOMATOR
|
138
171
|
locator.ui_selector = "#{@ui_selector}.instance(#{instance})"
|
139
172
|
locator.single = true
|
173
|
+
locator.can_use_id_strategy = false
|
140
174
|
locator
|
141
175
|
else
|
142
176
|
from_element = self.execute[instance]
|
@@ -235,6 +269,7 @@ module TestaAppiumDriver
|
|
235
269
|
locator.strategy = FIND_STRATEGY_XPATH
|
236
270
|
locator.strategy_reason = "parent"
|
237
271
|
locator.xpath_selector += "/.."
|
272
|
+
locator.can_use_id_strategy = false
|
238
273
|
locator
|
239
274
|
end
|
240
275
|
|
@@ -250,6 +285,7 @@ module TestaAppiumDriver
|
|
250
285
|
locator.xpath_selector += "/*"
|
251
286
|
locator.single = false
|
252
287
|
locator.last_selector_adjacent = true
|
288
|
+
locator.can_use_id_strategy = false
|
253
289
|
locator
|
254
290
|
end
|
255
291
|
|
@@ -265,6 +301,7 @@ module TestaAppiumDriver
|
|
265
301
|
locator.strategy_reason = "child"
|
266
302
|
locator.xpath_selector += "/*[1]"
|
267
303
|
locator.single = true
|
304
|
+
locator.can_use_id_strategy = false
|
268
305
|
locator
|
269
306
|
end
|
270
307
|
|
@@ -281,6 +318,7 @@ module TestaAppiumDriver
|
|
281
318
|
locator.xpath_selector += "/../*[not(@index=\"#{index}\")]"
|
282
319
|
locator.single = false
|
283
320
|
locator.last_selector_adjacent = true
|
321
|
+
locator.can_use_id_strategy = false
|
284
322
|
locator
|
285
323
|
end
|
286
324
|
|
@@ -296,6 +334,7 @@ module TestaAppiumDriver
|
|
296
334
|
locator.xpath_selector += "/../*[position() < #{index + 1}]" # position() starts from 1
|
297
335
|
locator.single = false
|
298
336
|
locator.last_selector_adjacent = true
|
337
|
+
locator.can_use_id_strategy = false
|
299
338
|
locator
|
300
339
|
end
|
301
340
|
|
@@ -313,6 +352,7 @@ module TestaAppiumDriver
|
|
313
352
|
return nil if i == 0
|
314
353
|
locator.xpath_selector += "/../*[@index=\"#{i - 1}\"]"
|
315
354
|
locator.last_selector_adjacent = true
|
355
|
+
locator.can_use_id_strategy = false
|
316
356
|
locator
|
317
357
|
end
|
318
358
|
|
@@ -329,6 +369,7 @@ module TestaAppiumDriver
|
|
329
369
|
locator.xpath_selector += "/../*[position() > #{index + 1}]" # position() starts from 1
|
330
370
|
locator.single = false
|
331
371
|
locator.last_selector_adjacent = true
|
372
|
+
locator.can_use_id_strategy = false
|
332
373
|
locator
|
333
374
|
end
|
334
375
|
|
@@ -346,6 +387,7 @@ module TestaAppiumDriver
|
|
346
387
|
return nil if i == 0
|
347
388
|
locator.xpath_selector += "/../*[@index=\"#{i + 1}\"]"
|
348
389
|
locator.last_selector_adjacent = true
|
390
|
+
locator.can_use_id_strategy = false
|
349
391
|
locator
|
350
392
|
end
|
351
393
|
|
@@ -98,33 +98,37 @@ module TestaAppiumDriver
|
|
98
98
|
# First scrolls to the beginning of the scrollable container and then scrolls down until element is found or end is reached
|
99
99
|
# @return [TestaAppiumDriver::Locator]
|
100
100
|
def scroll_to(deadzone: nil, max_scrolls: nil, direction: nil)
|
101
|
-
|
101
|
+
if direction
|
102
|
+
_scroll_dir_to(deadzone, max_scrolls, direction)
|
103
|
+
else
|
104
|
+
_scroll_to(deadzone, max_scrolls)
|
105
|
+
end
|
102
106
|
end
|
103
107
|
|
104
108
|
|
105
109
|
# Scrolls down until element is found or end is reached
|
106
110
|
# @return [TestaAppiumDriver::Locator]
|
107
111
|
def scroll_down_to(deadzone: nil, max_scrolls: nil)
|
108
|
-
|
112
|
+
_scroll_dir_to(deadzone, max_scrolls, :down)
|
109
113
|
end
|
110
114
|
|
111
115
|
# Scrolls up until element is found or end is reached
|
112
116
|
# @return [TestaAppiumDriver::Locator]
|
113
117
|
def scroll_up_to(deadzone: nil, max_scrolls: nil)
|
114
|
-
|
118
|
+
_scroll_dir_to(deadzone, max_scrolls, :up)
|
115
119
|
end
|
116
120
|
|
117
121
|
# Scrolls right until element is found or end is reached
|
118
122
|
# @return [TestaAppiumDriver::Locator]
|
119
123
|
def scroll_right_to(deadzone: nil, max_scrolls: nil)
|
120
|
-
|
124
|
+
_scroll_dir_to(deadzone, max_scrolls, :right)
|
121
125
|
end
|
122
126
|
|
123
127
|
|
124
128
|
# Scrolls left until element is found or end is reached
|
125
129
|
# @return [TestaAppiumDriver::Locator]
|
126
130
|
def scroll_left_to(deadzone: nil, max_scrolls: nil)
|
127
|
-
|
131
|
+
_scroll_dir_to(deadzone, max_scrolls, :left)
|
128
132
|
end
|
129
133
|
|
130
134
|
# Scrolls to the start of the scrollable container (top on vertical container, left on horizontal)
|
@@ -272,16 +276,28 @@ module TestaAppiumDriver
|
|
272
276
|
self
|
273
277
|
end
|
274
278
|
|
275
|
-
def _scroll_to(deadzone, max_scrolls
|
279
|
+
def _scroll_to(deadzone, max_scrolls)
|
276
280
|
deadzone = @scrollable_locator.scroll_deadzone if deadzone.nil? && !@scrollable_locator.nil?
|
277
281
|
sa = ScrollActions.new(@scrollable_locator,
|
278
282
|
locator: self,
|
279
283
|
deadzone: deadzone,
|
280
284
|
max_scrolls: max_scrolls,
|
281
|
-
direction: direction,
|
282
285
|
default_scroll_strategy: @default_scroll_strategy)
|
283
286
|
sa.scroll_to
|
284
287
|
self
|
285
288
|
end
|
289
|
+
|
290
|
+
def _scroll_dir_to(deadzone, max_scrolls, direction)
|
291
|
+
deadzone = @scrollable_locator.scroll_deadzone if deadzone.nil? && !@scrollable_locator.nil?
|
292
|
+
sa = ScrollActions.new(@scrollable_locator,
|
293
|
+
locator: self,
|
294
|
+
deadzone: deadzone,
|
295
|
+
max_scrolls: max_scrolls,
|
296
|
+
direction: direction,
|
297
|
+
default_scroll_strategy: @default_scroll_strategy)
|
298
|
+
|
299
|
+
sa.send("scroll_#{direction}_to")
|
300
|
+
self
|
301
|
+
end
|
286
302
|
end
|
287
303
|
end
|
@@ -26,7 +26,7 @@ module TestaAppiumDriver
|
|
26
26
|
@strategy = nil
|
27
27
|
if @scrollable.strategy == FIND_STRATEGY_XPATH || # uiautomator cannot resolve scrollable from a xpath locator
|
28
28
|
!@deadzone.nil? ||
|
29
|
-
!@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver)
|
29
|
+
!@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver) # uiautomator cannot resolve nested scrollable
|
30
30
|
@strategy = SCROLL_STRATEGY_W3C
|
31
31
|
end
|
32
32
|
|
@@ -41,8 +41,8 @@ module TestaAppiumDriver
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# @return [Array]
|
44
|
-
def each(skip_scroll_to_start,
|
45
|
-
w3c_each(skip_scroll_to_start,
|
44
|
+
def each(skip_scroll_to_start, &block)
|
45
|
+
w3c_each(skip_scroll_to_start, &block)
|
46
46
|
end
|
47
47
|
|
48
48
|
def resolve_strategy
|
@@ -63,39 +63,19 @@ module TestaAppiumDriver
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def scroll_down_to
|
66
|
-
|
67
|
-
# we have direction enabled, uiautomator does not support direction specific element search
|
68
|
-
w3c_scroll_to(:down)
|
69
|
-
elsif resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
70
|
-
raise "scroll_down_to is not supported for uiautomator scroll strategy. Use scroll_to without deadzone"
|
71
|
-
end
|
66
|
+
w3c_scroll_to(:down)
|
72
67
|
end
|
73
68
|
|
74
69
|
def scroll_up_to
|
75
|
-
|
76
|
-
# we have direction enabled, uiautomator does not support direction specific element search
|
77
|
-
w3c_scroll_to(:up)
|
78
|
-
elsif resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
79
|
-
raise "scroll_up_to is not supported for uiautomator scroll strategy. Use scroll_to without deadzone"
|
80
|
-
end
|
70
|
+
w3c_scroll_to(:up)
|
81
71
|
end
|
82
72
|
|
83
73
|
def scroll_right_to
|
84
|
-
|
85
|
-
# we have direction enabled, uiautomator does not support direction specific element search
|
86
|
-
w3c_scroll_to(:right)
|
87
|
-
elsif resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
88
|
-
raise "scroll_right_to is not supported for uiautomator scroll strategy. Use scroll_to without deadzone"
|
89
|
-
end
|
74
|
+
w3c_scroll_to(:right)
|
90
75
|
end
|
91
76
|
|
92
77
|
def scroll_left_to
|
93
|
-
|
94
|
-
# we have direction enabled, uiautomator does not support direction specific element search
|
95
|
-
w3c_scroll_to(:left)
|
96
|
-
elsif resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
97
|
-
raise "scroll_left_to is not supported for uiautomator scroll strategy. Use scroll_to without deadzone"
|
98
|
-
end
|
78
|
+
w3c_scroll_to(:left)
|
99
79
|
end
|
100
80
|
|
101
81
|
def page_next
|
@@ -202,6 +182,7 @@ module TestaAppiumDriver
|
|
202
182
|
|
203
183
|
|
204
184
|
private
|
185
|
+
|
205
186
|
def is_end_of_scroll?
|
206
187
|
old_elements = @previous_elements
|
207
188
|
@previous_elements = @scrollable.first_and_last_leaf
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
3
|
+
#noinspection RubyClassVariableUsageInspection
|
4
|
+
class Element
|
5
|
+
def self.set_driver(driver, udid)
|
6
|
+
udid = "unknown" if udid.nil?
|
7
|
+
@@drivers ||= {}
|
8
|
+
@@drivers[udid] = driver
|
9
|
+
end
|
10
|
+
|
11
|
+
def get_driver
|
12
|
+
udid = @bridge.capabilities.instance_variable_get(:@capabilities)["udid"]
|
13
|
+
udid = "unknown" if udid.nil?
|
14
|
+
@@drivers[udid]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -5,9 +5,11 @@ require_relative 'common/exceptions/strategy_mix_exception'
|
|
5
5
|
require_relative 'common/helpers'
|
6
6
|
require_relative 'common/locator'
|
7
7
|
require_relative 'common/scroll_actions'
|
8
|
+
require_relative 'common/selenium_element'
|
8
9
|
|
9
10
|
module TestaAppiumDriver
|
10
11
|
class Driver
|
12
|
+
include Helpers
|
11
13
|
attr_accessor :driver
|
12
14
|
attr_reader :device
|
13
15
|
attr_reader :automation_name
|
@@ -19,7 +21,7 @@ module TestaAppiumDriver
|
|
19
21
|
|
20
22
|
|
21
23
|
|
22
|
-
core = Appium::Core.for(opts)
|
24
|
+
core = ::Appium::Core.for(opts)
|
23
25
|
extend_for(core.device, core.automation_name)
|
24
26
|
@device = core.device
|
25
27
|
@automation_name = core.automation_name
|
@@ -30,8 +32,7 @@ module TestaAppiumDriver
|
|
30
32
|
invalidate_cache!
|
31
33
|
|
32
34
|
|
33
|
-
|
34
|
-
extend_element_with_driver(opts[:caps][:udid])
|
35
|
+
::Selenium::WebDriver::Element.set_driver(self, opts[:caps][:udid])
|
35
36
|
end
|
36
37
|
|
37
38
|
|
@@ -45,21 +46,7 @@ module TestaAppiumDriver
|
|
45
46
|
}
|
46
47
|
end
|
47
48
|
|
48
|
-
#noinspection RubyClassVariableUsageInspection
|
49
|
-
def extend_element_with_driver(udid)
|
50
|
-
Selenium::WebDriver::Element.define_singleton_method(:set_driver) do |driver|
|
51
|
-
udid = "unknown" if udid.nil?
|
52
|
-
@@drivers ||={}
|
53
|
-
@@drivers[udid] = driver
|
54
|
-
end
|
55
49
|
|
56
|
-
Selenium::WebDriver::Element.set_driver(self)
|
57
|
-
Selenium::WebDriver::Element.define_method(:get_driver) do
|
58
|
-
udid = self.instance_variable_get(:@bridge).instance_variable_get(:@capabilities).instance_variable_get(:@capabilities)["udid"]
|
59
|
-
udid = "unknown" if udid.nil?
|
60
|
-
@@drivers[udid]
|
61
|
-
end
|
62
|
-
end
|
63
50
|
|
64
51
|
|
65
52
|
#noinspection RubyScope
|
@@ -75,13 +62,14 @@ module TestaAppiumDriver
|
|
75
62
|
# if user wants to wait for element to exist, he can use wait_until_present
|
76
63
|
disable_wait_for_idle
|
77
64
|
|
65
|
+
|
78
66
|
# if not restricted to a strategy, use the default one
|
79
67
|
strategy = default_strategy if strategy.nil?
|
80
68
|
|
81
69
|
# resolve from_element unique id, so that we can cache it properly
|
82
|
-
from_element_id = from_element.kind_of?(TestaAppiumDriver::Locator) ? from_element.
|
70
|
+
from_element_id = from_element.kind_of?(TestaAppiumDriver::Locator) ? from_element.strategy_and_selector[1] : nil
|
83
71
|
|
84
|
-
puts "Executing #{from_element_id ? "from #{from_element.strategy}: #{from_element.
|
72
|
+
puts "Executing #{from_element_id ? "from #{from_element.strategy}: #{from_element.strategy_and_selector} => " : ""}#{strategy}: #{selector}"
|
85
73
|
begin
|
86
74
|
if @cache[:selector] != selector || # cache miss, selector is different
|
87
75
|
@cache[:time] + 5 <= Time.now || # cache miss, older than 5 seconds
|
@@ -89,23 +77,13 @@ module TestaAppiumDriver
|
|
89
77
|
@cache[:from_element_id] != from_element_id || # cache miss, search is started from different element
|
90
78
|
skip_cache # cache is skipped
|
91
79
|
|
92
|
-
if
|
93
|
-
|
94
|
-
execute_result = from_element.find_element(uiautomator: selector)
|
95
|
-
else
|
96
|
-
execute_result = from_element.find_elements(uiautomator: selector)
|
97
|
-
end
|
98
|
-
|
99
|
-
elsif strategy == FIND_STRATEGY_XPATH
|
100
|
-
if single
|
101
|
-
execute_result = from_element.find_element(xpath: selector)
|
102
|
-
else
|
103
|
-
execute_result = from_element.find_elements(xpath: selector)
|
104
|
-
end
|
80
|
+
if single
|
81
|
+
execute_result = from_element.find_element("#{strategy}": selector)
|
105
82
|
else
|
106
|
-
|
83
|
+
execute_result = from_element.find_elements("#{strategy}": selector)
|
107
84
|
end
|
108
85
|
|
86
|
+
|
109
87
|
unless skip_cache
|
110
88
|
@cache[:selector] = selector
|
111
89
|
@cache[:strategy] = strategy
|
@@ -8,6 +8,15 @@ module TestaAppiumDriver
|
|
8
8
|
def init(params, selectors, single)
|
9
9
|
if is_scrollable_selector?(selectors, single)
|
10
10
|
@scroll_orientation = :vertical
|
11
|
+
|
12
|
+
if !params[:top].nil? || !params[:bottom].nil? || !params[:right].nil? || !params[:left].nil?
|
13
|
+
@scroll_deadzone = {}
|
14
|
+
@scroll_deadzone[:top] = params[:top].to_f unless params[:top].nil?
|
15
|
+
@scroll_deadzone[:bottom] = params[:bottom].to_f unless params[:bottom].nil?
|
16
|
+
@scroll_deadzone[:right] = params[:right].to_f unless params[:right].nil?
|
17
|
+
@scroll_deadzone[:left] = params[:left].to_f unless params[:left].nil?
|
18
|
+
end
|
19
|
+
|
11
20
|
params[:scrollable_locator] = self.dup
|
12
21
|
end
|
13
22
|
|
@@ -15,8 +24,11 @@ module TestaAppiumDriver
|
|
15
24
|
end
|
16
25
|
|
17
26
|
|
18
|
-
def
|
19
|
-
@
|
27
|
+
def strategy_and_selector
|
28
|
+
if @can_use_id_strategy
|
29
|
+
return FIND_STRATEGY_NAME, @can_use_id_strategy
|
30
|
+
end
|
31
|
+
[FIND_STRATEGY_XPATH, @xpath_selector]
|
20
32
|
end
|
21
33
|
|
22
34
|
|
data/testa_appium_driver.gemspec
CHANGED
@@ -1,40 +1,40 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "lib/testa_appium_driver/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = "testa_appium_driver"
|
7
|
-
spec.version = TestaAppiumDriver::VERSION
|
8
|
-
spec.authors = ["karlo.razumovic"]
|
9
|
-
spec.email = ["karlo.razumovic@gmail.com"]
|
10
|
-
|
11
|
-
spec.summary = "Appium made easy"
|
12
|
-
spec.description = "Testa appium driver is a wrapper around ruby_lib_core. It significantly reduces the amount of code need to achieve your goals."
|
13
|
-
spec.homepage = "https://github.com/Karazum/testa_appium_driver"
|
14
|
-
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = ">= 2.4.0"
|
16
|
-
|
17
|
-
#spec.metadata["allowed_push_host"] = "Set to 'https://mygemserver.com'"
|
18
|
-
|
19
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
-
spec.metadata["source_code_uri"] = "https://github.com/Karazum/testa_appium_driver"
|
21
|
-
spec.metadata["changelog_uri"] = "https://github.com/Karazum/testa_appium_driver"
|
22
|
-
|
23
|
-
# Specify which files should be added to the gem when it is released.
|
24
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
26
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
27
|
-
end
|
28
|
-
spec.bindir = "exe"
|
29
|
-
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
-
spec.require_paths = ["lib"]
|
31
|
-
|
32
|
-
spec.add_runtime_dependency "appium_lib_core", ["= 4.7.0"]
|
33
|
-
spec.add_runtime_dependency "json", ["
|
34
|
-
|
35
|
-
spec.add_development_dependency "rubocop", ["= 1.19.0"]
|
36
|
-
spec.add_development_dependency "rake", ["~> 13.0"]
|
37
|
-
|
38
|
-
# For more information and examples about making a new gem, checkout our
|
39
|
-
# guide at: https://bundler.io/guides/creating_gem.html
|
40
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/testa_appium_driver/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "testa_appium_driver"
|
7
|
+
spec.version = TestaAppiumDriver::VERSION
|
8
|
+
spec.authors = ["karlo.razumovic"]
|
9
|
+
spec.email = ["karlo.razumovic@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Appium made easy"
|
12
|
+
spec.description = "Testa appium driver is a wrapper around ruby_lib_core. It significantly reduces the amount of code need to achieve your goals."
|
13
|
+
spec.homepage = "https://github.com/Karazum/testa_appium_driver"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.4.0"
|
16
|
+
|
17
|
+
#spec.metadata["allowed_push_host"] = "Set to 'https://mygemserver.com'"
|
18
|
+
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/Karazum/testa_appium_driver"
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/Karazum/testa_appium_driver"
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
27
|
+
end
|
28
|
+
spec.bindir = "exe"
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
|
+
spec.require_paths = ["lib"]
|
31
|
+
|
32
|
+
spec.add_runtime_dependency "appium_lib_core", ["= 4.7.0"]
|
33
|
+
spec.add_runtime_dependency "json", [">= 2.3.0"]
|
34
|
+
|
35
|
+
spec.add_development_dependency "rubocop", ["= 1.19.0"]
|
36
|
+
spec.add_development_dependency "rake", ["~> 13.0"]
|
37
|
+
|
38
|
+
# For more information and examples about making a new gem, checkout our
|
39
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
40
|
+
end
|
data/testa_appium_driver.iml
CHANGED
@@ -39,41 +39,7 @@
|
|
39
39
|
</component>
|
40
40
|
<component name="RakeTasksCache">
|
41
41
|
<option name="myRootTask">
|
42
|
-
<RakeTaskImpl id="rake"
|
43
|
-
<subtasks>
|
44
|
-
<RakeTaskImpl description="Build testa_appium_driver-0.1.0.gem into the pkg directory" fullCommand="build" id="build" />
|
45
|
-
<RakeTaskImpl id="build">
|
46
|
-
<subtasks>
|
47
|
-
<RakeTaskImpl description="Generate SHA512 checksum if testa_appium_driver-0.1.0.gem into the checksums directory" fullCommand="build:checksum" id="checksum" />
|
48
|
-
</subtasks>
|
49
|
-
</RakeTaskImpl>
|
50
|
-
<RakeTaskImpl description="Remove any temporary products" fullCommand="clean" id="clean" />
|
51
|
-
<RakeTaskImpl description="Remove any generated files" fullCommand="clobber" id="clobber" />
|
52
|
-
<RakeTaskImpl description="Build and install testa_appium_driver-0.1.0.gem into system gems" fullCommand="install" id="install" />
|
53
|
-
<RakeTaskImpl id="install">
|
54
|
-
<subtasks>
|
55
|
-
<RakeTaskImpl description="Build and install testa_appium_driver-0.1.0.gem into system gems without network access" fullCommand="install:local" id="local" />
|
56
|
-
</subtasks>
|
57
|
-
</RakeTaskImpl>
|
58
|
-
<RakeTaskImpl description="Create tag v0.1.0 and build and push testa_appium_driver-0.1.0.gem to rubygems.org" fullCommand="release[remote]" id="release[remote]" />
|
59
|
-
<RakeTaskImpl description="Run RuboCop" fullCommand="rubocop" id="rubocop" />
|
60
|
-
<RakeTaskImpl id="rubocop">
|
61
|
-
<subtasks>
|
62
|
-
<RakeTaskImpl description="Auto-correct RuboCop offenses" fullCommand="rubocop:auto_correct" id="auto_correct" />
|
63
|
-
</subtasks>
|
64
|
-
</RakeTaskImpl>
|
65
|
-
<RakeTaskImpl description="Run RSpec code examples" fullCommand="spec" id="spec" />
|
66
|
-
<RakeTaskImpl description="" fullCommand="default" id="default" />
|
67
|
-
<RakeTaskImpl description="" fullCommand="release" id="release" />
|
68
|
-
<RakeTaskImpl id="release">
|
69
|
-
<subtasks>
|
70
|
-
<RakeTaskImpl description="" fullCommand="release:guard_clean" id="guard_clean" />
|
71
|
-
<RakeTaskImpl description="" fullCommand="release:rubygem_push" id="rubygem_push" />
|
72
|
-
<RakeTaskImpl description="" fullCommand="release:source_control_push" id="source_control_push" />
|
73
|
-
</subtasks>
|
74
|
-
</RakeTaskImpl>
|
75
|
-
</subtasks>
|
76
|
-
</RakeTaskImpl>
|
42
|
+
<RakeTaskImpl id="rake" />
|
77
43
|
</option>
|
78
44
|
</component>
|
79
45
|
</module>
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: testa_appium_driver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- karlo.razumovic
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.3.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 2.
|
40
|
+
version: 2.3.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +109,7 @@ files:
|
|
109
109
|
- lib/testa_appium_driver/common/scroll_actions.rb
|
110
110
|
- lib/testa_appium_driver/common/scroll_actions/json_wire_scroll_actions.rb
|
111
111
|
- lib/testa_appium_driver/common/scroll_actions/w3c_scroll_actions.rb
|
112
|
+
- lib/testa_appium_driver/common/selenium_element.rb
|
112
113
|
- lib/testa_appium_driver/driver.rb
|
113
114
|
- lib/testa_appium_driver/ios/driver.rb
|
114
115
|
- lib/testa_appium_driver/ios/locator.rb
|