testa_appium_driver 0.1.21 → 0.1.24
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/.gitattributes +23 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.rubocop.yml +6 -0
- data/Gemfile.lock +1 -1
- data/bin/console +17 -0
- data/bin/setup +8 -0
- data/lib/testa_appium_driver/android/class_selectors.rb +438 -0
- data/lib/testa_appium_driver/android/driver.rb +71 -0
- data/lib/testa_appium_driver/android/locator/attributes.rb +115 -0
- data/lib/testa_appium_driver/android/locator.rb +142 -0
- data/lib/testa_appium_driver/android/scroll_actions/uiautomator_scroll_actions.rb +62 -0
- data/lib/testa_appium_driver/android/selenium_element.rb +12 -0
- data/lib/testa_appium_driver/common/bounds.rb +150 -0
- data/lib/testa_appium_driver/common/constants.rb +38 -0
- data/lib/testa_appium_driver/common/exceptions/strategy_mix_exception.rb +12 -0
- data/lib/testa_appium_driver/common/helpers.rb +272 -0
- data/lib/testa_appium_driver/common/locator/scroll_actions.rb +390 -0
- data/lib/testa_appium_driver/common/locator.rb +640 -0
- data/lib/testa_appium_driver/common/scroll_actions/json_wire_scroll_actions.rb +4 -0
- data/lib/testa_appium_driver/common/scroll_actions/w3c_scroll_actions.rb +380 -0
- data/lib/testa_appium_driver/common/scroll_actions.rb +275 -0
- data/lib/testa_appium_driver/common/selenium_element.rb +19 -0
- data/lib/testa_appium_driver/driver.rb +338 -0
- data/lib/testa_appium_driver/ios/driver.rb +49 -0
- data/lib/testa_appium_driver/ios/locator/attributes.rb +89 -0
- data/lib/testa_appium_driver/ios/locator.rb +73 -0
- data/lib/testa_appium_driver/ios/selenium_element.rb +8 -0
- data/lib/testa_appium_driver/ios/type_selectors.rb +201 -0
- data/lib/testa_appium_driver.rb +4 -0
- data/testa_appium_driver.gemspec +6 -2
- metadata +39 -11
- data/appium-driver.iml +0 -79
@@ -0,0 +1,380 @@
|
|
1
|
+
module ::TestaAppiumDriver
|
2
|
+
module W3cScrollActions
|
3
|
+
# @return [Array]
|
4
|
+
def w3c_scroll_each(direction, &block)
|
5
|
+
default_deadzone!
|
6
|
+
if direction.nil?
|
7
|
+
scroll_to_start
|
8
|
+
if @scrollable.scroll_orientation == :vertical
|
9
|
+
direction = :down
|
10
|
+
else
|
11
|
+
direction = :right
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
case direction
|
16
|
+
when :up
|
17
|
+
align_with = :bottom
|
18
|
+
when :down
|
19
|
+
align_with = :top
|
20
|
+
when :right
|
21
|
+
align_with = :left
|
22
|
+
when :left
|
23
|
+
align_with = :right
|
24
|
+
else
|
25
|
+
align_with = :top
|
26
|
+
end
|
27
|
+
|
28
|
+
if @driver.ios?
|
29
|
+
# if true
|
30
|
+
w3c_scroll_each_ios(direction, align_with, &block)
|
31
|
+
else
|
32
|
+
w3c_scroll_each_android(direction, align_with, &block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def w3c_scroll_each_android(direction, align_with, &block)
|
37
|
+
elements = []
|
38
|
+
begin
|
39
|
+
|
40
|
+
iterations = 0
|
41
|
+
ignore_element_ids = []
|
42
|
+
previous_element = nil
|
43
|
+
|
44
|
+
until is_end_of_scroll?
|
45
|
+
# # $__.puts "-- new iteration"
|
46
|
+
# # $__.puts "-------------"
|
47
|
+
aligned_items = 0
|
48
|
+
new_ignore_element_ids = []
|
49
|
+
matches = @locator.execute(skip_cache: true)
|
50
|
+
matches.each_with_index do |m, index|
|
51
|
+
# # $__.puts "Matches: #{matches.count}"
|
52
|
+
# # $__.puts "M: #{m.id}"
|
53
|
+
if ignore_element_ids.include?(m.id)
|
54
|
+
previous_element = m
|
55
|
+
next
|
56
|
+
end
|
57
|
+
|
58
|
+
sa = self.dup
|
59
|
+
sa.locator = m
|
60
|
+
sa.w3c_align(align_with, false, 1, speed_coef: 2.0)
|
61
|
+
is_aligned = sa.is_aligned?(align_with, m)
|
62
|
+
|
63
|
+
# add the previous to ignore if current is not aligned (probably means we cannot scroll any further)
|
64
|
+
new_ignore_element_ids << previous_element.id if !is_aligned && !previous_element.nil?
|
65
|
+
|
66
|
+
aligned_items += 1 if is_aligned
|
67
|
+
|
68
|
+
# add last element to ignore
|
69
|
+
new_ignore_element_ids << m.id if matches.count == index + 1
|
70
|
+
|
71
|
+
elements << m
|
72
|
+
if block_given? # block is given
|
73
|
+
@locator.driver.invalidate_cache
|
74
|
+
block.call(m) # use call to execute the block
|
75
|
+
else
|
76
|
+
# the value of block_argument becomes nil if you didn't give a block
|
77
|
+
# block was not given
|
78
|
+
end
|
79
|
+
previous_element = m
|
80
|
+
end
|
81
|
+
|
82
|
+
iterations += 1
|
83
|
+
break if !@max_scrolls.nil? && iterations == @max_scrolls
|
84
|
+
|
85
|
+
if aligned_items.zero?
|
86
|
+
self.send("page_#{direction}")
|
87
|
+
else
|
88
|
+
ignore_element_ids = new_ignore_element_ids.dup
|
89
|
+
end
|
90
|
+
end
|
91
|
+
rescue StandardError => e
|
92
|
+
raise e
|
93
|
+
end
|
94
|
+
|
95
|
+
elements
|
96
|
+
end
|
97
|
+
|
98
|
+
def w3c_scroll_each_ios(direction, align_with, &block)
|
99
|
+
elements = []
|
100
|
+
elements_in_current_iteration = []
|
101
|
+
begin
|
102
|
+
iterations = 0
|
103
|
+
|
104
|
+
loop do
|
105
|
+
elements_in_last_iteration = elements_in_current_iteration
|
106
|
+
elements_in_current_iteration = []
|
107
|
+
elements_count_before_iteration = elements.count
|
108
|
+
|
109
|
+
new_element_in_this_iteration_found = false
|
110
|
+
matches = @locator.execute(skip_cache: true)
|
111
|
+
matches.each do |m|
|
112
|
+
elements_in_current_iteration << m.id
|
113
|
+
|
114
|
+
element_found_in_last_iteration = elements_in_last_iteration.include?(m.id)
|
115
|
+
|
116
|
+
# ignore all elements from last iteration until first new element is found
|
117
|
+
if !new_element_in_this_iteration_found && element_found_in_last_iteration
|
118
|
+
next
|
119
|
+
end
|
120
|
+
|
121
|
+
# new element in this iteration is found,
|
122
|
+
# process all remaining elements regardless if it is found in last iteration or not
|
123
|
+
new_element_in_this_iteration_found = true
|
124
|
+
|
125
|
+
sa = self.dup
|
126
|
+
sa.locator = m
|
127
|
+
sa.w3c_align(align_with, false, 1, speed_coef: 2.0)
|
128
|
+
|
129
|
+
elements << m.id
|
130
|
+
if block_given? # block is given
|
131
|
+
@locator.driver.invalidate_cache
|
132
|
+
block.call(m) # use call to execute the block
|
133
|
+
else
|
134
|
+
# the value of block_argument becomes nil if you didn't give a block
|
135
|
+
# block was not given
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
iterations += 1
|
140
|
+
break if !@max_scrolls.nil? && iterations == @max_scrolls
|
141
|
+
|
142
|
+
if matches.count.positive?
|
143
|
+
# if there are elements on screen, but there are no new elements
|
144
|
+
# then we have reached the end of scrolling
|
145
|
+
if elements.count == elements_count_before_iteration
|
146
|
+
return elements
|
147
|
+
end
|
148
|
+
else
|
149
|
+
# there are no matching elements. to detect end of scroll,
|
150
|
+
# first and last leaf is compared before with first and last leaf of previous iteration
|
151
|
+
if is_end_of_scroll?
|
152
|
+
return elements
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# if there are more than 1 match on screen,
|
157
|
+
# the page is scrolled by aligning elements 1 by one,
|
158
|
+
# but if there is only 1, or none elements.
|
159
|
+
# then scroll the page manually
|
160
|
+
self.send("page_#{direction}") if matches.count < 2
|
161
|
+
end
|
162
|
+
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
163
|
+
# if boundElementsByIndex is enabled, we can get stale element reference while doing scroll each
|
164
|
+
retry
|
165
|
+
rescue StandardError => e
|
166
|
+
raise e
|
167
|
+
end
|
168
|
+
|
169
|
+
elements
|
170
|
+
end
|
171
|
+
|
172
|
+
def w3c_align(with, scroll_to_find, max_attempts, speed_coef: 1.25)
|
173
|
+
default_deadzone!
|
174
|
+
|
175
|
+
@locator.scroll_to if scroll_to_find
|
176
|
+
|
177
|
+
if @locator.instance_of?(TestaAppiumDriver::Locator)
|
178
|
+
element = @locator.execute
|
179
|
+
else
|
180
|
+
element = @locator
|
181
|
+
end
|
182
|
+
|
183
|
+
max_attempts = 3 if max_attempts.nil? || max_attempts <= 0
|
184
|
+
# $ctx.puts("Is aligned: #{is_aligned?(with, element)}")
|
185
|
+
timeout = 0
|
186
|
+
stale_retries = 0
|
187
|
+
begin
|
188
|
+
until is_aligned?(with, element) || timeout == max_attempts
|
189
|
+
# $ctx.puts("align roudn: #{timeout}")
|
190
|
+
w3c_attempt_align(with, speed_coef)
|
191
|
+
timeout += 1
|
192
|
+
end
|
193
|
+
rescue Selenium::WebDriver::Error::StaleElementReferenceError
|
194
|
+
# if boundElementsByIndex is enabled, we can get stale element reference while doing scroll each
|
195
|
+
stale_retries += 1
|
196
|
+
element = @locator.execute if @locator.instance_of?(TestaAppiumDriver::Locator)
|
197
|
+
retry if stale_retries < 2
|
198
|
+
end
|
199
|
+
# $ctx.puts("end align")
|
200
|
+
end
|
201
|
+
|
202
|
+
def w3c_attempt_align(with, speed_coef)
|
203
|
+
case with
|
204
|
+
when :top
|
205
|
+
y0 = @bounds.bottom_right.y - @deadzone[:bottom]
|
206
|
+
y1 = y0 - @align_offset
|
207
|
+
x0 = @bounds.width / 2
|
208
|
+
x1 = x0
|
209
|
+
scroll_direction = :down
|
210
|
+
when :bottom
|
211
|
+
y0 = @bounds.top_left.y + @deadzone[:top]
|
212
|
+
y1 = y0 + @align_offset
|
213
|
+
x0 = @bounds.width / 2
|
214
|
+
x1 = x0
|
215
|
+
scroll_direction = :up
|
216
|
+
when :left
|
217
|
+
x0 = @bounds.bottom_right.x - @deadzone[:right]
|
218
|
+
x1 = x0 - @align_offset
|
219
|
+
y0 = @bounds.height / 2
|
220
|
+
y1 = y0
|
221
|
+
scroll_direction = :right
|
222
|
+
when :right
|
223
|
+
x0 = @bounds.top_left.x + @deadzone[:top]
|
224
|
+
x1 = x0 + @align_offset
|
225
|
+
y0 = @bounds.height / 2
|
226
|
+
y1 = y0
|
227
|
+
scroll_direction = :left
|
228
|
+
else
|
229
|
+
raise "Unsupported align with option: #{with}"
|
230
|
+
end
|
231
|
+
|
232
|
+
x1, y1 = apply_w3c_correction(x1, y1, scroll_direction) if @driver.device == :android
|
233
|
+
w3c_action(x0, y0, x1, y1, SCROLL_ACTION_TYPE_SCROLL, speed_coef: speed_coef)
|
234
|
+
end
|
235
|
+
|
236
|
+
def w3c_scroll_to(direction)
|
237
|
+
rounds = 0
|
238
|
+
max_scrolls_reached = false
|
239
|
+
end_of_scroll_reached = false
|
240
|
+
# $ctx.puts("starting scroll to")
|
241
|
+
until (@driver.android? && @locator.exists?) ||
|
242
|
+
(@driver.ios? && @locator.exists? && @locator.in_viewport?) || end_of_scroll_reached
|
243
|
+
# $ctx.puts("Scroll to round: #{rounds}")
|
244
|
+
end_of_scroll_reached = is_end_of_scroll?
|
245
|
+
case direction
|
246
|
+
when :down
|
247
|
+
page_down
|
248
|
+
when :right
|
249
|
+
page_right
|
250
|
+
when :left
|
251
|
+
page_left
|
252
|
+
when :up
|
253
|
+
page_up
|
254
|
+
else
|
255
|
+
scroll_to_start
|
256
|
+
@previous_elements = nil
|
257
|
+
if @scrollable.scroll_orientation == :vertical
|
258
|
+
direction = :down
|
259
|
+
else
|
260
|
+
direction = :right
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
rounds += 1
|
265
|
+
|
266
|
+
max_scrolls_reached = true if rounds == @max_scrolls
|
267
|
+
break if rounds == @max_scrolls
|
268
|
+
end
|
269
|
+
# $ctx.puts("end scroll to")
|
270
|
+
raise Selenium::WebDriver::Error::NoSuchElementError if max_scrolls_reached || end_of_scroll_reached
|
271
|
+
end
|
272
|
+
|
273
|
+
def w3c_scroll_to_start_or_end(type)
|
274
|
+
default_deadzone!
|
275
|
+
|
276
|
+
@previous_elements = nil
|
277
|
+
|
278
|
+
if type == :start
|
279
|
+
if @scrollable.scroll_orientation == :vertical
|
280
|
+
method = "fling_up"
|
281
|
+
else
|
282
|
+
method = "fling_left"
|
283
|
+
end
|
284
|
+
else
|
285
|
+
if @scrollable.scroll_orientation == :vertical
|
286
|
+
method = "fling_down"
|
287
|
+
else
|
288
|
+
method = "fling_right"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
iterations = 0
|
293
|
+
until is_end_of_scroll? || iterations >= 3
|
294
|
+
self.send(method)
|
295
|
+
iterations += 1
|
296
|
+
end
|
297
|
+
|
298
|
+
# reset the flag for end of scroll elements
|
299
|
+
@previous_elements = nil
|
300
|
+
end
|
301
|
+
|
302
|
+
def w3c_page_or_fling(type, direction)
|
303
|
+
default_deadzone!
|
304
|
+
|
305
|
+
if direction == :down || direction == :up
|
306
|
+
if direction == :down
|
307
|
+
y0 = @bounds.bottom_right.y - @deadzone[:bottom].to_i
|
308
|
+
y1 = @bounds.top_left.y + @deadzone[:top].to_i
|
309
|
+
else
|
310
|
+
y0 = @bounds.top_left.y + @deadzone[:top].to_i
|
311
|
+
y1 = @bounds.bottom_right.y - @deadzone[:bottom].to_i
|
312
|
+
end
|
313
|
+
x0 = @bounds.top_left.x + (@bounds.width - @deadzone[:left].to_i - @deadzone[:right].to_i) / 2
|
314
|
+
x0 = @bounds.top_left.x if x0 < @bounds.top_left.x
|
315
|
+
x0 = @bounds.bottom_right.x if x0 > @bounds.bottom_right.x
|
316
|
+
x1 = x0
|
317
|
+
else
|
318
|
+
if direction == :right
|
319
|
+
x0 = @bounds.bottom_right.x - @deadzone[:right].to_i
|
320
|
+
x1 = @bounds.top_left.x + @deadzone[:left].to_i
|
321
|
+
else
|
322
|
+
x0 = @bounds.top_left.x + @deadzone[:left].to_i
|
323
|
+
x1 = @bounds.bottom_right.x - @deadzone[:right].to_i
|
324
|
+
end
|
325
|
+
|
326
|
+
y0 = @bounds.top_left.y + (@bounds.height - @deadzone[:top].to_i - @deadzone[:bottom].to_i) / 2
|
327
|
+
y0 = @bounds.top_left.y if y0 < @bounds.top_left.y
|
328
|
+
y0 = @bounds.bottom_right.y if y0 > @bounds.bottom_right.y
|
329
|
+
y1 = y0
|
330
|
+
end
|
331
|
+
x1, y1 = apply_w3c_correction(x1, y1, direction) if @driver.device == :android
|
332
|
+
|
333
|
+
speed_coef = 1
|
334
|
+
speed_coef = 1.5 if type == SCROLL_ACTION_TYPE_SCROLL
|
335
|
+
|
336
|
+
w3c_action(x0, y0, x1, y1, type, speed_coef: speed_coef)
|
337
|
+
end
|
338
|
+
|
339
|
+
def w3c_action(x0, y0, x1, y1, type, speed_coef: 1.0)
|
340
|
+
speed_coef = 1 / speed_coef
|
341
|
+
if type == SCROLL_ACTION_TYPE_SCROLL
|
342
|
+
duration = 1.8 * speed_coef
|
343
|
+
elsif type == SCROLL_ACTION_TYPE_FLING
|
344
|
+
duration = 0.1 * speed_coef
|
345
|
+
elsif type == SCROLL_ACTION_TYPE_DRAG
|
346
|
+
duration = 3.5 * speed_coef
|
347
|
+
else
|
348
|
+
raise "Unknown scroll action type #{type}"
|
349
|
+
end
|
350
|
+
|
351
|
+
action_builder = @driver.action
|
352
|
+
f1 = action_builder.add_pointer_input(:touch, "finger1")
|
353
|
+
f1.create_pointer_move(duration: 0, x: x0, y: y0, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
354
|
+
f1.create_pointer_down(:left)
|
355
|
+
|
356
|
+
f1.create_pointer_move(duration: duration, x: x1, y: y1, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
357
|
+
unless type == SCROLL_ACTION_TYPE_FLING
|
358
|
+
# with this move we prevent flinging/overscroll
|
359
|
+
overscroll_pause = @driver.ios? ? 1 : 0.5
|
360
|
+
f1.create_pointer_move(duration: overscroll_pause, x: x1, y: y1, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
361
|
+
end
|
362
|
+
f1.create_pointer_up(:left)
|
363
|
+
puts "Scroll execute[w3c_action]: #{type}: {x0: #{x0}, y0: #{y0}} => (duration: #{duration}) => {x1: #{x1}, y1: #{y1}}"
|
364
|
+
# $ctx.puts "Scroll execute[w3c_action]: #{type}: {x0: #{x0}, y0: #{y0}} => (duration: #{duration}) => {x1: #{x1}, y1: #{y1}}"
|
365
|
+
@driver.perform_actions [f1]
|
366
|
+
end
|
367
|
+
|
368
|
+
def apply_w3c_correction(x1, y1, direction)
|
369
|
+
y1 -= SCROLL_CORRECTION_W3C if direction == :down
|
370
|
+
y1 += SCROLL_CORRECTION_W3C if direction == :up
|
371
|
+
x1 -= SCROLL_CORRECTION_W3C if direction == :right
|
372
|
+
x1 += SCROLL_CORRECTION_W3C if direction == :left
|
373
|
+
[x1, y1]
|
374
|
+
end
|
375
|
+
|
376
|
+
def w3c_drag_to(x0, y0, x1, y1)
|
377
|
+
w3c_action(x0, y0, x1, y1, SCROLL_ACTION_TYPE_DRAG)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
@@ -0,0 +1,275 @@
|
|
1
|
+
require_relative 'scroll_actions/json_wire_scroll_actions'
|
2
|
+
require_relative 'scroll_actions/w3c_scroll_actions'
|
3
|
+
|
4
|
+
module ::TestaAppiumDriver
|
5
|
+
|
6
|
+
# Class for handling scroll actions
|
7
|
+
class ScrollActions
|
8
|
+
include W3cScrollActions
|
9
|
+
include JsonWireScrollActions
|
10
|
+
|
11
|
+
attr_accessor :locator
|
12
|
+
# @param [TestaAppiumDriver::Locator, nil] scrollable container that will be used to determine the bounds for scrolling
|
13
|
+
# @param [Hash] params
|
14
|
+
# acceptable params
|
15
|
+
# - locator - element that should be found with scrolling actions
|
16
|
+
# - deadzone - [Hash] that stores top, bottom, left and right deadzone values. If deadzone[:top] is 200 then 200px from top of the scrollable container will not be used for scrolling
|
17
|
+
# - max_scrolls - [Integer] maximum number of scrolls before exception is thrown
|
18
|
+
# - default_scroll_strategy - defines which scroll strategy will be used if a scroll action is valid for multiple strategies
|
19
|
+
def initialize(scrollable, params = {})
|
20
|
+
@scrollable = scrollable
|
21
|
+
@locator = params[:locator]
|
22
|
+
# TODO: raise error if locator is for multiple, but not for scroll each, chekc other cases aswell
|
23
|
+
@deadzone = params[:deadzone]
|
24
|
+
@max_scrolls = params[:max_scrolls]
|
25
|
+
@default_scroll_strategy = params[:default_scroll_strategy]
|
26
|
+
@driver = @locator.driver
|
27
|
+
|
28
|
+
if @scrollable.nil?
|
29
|
+
# if we dont have a scrollable element or if we do have it, but it is not compatible with uiautomator
|
30
|
+
# then find first scrollable in document
|
31
|
+
@scrollable = @driver.scrollable
|
32
|
+
end
|
33
|
+
|
34
|
+
@strategy = nil
|
35
|
+
if @scrollable.strategy == FIND_STRATEGY_XPATH || # uiautomator cannot resolve scrollable from a xpath locator
|
36
|
+
!@deadzone.nil? ||
|
37
|
+
!@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver) # uiautomator cannot resolve nested scrollable
|
38
|
+
@strategy = SCROLL_STRATEGY_W3C
|
39
|
+
end
|
40
|
+
|
41
|
+
@bounds = @scrollable.bounds
|
42
|
+
end
|
43
|
+
|
44
|
+
def align(with, scroll_to_find, max_attempts)
|
45
|
+
w3c_align(with, scroll_to_find, max_attempts)
|
46
|
+
@locator
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Array]
|
50
|
+
def scroll_each(&block)
|
51
|
+
w3c_scroll_each(nil, &block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def scroll_each_down(&block)
|
55
|
+
w3c_scroll_each(:down, &block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def scroll_each_up(&block)
|
59
|
+
w3c_scroll_each(:up, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
def scroll_each_right(&block)
|
63
|
+
w3c_scroll_each(:right, &block)
|
64
|
+
end
|
65
|
+
|
66
|
+
def scroll_each_left(&block)
|
67
|
+
w3c_scroll_each(:left, &block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def resolve_strategy
|
71
|
+
if @strategy.nil?
|
72
|
+
@default_scroll_strategy
|
73
|
+
else
|
74
|
+
@strategy
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def scroll_to
|
79
|
+
if @locator.strategy != FIND_STRATEGY_XPATH && resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
80
|
+
uiautomator_scroll_to
|
81
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
82
|
+
w3c_scroll_to(nil)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def scroll_down_to
|
87
|
+
w3c_scroll_to(:down)
|
88
|
+
end
|
89
|
+
|
90
|
+
def scroll_up_to
|
91
|
+
w3c_scroll_to(:up)
|
92
|
+
end
|
93
|
+
|
94
|
+
def scroll_right_to
|
95
|
+
w3c_scroll_to(:right)
|
96
|
+
end
|
97
|
+
|
98
|
+
def scroll_left_to
|
99
|
+
w3c_scroll_to(:left)
|
100
|
+
end
|
101
|
+
|
102
|
+
def page_next
|
103
|
+
if @scrollable.scroll_orientation == :vertical
|
104
|
+
page_down
|
105
|
+
else
|
106
|
+
page_left
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def page_back
|
111
|
+
if @scrollable.scroll_orientation == :vertical
|
112
|
+
page_up
|
113
|
+
else
|
114
|
+
page_right
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def page_down
|
119
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
120
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :down)
|
121
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
122
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :down)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def page_right
|
127
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
128
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :right)
|
129
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
130
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :right)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def page_up
|
135
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
136
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :up)
|
137
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
138
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :up)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def page_left
|
143
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
144
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :left)
|
145
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
146
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :left)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def scroll_to_start
|
151
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
152
|
+
uiautomator_scroll_to_start_or_end(:start)
|
153
|
+
|
154
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
155
|
+
w3c_scroll_to_start_or_end(:start)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def scroll_to_end
|
160
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
161
|
+
uiautomator_scroll_to_start_or_end(:end)
|
162
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
163
|
+
w3c_scroll_to_start_or_end(:end)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def fling_down
|
168
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
169
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :down)
|
170
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
171
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :down)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def fling_right
|
176
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
177
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :right)
|
178
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
179
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :right)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def fling_up
|
184
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
185
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :up)
|
186
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
187
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :up)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def fling_left
|
192
|
+
if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
|
193
|
+
uiautomator_page_or_fling(SCROLL_ACTION_TYPE_FLING, :left)
|
194
|
+
elsif resolve_strategy == SCROLL_STRATEGY_W3C
|
195
|
+
w3c_page_or_fling(SCROLL_ACTION_TYPE_FLING, :left)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def drag_to(x, y)
|
200
|
+
b = @locator.bounds
|
201
|
+
coords = b.center
|
202
|
+
w3c_drag_to(coords.x, coords.y, x, y)
|
203
|
+
end
|
204
|
+
|
205
|
+
|
206
|
+
|
207
|
+
|
208
|
+
def is_aligned?(with, element)
|
209
|
+
align_bounds = @locator.bounds(force_cache_element: element)
|
210
|
+
case with
|
211
|
+
when :top
|
212
|
+
@align_offset = align_bounds.top_left.y - @bounds.top_left.y - @deadzone[:top]
|
213
|
+
when :bottom
|
214
|
+
@align_offset = @bounds.bottom_right.y - @deadzone[:bottom] - align_bounds.bottom_right.y
|
215
|
+
when :right
|
216
|
+
@align_offset = @bounds.bottom_right.x - @deadzone[:right] - align_bounds.bottom_right.x
|
217
|
+
when :left
|
218
|
+
@align_offset = align_bounds.top_left.x - @bounds.top_left.x - @deadzone[:left]
|
219
|
+
else
|
220
|
+
raise "Unsupported align with option: #{with}"
|
221
|
+
end
|
222
|
+
@align_offset < SCROLL_ALIGNMENT_THRESHOLD
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
|
227
|
+
def is_end_of_scroll?
|
228
|
+
# if @driver.device == :android
|
229
|
+
|
230
|
+
old_elements = @previous_elements
|
231
|
+
@previous_elements = @scrollable.first_and_last_leaf
|
232
|
+
|
233
|
+
|
234
|
+
# $__.puts "old: #{old_elements}"
|
235
|
+
# $__.puts "new: #{@previous_elements}"
|
236
|
+
# $__.puts "end_of_scroll? #{ old_elements == @previous_elements}"
|
237
|
+
old_elements == @previous_elements
|
238
|
+
# else
|
239
|
+
# # for ios, check location of first and last elements
|
240
|
+
# old_elements = @previous_elements
|
241
|
+
# @previous_elements = @scrollable.first_and_last_child&.map(&:location)
|
242
|
+
# # $__.puts "old:"
|
243
|
+
# # $__.puts old_elements
|
244
|
+
# # $__.puts "prev:"
|
245
|
+
# # $__.puts @previous_elements
|
246
|
+
# old_elements == @previous_elements
|
247
|
+
# end
|
248
|
+
end
|
249
|
+
|
250
|
+
def default_deadzone!
|
251
|
+
@deadzone = {} if @deadzone.nil?
|
252
|
+
if @deadzone[:top].nil?
|
253
|
+
@deadzone[:top] = 1
|
254
|
+
else
|
255
|
+
@deadzone[:top] = @deadzone[:top].to_f
|
256
|
+
end
|
257
|
+
if @deadzone[:bottom].nil?
|
258
|
+
@deadzone[:bottom] = 1
|
259
|
+
else
|
260
|
+
@deadzone[:bottom] = @deadzone[:bottom].to_f
|
261
|
+
end
|
262
|
+
if @deadzone[:right].nil?
|
263
|
+
@deadzone[:right] = 1
|
264
|
+
else
|
265
|
+
@deadzone[:right] = @deadzone[:right].to_f
|
266
|
+
end
|
267
|
+
if @deadzone[:left].nil?
|
268
|
+
@deadzone[:left] = 1
|
269
|
+
else
|
270
|
+
@deadzone[:left] = @deadzone[:left].to_f
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ::Appium
|
2
|
+
module Core
|
3
|
+
class Element
|
4
|
+
# sets the testa appium driver instance for the current phone
|
5
|
+
def self.set_driver(driver, udid)
|
6
|
+
udid = "unknown" if udid.nil?
|
7
|
+
@@drivers ||= {}
|
8
|
+
@@drivers[udid] = driver
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [TestaAppiumDriver::Driver] testa appium driver instance for the current phone
|
12
|
+
def get_driver
|
13
|
+
udid = @bridge.capabilities.instance_variable_get(:@capabilities)["udid"]
|
14
|
+
udid = "unknown" if udid.nil?
|
15
|
+
@@drivers[udid]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|