testa_appium_driver 0.1.13 → 0.1.14
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 +0 -2
- data/.rubocop.yml +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +74 -0
- data/appium-driver.iml +72 -0
- data/lib/testa_appium_driver/android/class_selectors.rb +7 -7
- data/lib/testa_appium_driver/android/driver.rb +1 -0
- data/lib/testa_appium_driver/android/locator/attributes.rb +29 -25
- data/lib/testa_appium_driver/android/locator.rb +1 -1
- data/lib/testa_appium_driver/android/selenium_element.rb +6 -2
- data/lib/testa_appium_driver/common/constants.rb +2 -1
- data/lib/testa_appium_driver/common/locator/scroll_actions.rb +33 -33
- data/lib/testa_appium_driver/common/locator.rb +42 -25
- data/lib/testa_appium_driver/common/scroll_actions/json_wire_scroll_actions.rb +1 -1
- data/lib/testa_appium_driver/common/scroll_actions/w3c_scroll_actions.rb +87 -20
- data/lib/testa_appium_driver/common/scroll_actions.rb +26 -19
- data/lib/testa_appium_driver/common/selenium_element.rb +2 -2
- data/lib/testa_appium_driver/driver.rb +33 -19
- data/lib/testa_appium_driver/ios/locator/attributes.rb +24 -20
- data/lib/testa_appium_driver/ios/locator.rb +1 -0
- data/lib/testa_appium_driver/ios/selenium_element.rb +2 -2
- data/lib/testa_appium_driver/ios/type_selectors.rb +2 -2
- data/lib/testa_appium_driver/version.rb +1 -1
- data/testa_appium_driver.gemspec +1 -1
- metadata +7 -14
- data/.idea/deployment.xml +0 -22
- data/.idea/inspectionProfiles/Project_Default.xml +0 -9
- data/.idea/misc.xml +0 -6
- data/.idea/modules.xml +0 -8
- data/.idea/runConfigurations/Android_Test.xml +0 -42
- data/.idea/runConfigurations.xml +0 -10
- data/.idea/sshConfigs.xml +0 -13
- data/.idea/vcs.xml +0 -6
- data/.idea/webServers.xml +0 -21
- data/testa_appium_driver.iml +0 -41
@@ -6,6 +6,7 @@ module TestaAppiumDriver
|
|
6
6
|
class Locator
|
7
7
|
include Helpers
|
8
8
|
|
9
|
+
|
9
10
|
attr_accessor :xpath_selector
|
10
11
|
attr_accessor :single
|
11
12
|
|
@@ -59,9 +60,9 @@ module TestaAppiumDriver
|
|
59
60
|
end
|
60
61
|
|
61
62
|
selectors[:id] = selectors[:name] unless selectors[:name].nil?
|
62
|
-
if from_element.instance_of?(Selenium::WebDriver::Element)
|
63
|
-
@xpath_selector = "
|
64
|
-
@xpath_selector += hash_to_xpath(@driver.device, selectors, single)
|
63
|
+
if from_element.instance_of?(::Selenium::WebDriver::Element) || from_element.instance_of?(::Appium::Core::Element) || from_element.instance_of?(::TestaAppiumDriver::Locator)
|
64
|
+
@xpath_selector = "."
|
65
|
+
@xpath_selector += hash_to_xpath(@driver.device, selectors, single)
|
65
66
|
else
|
66
67
|
@xpath_selector = hash_to_xpath(@driver.device, selectors, single)
|
67
68
|
end
|
@@ -122,8 +123,8 @@ module TestaAppiumDriver
|
|
122
123
|
# elements[2] will be resolved with xpath because we are looking for multiple elements from element
|
123
124
|
# and since we are looking for instance 2, [](instance) method will return new "empty locator"
|
124
125
|
# we are executing click on that "empty locator" so we have to return the instance 2 of elements for the click
|
125
|
-
if @xpath_selector == "
|
126
|
-
return @from_element if @from_element.instance_of?(Selenium::WebDriver::Element)
|
126
|
+
if @xpath_selector == ".//*[1]" && !@from_element.nil? && @image_selector.nil?
|
127
|
+
return @from_element if @from_element.instance_of?(::Selenium::WebDriver::Element) || @from_element.instance_of?(::Appium::Core::Element)
|
127
128
|
return @from_element.execute(skip_cache: skip_cache, force_cache_element: force_cache_element, ignore_implicit_wait: ignore_implicit_wait) if @from_element.instance_of?(TestaAppiumDriver::Locator)
|
128
129
|
return @from_element
|
129
130
|
end
|
@@ -302,38 +303,44 @@ module TestaAppiumDriver
|
|
302
303
|
@driver.first_and_last_leaf(execute)
|
303
304
|
end
|
304
305
|
|
305
|
-
|
306
|
-
|
307
|
-
click(x, y)
|
306
|
+
def double_click(x = nil, y = nil)
|
307
|
+
click(x,y, double: true)
|
308
308
|
end
|
309
309
|
|
310
|
+
|
311
|
+
|
310
312
|
# if both x or y, or both are not given, will click in the center of the element
|
311
313
|
# @param x If positive integer, will offset the click from the left side, if negative integer, will offset the click from the right. If float value is given, it will threat it as percentage offset, giving it 0.5 will click in the middle
|
312
314
|
# @param y If positive integer, will offset the click from the bottom side, if negative integer, will offset the click from the top. If float value is given, it will threat it as percentage offset, giving it 0.5 will click in the middle
|
313
|
-
def click(x = nil, y = nil)
|
314
|
-
if !x.nil? && !y.nil?
|
315
|
+
def click(x = nil, y = nil, double: false)
|
316
|
+
if !x.nil? && !y.nil? || double
|
317
|
+
|
318
|
+
x=0.5 if x.nil?
|
319
|
+
y=0.5 if y.nil?
|
315
320
|
|
316
321
|
b = self.bounds
|
317
|
-
if x.kind_of?
|
322
|
+
if x.kind_of?(Integer)
|
318
323
|
if x >= 0
|
319
324
|
x = b.top_left.x + x
|
320
325
|
else
|
321
326
|
x = b.bottom_right.x + x
|
322
327
|
end
|
323
|
-
elsif x.kind_of?
|
328
|
+
elsif x.kind_of?(Float) && x <= 1.0 && x >= 0
|
324
329
|
x = b.top_left.x + b.width*x
|
325
330
|
else
|
326
|
-
raise "x value #{x} not supported"
|
331
|
+
raise "x value #{x} not supported. Use integer as pixel or float (0..1) as percentage of element width"
|
327
332
|
end
|
328
333
|
|
329
|
-
if y.kind_of?
|
334
|
+
if y.kind_of?(Integer)
|
330
335
|
if y >= 0
|
331
|
-
y = b.
|
336
|
+
y = b.top_left.y + y
|
332
337
|
else
|
333
|
-
y = b.
|
338
|
+
y = b.bottom_right + y
|
334
339
|
end
|
335
|
-
elsif y.kind_of?
|
336
|
-
y = b.
|
340
|
+
elsif y.kind_of?(Float) && y <= 1.0 && y >= 0
|
341
|
+
y = b.top_left.y + b.height*y
|
342
|
+
else
|
343
|
+
raise "y value #{x} not supported. Use integer as pixel or float (0..1) as percentage of element height"
|
337
344
|
end
|
338
345
|
|
339
346
|
action_builder = @driver.action
|
@@ -341,6 +348,11 @@ module TestaAppiumDriver
|
|
341
348
|
f1.create_pointer_move(duration: 0, x: x, y: y, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
342
349
|
f1.create_pointer_down(:left)
|
343
350
|
f1.create_pointer_up(:left)
|
351
|
+
if double
|
352
|
+
f1.create_pause(0.1)
|
353
|
+
f1.create_pointer_down(:left)
|
354
|
+
f1.create_pointer_up(:left)
|
355
|
+
end
|
344
356
|
@driver.perform_actions [f1]
|
345
357
|
else
|
346
358
|
if @driver.device == :android
|
@@ -355,6 +367,11 @@ module TestaAppiumDriver
|
|
355
367
|
end
|
356
368
|
end
|
357
369
|
|
370
|
+
|
371
|
+
alias_method :tap, :click
|
372
|
+
alias_method :double_tap, :double_click
|
373
|
+
|
374
|
+
|
358
375
|
def send_key(*args)
|
359
376
|
perform_driver_method(:send_keys, *args)
|
360
377
|
end
|
@@ -368,7 +385,7 @@ module TestaAppiumDriver
|
|
368
385
|
# @return [TestaAppiumDriver::Locator]
|
369
386
|
def parent
|
370
387
|
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "parent") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
|
371
|
-
raise "Cannot add parent selector to a retrieved instance of a class array" if (@xpath_selector == "
|
388
|
+
raise "Cannot add parent selector to a retrieved instance of a class array" if (@xpath_selector == ".//*" || @xpath_selector == ".//*[1]") && !@from_element.nil?
|
372
389
|
|
373
390
|
locator = self.dup
|
374
391
|
locator.strategy = FIND_STRATEGY_XPATH
|
@@ -426,7 +443,7 @@ module TestaAppiumDriver
|
|
426
443
|
def siblings
|
427
444
|
raise "Cannot add siblings selector to array" unless @single
|
428
445
|
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "siblings") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
|
429
|
-
raise "Cannot add siblings selector to a retrieved instance of a class array" if (@xpath_selector == "
|
446
|
+
raise "Cannot add siblings selector to a retrieved instance of a class array" if (@xpath_selector == ".//*" || @xpath_selector == ".//*[1]") && !@from_element.nil?
|
430
447
|
|
431
448
|
locator = self.dup
|
432
449
|
locator.strategy = FIND_STRATEGY_XPATH
|
@@ -442,7 +459,7 @@ module TestaAppiumDriver
|
|
442
459
|
def preceding_siblings
|
443
460
|
raise "Cannot add preceding_siblings selector to array" unless @single
|
444
461
|
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "preceding_siblings") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
|
445
|
-
raise "Cannot add preceding_siblings selector to a retrieved instance of a class array" if (@xpath_selector == "
|
462
|
+
raise "Cannot add preceding_siblings selector to a retrieved instance of a class array" if (@xpath_selector == ".//*" || @xpath_selector == ".//*[1]") && !@from_element.nil?
|
446
463
|
|
447
464
|
locator = self.dup
|
448
465
|
locator.strategy = FIND_STRATEGY_XPATH
|
@@ -458,7 +475,7 @@ module TestaAppiumDriver
|
|
458
475
|
def preceding_sibling
|
459
476
|
raise "Cannot add preceding_sibling selector to array" unless @single
|
460
477
|
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "preceding_sibling") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
|
461
|
-
raise "Cannot add preceding siblings selector to a retrieved instance of a class array" if (@xpath_selector == "
|
478
|
+
raise "Cannot add preceding siblings selector to a retrieved instance of a class array" if (@xpath_selector == ".//*" || @xpath_selector == ".//*[1]") && !@from_element.nil?
|
462
479
|
|
463
480
|
locator = self.dup
|
464
481
|
locator.strategy = FIND_STRATEGY_XPATH
|
@@ -477,7 +494,7 @@ module TestaAppiumDriver
|
|
477
494
|
def following_siblings
|
478
495
|
raise "Cannot add following_siblings selector to array" unless @single
|
479
496
|
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "following_siblings") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
|
480
|
-
raise "Cannot add following_siblings selector to a retrieved instance of a class array" if (@xpath_selector == "
|
497
|
+
raise "Cannot add following_siblings selector to a retrieved instance of a class array" if (@xpath_selector == ".//*" || @xpath_selector == ".//*[1]") && !@from_element.nil?
|
481
498
|
|
482
499
|
locator = self.dup
|
483
500
|
locator.strategy = FIND_STRATEGY_XPATH
|
@@ -493,7 +510,7 @@ module TestaAppiumDriver
|
|
493
510
|
def following_sibling
|
494
511
|
raise "Cannot add following_sibling selector to array" unless @single
|
495
512
|
raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "following_sibling") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
|
496
|
-
raise "Cannot add following_sibling selector to a retrieved instance of a class array" if (@xpath_selector == "
|
513
|
+
raise "Cannot add following_sibling selector to a retrieved instance of a class array" if (@xpath_selector == ".//*" || @xpath_selector == ".//*[1]") && !@from_element.nil?
|
497
514
|
|
498
515
|
locator = self.dup
|
499
516
|
locator.strategy = FIND_STRATEGY_XPATH
|
@@ -548,7 +565,7 @@ module TestaAppiumDriver
|
|
548
565
|
def _attributes_match(attributes)
|
549
566
|
all_match = true
|
550
567
|
attributes.each do |key, value|
|
551
|
-
unless
|
568
|
+
unless testa_attribute(key) == value
|
552
569
|
all_match = false
|
553
570
|
break
|
554
571
|
end
|
@@ -1,7 +1,7 @@
|
|
1
|
-
module TestaAppiumDriver
|
2
|
-
|
1
|
+
module ::TestaAppiumDriver
|
2
|
+
module W3cScrollActions
|
3
|
+
|
3
4
|
|
4
|
-
private
|
5
5
|
# @return [Array]
|
6
6
|
def w3c_scroll_each(direction, &block)
|
7
7
|
elements = []
|
@@ -19,48 +19,105 @@ module TestaAppiumDriver
|
|
19
19
|
direction = :right
|
20
20
|
end
|
21
21
|
end
|
22
|
+
case direction
|
23
|
+
when :up
|
24
|
+
align_with = :bottom
|
25
|
+
when :down
|
26
|
+
align_with = :top
|
27
|
+
when :right
|
28
|
+
align_with = :left
|
29
|
+
when :left
|
30
|
+
align_with = :right
|
31
|
+
else
|
32
|
+
align_with = :top
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
ignore_element_ids = []
|
38
|
+
previous_element = nil
|
22
39
|
|
23
40
|
until is_end_of_scroll?
|
41
|
+
aligned_items = 0
|
42
|
+
new_ignore_element_ids = []
|
24
43
|
matches = @locator.execute(skip_cache: true)
|
25
|
-
matches.each_with_index do |m|
|
26
|
-
|
44
|
+
matches.each_with_index do |m, index|
|
45
|
+
if ignore_element_ids.include?(m.id)
|
46
|
+
previous_element = m
|
47
|
+
next
|
48
|
+
end
|
49
|
+
|
50
|
+
sa = self.dup
|
51
|
+
sa.locator = m
|
52
|
+
sa.w3c_align(align_with, false, 1, speed_coef: 2.0)
|
53
|
+
is_aligned = sa.is_aligned?(align_with, m)
|
54
|
+
if !is_aligned && !previous_element.nil?
|
55
|
+
new_ignore_element_ids << previous_element.id
|
56
|
+
end
|
57
|
+
|
58
|
+
if is_aligned
|
59
|
+
aligned_items += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
if matches.count == index + 1
|
63
|
+
new_ignore_element_ids << m.id
|
64
|
+
end
|
65
|
+
|
27
66
|
elements << m
|
28
67
|
if block_given? # block is given
|
68
|
+
@locator.driver.invalidate_cache
|
29
69
|
block.call(m) # use call to execute the block
|
30
70
|
else # the value of block_argument becomes nil if you didn't give a block
|
31
71
|
# block was not given
|
32
72
|
end
|
73
|
+
previous_element = m
|
33
74
|
end
|
75
|
+
|
34
76
|
iterations += 1
|
35
77
|
break if !@max_scrolls.nil? && iterations == @max_scrolls
|
36
|
-
|
78
|
+
|
79
|
+
if aligned_items == 0
|
80
|
+
self.send("page_#{direction}")
|
81
|
+
else
|
82
|
+
ignore_element_ids = new_ignore_element_ids.dup
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
|
37
88
|
end
|
38
89
|
rescue => e
|
39
90
|
raise e
|
40
|
-
|
41
91
|
end
|
42
92
|
elements
|
43
93
|
end
|
44
94
|
|
45
|
-
def w3c_align(with, scroll_to_find)
|
95
|
+
def w3c_align(with, scroll_to_find, max_attempts, speed_coef: 1.25)
|
46
96
|
default_deadzone!
|
47
97
|
|
48
98
|
|
49
99
|
|
50
100
|
@locator.scroll_to if scroll_to_find
|
51
101
|
|
52
|
-
|
102
|
+
if @locator.instance_of?(TestaAppiumDriver::Locator)
|
103
|
+
element = @locator.execute
|
104
|
+
else
|
105
|
+
element = @locator
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
max_attempts = 3 if max_attempts.nil? || max_attempts <= 0
|
53
110
|
|
54
111
|
timeout = 0
|
55
|
-
until is_aligned?(with, element) || timeout ==
|
56
|
-
w3c_attempt_align(with)
|
112
|
+
until is_aligned?(with, element) || timeout == max_attempts
|
113
|
+
w3c_attempt_align(with, speed_coef)
|
57
114
|
timeout += 1
|
58
115
|
end
|
59
116
|
|
60
117
|
end
|
61
118
|
|
62
119
|
|
63
|
-
def w3c_attempt_align(with)
|
120
|
+
def w3c_attempt_align(with, speed_coef)
|
64
121
|
case with
|
65
122
|
when :top
|
66
123
|
y0 = @bounds.bottom_right.y - @deadzone[:bottom]
|
@@ -91,7 +148,7 @@ module TestaAppiumDriver
|
|
91
148
|
end
|
92
149
|
|
93
150
|
x1, y1 = apply_w3c_correction(x1, y1, scroll_direction) if @driver.device == :android
|
94
|
-
w3c_action(x0, y0, x1, y1, SCROLL_ACTION_TYPE_SCROLL)
|
151
|
+
w3c_action(x0, y0, x1, y1, SCROLL_ACTION_TYPE_SCROLL, speed_coef: speed_coef)
|
95
152
|
end
|
96
153
|
|
97
154
|
|
@@ -171,7 +228,9 @@ module TestaAppiumDriver
|
|
171
228
|
y0 = @bounds.top_left.y + @deadzone[:top].to_i
|
172
229
|
y1 = @bounds.bottom_right.y - @deadzone[:bottom].to_i
|
173
230
|
end
|
174
|
-
x0 = @bounds.width / 2
|
231
|
+
x0 = @bounds.top_left.x + (@bounds.width - @deadzone[:left].to_i - @deadzone[:right].to_i)/ 2
|
232
|
+
x0 = @bounds.top_left.x if x0 < @bounds.top_left.x
|
233
|
+
x0 = @bounds.bottom_right.x if x0 > @bounds.bottom_right.x
|
175
234
|
x1 = x0
|
176
235
|
else
|
177
236
|
if direction == :right
|
@@ -181,24 +240,32 @@ module TestaAppiumDriver
|
|
181
240
|
x0 = @bounds.top_left.x + @deadzone[:left].to_i
|
182
241
|
x1 = @bounds.bottom_right.x - @deadzone[:right].to_i
|
183
242
|
end
|
184
|
-
|
243
|
+
|
244
|
+
y0 = @bounds.top_left.y + (@bounds.height - @deadzone[:top].to_i - @deadzone[:bottom].to_i)/ 2
|
245
|
+
y0 = @bounds.top_left.y if y0 < @bounds.top_left.y
|
246
|
+
y0 = @bounds.bottom_right.y if y0 > @bounds.bottom_right.y
|
185
247
|
y1 = y0
|
186
248
|
end
|
187
249
|
x1, y1 = apply_w3c_correction(x1, y1, direction) if @driver.device == :android
|
188
250
|
|
251
|
+
speed_coef = 1
|
252
|
+
if type == SCROLL_ACTION_TYPE_SCROLL
|
253
|
+
speed_coef = 1.5
|
254
|
+
end
|
189
255
|
|
190
|
-
w3c_action(x0, y0, x1, y1, type)
|
256
|
+
w3c_action(x0, y0, x1, y1, type, speed_coef: speed_coef)
|
191
257
|
|
192
258
|
end
|
193
259
|
|
194
260
|
|
195
|
-
def w3c_action(x0, y0, x1, y1, type)
|
261
|
+
def w3c_action(x0, y0, x1, y1, type, speed_coef: 1.0)
|
262
|
+
speed_coef = 1/speed_coef
|
196
263
|
if type == SCROLL_ACTION_TYPE_SCROLL
|
197
|
-
duration = 1.8
|
264
|
+
duration = 1.8*speed_coef
|
198
265
|
elsif type == SCROLL_ACTION_TYPE_FLING
|
199
|
-
duration = 0.1
|
266
|
+
duration = 0.1*speed_coef
|
200
267
|
elsif type == SCROLL_ACTION_TYPE_DRAG
|
201
|
-
duration = 3.5
|
268
|
+
duration = 3.5*speed_coef
|
202
269
|
else
|
203
270
|
raise "Unknown scroll action type #{type}"
|
204
271
|
end
|
@@ -5,6 +5,10 @@ module TestaAppiumDriver
|
|
5
5
|
|
6
6
|
# Class for handling scroll actions
|
7
7
|
class ScrollActions
|
8
|
+
include W3cScrollActions
|
9
|
+
include JsonWireScrollActions
|
10
|
+
|
11
|
+
attr_accessor :locator
|
8
12
|
# @param [TestaAppiumDriver::Locator, nil] scrollable container that will be used to determine the bounds for scrolling
|
9
13
|
# @param [Hash] params
|
10
14
|
# acceptable params
|
@@ -15,6 +19,7 @@ module TestaAppiumDriver
|
|
15
19
|
def initialize(scrollable, params = {})
|
16
20
|
@scrollable = scrollable
|
17
21
|
@locator = params[:locator]
|
22
|
+
# TODO: raise error if locator is for multiple, but not for scroll each, chekc other cases aswell
|
18
23
|
@deadzone = params[:deadzone]
|
19
24
|
@max_scrolls = params[:max_scrolls]
|
20
25
|
@default_scroll_strategy = params[:default_scroll_strategy]
|
@@ -36,8 +41,8 @@ module TestaAppiumDriver
|
|
36
41
|
@bounds = @scrollable.bounds
|
37
42
|
end
|
38
43
|
|
39
|
-
def align(with, scroll_to_find)
|
40
|
-
w3c_align(with, scroll_to_find)
|
44
|
+
def align(with, scroll_to_find, max_attempts)
|
45
|
+
w3c_align(with, scroll_to_find, max_attempts)
|
41
46
|
@locator
|
42
47
|
end
|
43
48
|
|
@@ -195,7 +200,25 @@ module TestaAppiumDriver
|
|
195
200
|
w3c_drag_to(x0, y0, x1, y1)
|
196
201
|
end
|
197
202
|
|
198
|
-
|
203
|
+
|
204
|
+
def is_aligned?(with, element)
|
205
|
+
align_bounds = @locator.bounds(force_cache_element: element)
|
206
|
+
case with
|
207
|
+
when :top
|
208
|
+
@align_offset = align_bounds.top_left.y - @bounds.top_left.y - @deadzone[:top]
|
209
|
+
when :bottom
|
210
|
+
@align_offset = @bounds.bottom_right.y - @deadzone[:bottom] - align_bounds.bottom_right.y
|
211
|
+
when :right
|
212
|
+
@align_offset = @bounds.bottom_right.x - @deadzone[:right] - align_bounds.bottom_right.x
|
213
|
+
when :left
|
214
|
+
@align_offset = align_bounds.top_left.x - @bounds.top_left.x - @deadzone[:left]
|
215
|
+
else
|
216
|
+
raise "Unsupported align with option: #{with}"
|
217
|
+
end
|
218
|
+
@align_offset < SCROLL_ALIGNMENT_THRESHOLD
|
219
|
+
end
|
220
|
+
|
221
|
+
|
199
222
|
|
200
223
|
def is_end_of_scroll?
|
201
224
|
old_elements = @previous_elements
|
@@ -227,21 +250,5 @@ module TestaAppiumDriver
|
|
227
250
|
end
|
228
251
|
end
|
229
252
|
|
230
|
-
def is_aligned?(with, element)
|
231
|
-
align_bounds = @locator.bounds(force_cache_element: element)
|
232
|
-
case with
|
233
|
-
when :top
|
234
|
-
@align_offset = align_bounds.top_left.y - @bounds.top_left.y + @deadzone[:top]
|
235
|
-
when :bottom
|
236
|
-
@align_offset = @bounds.bottom_right.y - @deadzone[:bottom] - align_bounds.bottom_right.y
|
237
|
-
when :right
|
238
|
-
@align_offset = @bounds.bottom_right.x - @deadzone[:right] - align_bounds.bottom_right.x
|
239
|
-
when :left
|
240
|
-
@align_offset = align_bounds.top_left.x - @bounds.top_left.x + @deadzone[:left]
|
241
|
-
else
|
242
|
-
raise "Unsupported align with option: #{with}"
|
243
|
-
end
|
244
|
-
@align_offset < SCROLL_ALIGNMENT_THRESHOLD
|
245
|
-
end
|
246
253
|
end
|
247
254
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'em/pure_ruby'
|
3
|
+
#require 'em/pure_ruby'
|
4
4
|
require 'appium_lib_core'
|
5
5
|
|
6
6
|
require_relative 'common/bounds'
|
@@ -27,25 +27,24 @@ module TestaAppiumDriver
|
|
27
27
|
# - default_find_strategy: default strategy to be used for finding elements. Available strategies :uiautomator or :xpath
|
28
28
|
# - default_scroll_strategy: default strategy to be used for scrolling. Available strategies: :uiautomator(android only), :w3c
|
29
29
|
def initialize(opts = {})
|
30
|
-
opts[:shouldEnforceXpath1] = false
|
31
30
|
|
32
31
|
@testa_opts = opts[:testa_appium_driver] || {}
|
33
32
|
|
34
33
|
core = Appium::Core.for(opts)
|
35
|
-
|
36
|
-
@
|
37
|
-
@
|
34
|
+
@driver = core.start_driver
|
35
|
+
@automation_name = @driver.capabilities["automationName"].downcase.to_sym
|
36
|
+
@device = @driver.capabilities.platform_name.downcase.to_sym
|
37
|
+
|
38
|
+
extend_for(@device, @automation_name)
|
38
39
|
|
39
40
|
handle_testa_opts
|
40
41
|
|
41
|
-
@driver = core.start_driver
|
42
42
|
invalidate_cache
|
43
43
|
|
44
|
+
#disable_wait_for_idle
|
45
|
+
#disable_implicit_wait
|
44
46
|
|
45
|
-
|
46
|
-
disable_implicit_wait
|
47
|
-
|
48
|
-
Selenium::WebDriver::Element.set_driver(self, opts[:caps][:udid])
|
47
|
+
::Appium::Core::Element.set_driver(self, @driver.capabilities["udid"])
|
49
48
|
end
|
50
49
|
|
51
50
|
|
@@ -84,7 +83,11 @@ module TestaAppiumDriver
|
|
84
83
|
from_element_id = from_element.instance_of?(TestaAppiumDriver::Locator) ? from_element.strategies_and_selectors : nil
|
85
84
|
|
86
85
|
begin
|
86
|
+
begin
|
87
87
|
ss = strategies_and_selectors[ss_index % strategies_and_selectors.count]
|
88
|
+
rescue ZeroDivisionError
|
89
|
+
puts "aa"
|
90
|
+
end
|
88
91
|
ss_index +=1
|
89
92
|
|
90
93
|
puts "Executing #{from_element_id ? "from #{from_element.strategy}: #{from_element.strategies_and_selectors} => " : ""}#{ss.keys[0]}: #{ss.values[0]}"
|
@@ -153,7 +156,7 @@ module TestaAppiumDriver
|
|
153
156
|
@implicit_wait_ms = @implicit_wait_ms/1000 if @implicit_wait_ms > 100000
|
154
157
|
@implicit_wait_uiautomator_ms = @driver.get_settings["waitForSelectorTimeout"]
|
155
158
|
@driver.manage.timeouts.implicit_wait = 0
|
156
|
-
@driver.update_settings({waitForSelectorTimeout:
|
159
|
+
@driver.update_settings({waitForSelectorTimeout: 0})
|
157
160
|
end
|
158
161
|
|
159
162
|
|
@@ -246,26 +249,28 @@ module TestaAppiumDriver
|
|
246
249
|
@driver.long_press_keycode(code)
|
247
250
|
end
|
248
251
|
|
249
|
-
def click(x, y)
|
252
|
+
def click(x, y, double: false)
|
250
253
|
ws = driver.window_size
|
251
254
|
window_width = ws.width.to_i
|
252
255
|
window_height = ws.height.to_i
|
253
|
-
if x.kind_of?
|
256
|
+
if x.kind_of?(Integer)
|
254
257
|
if x < 0
|
255
258
|
x = window_width + x
|
256
259
|
end
|
257
|
-
elsif x.kind_of?
|
260
|
+
elsif x.kind_of?(Float) && x <= 1.0 && x >= 0
|
258
261
|
x = window_width*x
|
259
262
|
else
|
260
|
-
raise "x value #{x} not supported"
|
263
|
+
raise "x value #{x} not supported. Use integer as pixel or float (0..1) as percentage of screen"
|
261
264
|
end
|
262
265
|
|
263
|
-
if y.kind_of?
|
266
|
+
if y.kind_of?(Integer)
|
264
267
|
if y < 0
|
265
268
|
y = window_height + y
|
266
269
|
end
|
267
|
-
elsif y.kind_of?
|
270
|
+
elsif y.kind_of?(Float) && y <= 1.0 && y >= 0
|
268
271
|
y = window_height*y
|
272
|
+
else
|
273
|
+
raise "y value #{x} not supported. Use integer as pixel or float (0..1) as percentage of screen"
|
269
274
|
end
|
270
275
|
|
271
276
|
|
@@ -274,14 +279,23 @@ module TestaAppiumDriver
|
|
274
279
|
f1.create_pointer_move(duration: 0, x: x, y: y, origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
275
280
|
f1.create_pointer_down(:left)
|
276
281
|
f1.create_pointer_up(:left)
|
282
|
+
if double
|
283
|
+
f1.create_pause(0.1)
|
284
|
+
f1.create_pointer_down(:left)
|
285
|
+
f1.create_pointer_up(:left)
|
286
|
+
end
|
277
287
|
@driver.perform_actions [f1]
|
278
288
|
end
|
279
289
|
|
290
|
+
def double_click(x,y)
|
291
|
+
click(x,y, double: true)
|
292
|
+
end
|
293
|
+
|
280
294
|
|
281
295
|
|
282
296
|
# @return [Array<Selenium::WebDriver::Element] array of 2 elements, the first element without children and the last element without children in the current page
|
283
297
|
def first_and_last_leaf(from_element = @driver)
|
284
|
-
elements = from_element.find_elements(xpath: "
|
298
|
+
elements = from_element.find_elements(xpath: ".//*[not(*)]")
|
285
299
|
return nil if elements.count == 0
|
286
300
|
[elements[0], elements[-1]]
|
287
301
|
end
|
@@ -291,7 +305,7 @@ module TestaAppiumDriver
|
|
291
305
|
case device
|
292
306
|
when :android
|
293
307
|
case automation_name
|
294
|
-
when :uiautomator2
|
308
|
+
when :uiautomator2, :espresso, :Espresso
|
295
309
|
require_relative 'android/driver'
|
296
310
|
else
|
297
311
|
raise "Testa appium driver not supported for #{automation_name} automation"
|
@@ -2,10 +2,17 @@ module TestaAppiumDriver
|
|
2
2
|
module Attributes
|
3
3
|
|
4
4
|
#noinspection RubyNilAnalysis
|
5
|
-
def
|
6
|
-
elements = execute(*args)
|
5
|
+
def testa_attribute(name, *args)
|
7
6
|
|
8
|
-
if
|
7
|
+
if self.instance_of?(::Selenium::WebDriver::Element) || self.instance_of?(::Appium::Core::Element)
|
8
|
+
@driver = get_driver
|
9
|
+
elements = self
|
10
|
+
else
|
11
|
+
elements = execute(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
if elements.instance_of?(::Selenium::WebDriver::Element) || elements.instance_of?(::Appium::Core::Element)
|
9
16
|
r = elements.send(:attribute, name.to_s)
|
10
17
|
r = TestaAppiumDriver::Bounds.from_ios(r, @driver) if name.to_s == "rect"
|
11
18
|
else
|
@@ -17,65 +24,62 @@ module TestaAppiumDriver
|
|
17
24
|
|
18
25
|
|
19
26
|
def accessibility_container(*args)
|
20
|
-
|
27
|
+
testa_attribute("accessibilityContainer", *args)
|
21
28
|
end
|
22
29
|
|
23
30
|
def accessible?(*args)
|
24
|
-
|
31
|
+
testa_attribute("accessible", *args).to_s == "true"
|
25
32
|
end
|
26
33
|
|
27
34
|
|
28
35
|
def class_name(*args)
|
29
|
-
|
36
|
+
testa_attribute("class", *args)
|
30
37
|
end
|
31
38
|
|
32
39
|
def enabled?(*args)
|
33
|
-
|
40
|
+
testa_attribute("enabled", *args).to_s == "true"
|
34
41
|
end
|
35
42
|
|
36
43
|
def frame(*args)
|
37
|
-
|
44
|
+
testa_attribute("frame", *args)
|
38
45
|
end
|
39
46
|
|
40
47
|
def index(*args)
|
41
|
-
|
48
|
+
testa_attribute("index", *args)
|
42
49
|
end
|
43
50
|
|
44
51
|
def label(*args)
|
45
|
-
|
52
|
+
testa_attribute("label", *args)
|
46
53
|
end
|
47
54
|
|
48
55
|
def name(*args)
|
49
|
-
|
56
|
+
testa_attribute("name", *args)
|
50
57
|
end
|
51
58
|
|
52
59
|
|
53
60
|
def rect(*args)
|
54
|
-
|
61
|
+
testa_attribute("rect", *args)
|
55
62
|
end
|
56
63
|
|
57
64
|
def selected?(*args)
|
58
|
-
|
65
|
+
testa_attribute("selected", *args).to_s == "true"
|
59
66
|
end
|
60
67
|
|
61
68
|
def type(*args)
|
62
|
-
|
69
|
+
testa_attribute("type", *args)
|
63
70
|
end
|
64
71
|
|
65
72
|
def value(*args)
|
66
|
-
|
73
|
+
testa_attribute("value", *args)
|
67
74
|
end
|
68
75
|
|
69
76
|
def visible?(*args)
|
70
|
-
|
77
|
+
testa_attribute("visible", *args).to_s == "true"
|
71
78
|
end
|
72
79
|
|
73
80
|
|
74
81
|
alias_method :bounds, :rect
|
75
82
|
alias_method :text, :label
|
76
83
|
end
|
77
|
-
|
78
|
-
class Locator
|
79
|
-
include TestaAppiumDriver::Attributes
|
80
|
-
end
|
84
|
+
|
81
85
|
end
|