testa_appium_driver 0.1.0 → 0.1.4
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/class_selectors.rb +50 -0
- data/lib/testa_appium_driver/android/driver.rb +2 -1
- data/lib/testa_appium_driver/android/locator/attributes.rb +4 -4
- data/lib/testa_appium_driver/android/locator.rb +17 -5
- data/lib/testa_appium_driver/android/selenium_element.rb +1 -1
- 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/scroll_actions.rb +152 -58
- data/lib/testa_appium_driver/common/locator.rb +58 -10
- data/lib/testa_appium_driver/common/scroll_actions/w3c_scroll_actions.rb +12 -4
- data/lib/testa_appium_driver/common/scroll_actions.rb +36 -33
- data/lib/testa_appium_driver/common/selenium_element.rb +19 -0
- data/lib/testa_appium_driver/driver.rb +41 -41
- data/lib/testa_appium_driver/ios/driver.rb +1 -0
- data/lib/testa_appium_driver/ios/locator/attributes.rb +5 -3
- data/lib/testa_appium_driver/ios/locator.rb +17 -4
- data/lib/testa_appium_driver/version.rb +1 -1
- data/testa_appium_driver.gemspec +41 -40
- data/testa_appium_driver.iml +1 -35
- metadata +11 -8
@@ -12,7 +12,10 @@ module TestaAppiumDriver
|
|
12
12
|
attr_accessor :driver
|
13
13
|
attr_accessor :strategy
|
14
14
|
attr_accessor :strategy_reason
|
15
|
+
|
16
|
+
# @type [Boolean] used to determine if last selector was one of siblings or children. Only in those selectors we can reliably use xpath array [instance] selector
|
15
17
|
attr_accessor :last_selector_adjacent
|
18
|
+
attr_accessor :can_use_id_strategy
|
16
19
|
|
17
20
|
attr_accessor :from_element
|
18
21
|
attr_accessor :scroll_orientation
|
@@ -37,11 +40,11 @@ module TestaAppiumDriver
|
|
37
40
|
@driver = driver
|
38
41
|
|
39
42
|
params, selectors = extract_selectors_from_params(params)
|
40
|
-
|
41
43
|
single = params[:single]
|
42
44
|
|
43
45
|
@single = single
|
44
46
|
|
47
|
+
selectors[:id] = selectors[:name] unless selectors[:name].nil?
|
45
48
|
if from_element.instance_of?(Selenium::WebDriver::Element)
|
46
49
|
@xpath_selector = "//*" # to select current element
|
47
50
|
@xpath_selector += hash_to_xpath(@driver.device, selectors, single)[1..-1]
|
@@ -54,11 +57,19 @@ module TestaAppiumDriver
|
|
54
57
|
@default_find_strategy = params[:default_find_strategy]
|
55
58
|
@default_scroll_strategy = params[:default_scroll_strategy]
|
56
59
|
|
60
|
+
@can_use_id_strategy = selectors.keys.count == 1 && !selectors[:id].nil?
|
61
|
+
if @can_use_id_strategy
|
62
|
+
if @driver.device == :android
|
63
|
+
@can_use_id_strategy = resolve_id(selectors[:id])
|
64
|
+
else
|
65
|
+
@can_use_id_strategy = selectors[:id]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
57
69
|
|
58
70
|
@strategy = params[:strategy]
|
59
71
|
@strategy_reason = params[:strategy_reason]
|
60
72
|
|
61
|
-
# @type [Boolean] used to determine if last selector was one of siblings or children. Only in those selectors we can reliably use xpath array [instance] selector
|
62
73
|
@last_selector_adjacent = false
|
63
74
|
|
64
75
|
init(params, selectors, single)
|
@@ -68,6 +79,7 @@ module TestaAppiumDriver
|
|
68
79
|
# method missing is used to fetch the element before executing additional commands like click, send_key, count
|
69
80
|
def method_missing(method, *args, &block)
|
70
81
|
execute.send(method, *args, &block)
|
82
|
+
@driver.invalidate_cache
|
71
83
|
end
|
72
84
|
|
73
85
|
|
@@ -84,16 +96,23 @@ module TestaAppiumDriver
|
|
84
96
|
if @xpath_selector == "//*/*[1]" && @from_element.instance_of?(Selenium::WebDriver::Element)
|
85
97
|
return @from_element
|
86
98
|
end
|
87
|
-
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
strategy, selector = strategy_and_selector
|
103
|
+
|
104
|
+
|
105
|
+
@driver.execute(@from_element, selector, @single, strategy, @default_find_strategy, skip_cache)
|
88
106
|
end
|
89
107
|
|
90
108
|
|
91
109
|
# @param [Integer] timeout in seconds
|
92
110
|
# @return [TestaAppiumDriver::Locator]
|
93
|
-
def wait_until_exists(timeout =
|
111
|
+
def wait_until_exists(timeout = nil)
|
112
|
+
timeout = @driver.get_timeouts["implicit"] / 1000 if timeout.nil?
|
94
113
|
start_time = Time.now.to_f
|
95
114
|
until exists?
|
96
|
-
raise "wait until exists timeout exceeded" if start_time + timeout
|
115
|
+
raise "wait until exists timeout exceeded" if start_time + timeout < Time.now.to_f
|
97
116
|
sleep EXISTS_WAIT
|
98
117
|
end
|
99
118
|
self
|
@@ -102,10 +121,11 @@ module TestaAppiumDriver
|
|
102
121
|
|
103
122
|
# @param [Integer] timeout in seconds
|
104
123
|
# @return [TestaAppiumDriver::Locator]
|
105
|
-
def wait_while_exists(timeout =
|
124
|
+
def wait_while_exists(timeout = nil)
|
125
|
+
timeout = @driver.get_timeouts["implicit"] / 1000 if timeout.nil?
|
106
126
|
start_time = Time.now.to_f
|
107
127
|
while exists?
|
108
|
-
raise "wait until exists timeout exceeded" if start_time + timeout
|
128
|
+
raise "wait until exists timeout exceeded" if start_time + timeout < Time.now.to_f
|
109
129
|
sleep EXISTS_WAIT
|
110
130
|
end
|
111
131
|
self
|
@@ -128,15 +148,34 @@ module TestaAppiumDriver
|
|
128
148
|
found
|
129
149
|
end
|
130
150
|
|
151
|
+
# @return [TestaAppiumDriver::Locator]
|
152
|
+
def first
|
153
|
+
self[0]
|
154
|
+
end
|
155
|
+
|
156
|
+
# @return [TestaAppiumDriver::Locator]
|
157
|
+
def second
|
158
|
+
self[1]
|
159
|
+
end
|
160
|
+
|
161
|
+
# @return [TestaAppiumDriver::Locator]
|
162
|
+
def third
|
163
|
+
self[2]
|
164
|
+
end
|
165
|
+
|
166
|
+
# @return [TestaAppiumDriver::Locator]
|
167
|
+
def last
|
168
|
+
self[-1]
|
169
|
+
end
|
131
170
|
|
132
171
|
def [](instance)
|
133
172
|
raise "Cannot add index selector to non-Array" if @single
|
134
|
-
|
135
|
-
if (@strategy.nil? && !@last_selector_adjacent) || @strategy == FIND_STRATEGY_UIAUTOMATOR
|
173
|
+
if ((@strategy.nil? && !@last_selector_adjacent) || @strategy == FIND_STRATEGY_UIAUTOMATOR) && instance >= 0
|
136
174
|
locator = self.dup
|
137
175
|
locator.strategy = FIND_STRATEGY_UIAUTOMATOR
|
138
176
|
locator.ui_selector = "#{@ui_selector}.instance(#{instance})"
|
139
177
|
locator.single = true
|
178
|
+
locator.can_use_id_strategy = false
|
140
179
|
locator
|
141
180
|
else
|
142
181
|
from_element = self.execute[instance]
|
@@ -175,7 +214,8 @@ module TestaAppiumDriver
|
|
175
214
|
uiautomator: defined?(self.ui_selector) ? ui_selector : nil,
|
176
215
|
xpath: @xpath_selector,
|
177
216
|
scrollable: @scrollable_locator.nil? ? nil : @scrollable_locator.to_s,
|
178
|
-
scroll_orientation: @scroll_orientation
|
217
|
+
scroll_orientation: @scroll_orientation,
|
218
|
+
resolved: strategy_and_selector
|
179
219
|
}
|
180
220
|
end
|
181
221
|
|
@@ -235,6 +275,7 @@ module TestaAppiumDriver
|
|
235
275
|
locator.strategy = FIND_STRATEGY_XPATH
|
236
276
|
locator.strategy_reason = "parent"
|
237
277
|
locator.xpath_selector += "/.."
|
278
|
+
locator.can_use_id_strategy = false
|
238
279
|
locator
|
239
280
|
end
|
240
281
|
|
@@ -250,6 +291,7 @@ module TestaAppiumDriver
|
|
250
291
|
locator.xpath_selector += "/*"
|
251
292
|
locator.single = false
|
252
293
|
locator.last_selector_adjacent = true
|
294
|
+
locator.can_use_id_strategy = false
|
253
295
|
locator
|
254
296
|
end
|
255
297
|
|
@@ -265,6 +307,7 @@ module TestaAppiumDriver
|
|
265
307
|
locator.strategy_reason = "child"
|
266
308
|
locator.xpath_selector += "/*[1]"
|
267
309
|
locator.single = true
|
310
|
+
locator.can_use_id_strategy = false
|
268
311
|
locator
|
269
312
|
end
|
270
313
|
|
@@ -281,6 +324,7 @@ module TestaAppiumDriver
|
|
281
324
|
locator.xpath_selector += "/../*[not(@index=\"#{index}\")]"
|
282
325
|
locator.single = false
|
283
326
|
locator.last_selector_adjacent = true
|
327
|
+
locator.can_use_id_strategy = false
|
284
328
|
locator
|
285
329
|
end
|
286
330
|
|
@@ -296,6 +340,7 @@ module TestaAppiumDriver
|
|
296
340
|
locator.xpath_selector += "/../*[position() < #{index + 1}]" # position() starts from 1
|
297
341
|
locator.single = false
|
298
342
|
locator.last_selector_adjacent = true
|
343
|
+
locator.can_use_id_strategy = false
|
299
344
|
locator
|
300
345
|
end
|
301
346
|
|
@@ -313,6 +358,7 @@ module TestaAppiumDriver
|
|
313
358
|
return nil if i == 0
|
314
359
|
locator.xpath_selector += "/../*[@index=\"#{i - 1}\"]"
|
315
360
|
locator.last_selector_adjacent = true
|
361
|
+
locator.can_use_id_strategy = false
|
316
362
|
locator
|
317
363
|
end
|
318
364
|
|
@@ -329,6 +375,7 @@ module TestaAppiumDriver
|
|
329
375
|
locator.xpath_selector += "/../*[position() > #{index + 1}]" # position() starts from 1
|
330
376
|
locator.single = false
|
331
377
|
locator.last_selector_adjacent = true
|
378
|
+
locator.can_use_id_strategy = false
|
332
379
|
locator
|
333
380
|
end
|
334
381
|
|
@@ -346,6 +393,7 @@ module TestaAppiumDriver
|
|
346
393
|
return nil if i == 0
|
347
394
|
locator.xpath_selector += "/../*[@index=\"#{i + 1}\"]"
|
348
395
|
locator.last_selector_adjacent = true
|
396
|
+
locator.can_use_id_strategy = false
|
349
397
|
locator
|
350
398
|
end
|
351
399
|
|
@@ -3,7 +3,7 @@ module TestaAppiumDriver
|
|
3
3
|
|
4
4
|
private
|
5
5
|
# @return [Array]
|
6
|
-
def w3c_each(
|
6
|
+
def w3c_each(direction, &block)
|
7
7
|
elements = []
|
8
8
|
begin
|
9
9
|
@driver.disable_wait_for_idle
|
@@ -13,7 +13,14 @@ module TestaAppiumDriver
|
|
13
13
|
iterations = 0
|
14
14
|
|
15
15
|
|
16
|
-
|
16
|
+
if direction.nil?
|
17
|
+
scroll_to_start
|
18
|
+
if @scrollable.scroll_orientation == :vertical
|
19
|
+
direction = :down
|
20
|
+
else
|
21
|
+
direction = :right
|
22
|
+
end
|
23
|
+
end
|
17
24
|
|
18
25
|
until is_end_of_scroll?
|
19
26
|
matches = @locator.execute(skip_cache: true)
|
@@ -27,6 +34,7 @@ module TestaAppiumDriver
|
|
27
34
|
end
|
28
35
|
iterations += 1
|
29
36
|
break if !@max_scrolls.nil? && iterations == @max_scrolls
|
37
|
+
self.send("page_#{direction}")
|
30
38
|
end
|
31
39
|
rescue => e
|
32
40
|
raise e
|
@@ -37,13 +45,13 @@ module TestaAppiumDriver
|
|
37
45
|
elements
|
38
46
|
end
|
39
47
|
|
40
|
-
def w3c_align(with)
|
48
|
+
def w3c_align(with, scroll_to_find)
|
41
49
|
@driver.disable_wait_for_idle
|
42
50
|
default_deadzone!
|
43
51
|
|
44
52
|
|
45
53
|
|
46
|
-
@locator.scroll_to
|
54
|
+
@locator.scroll_to if scroll_to_find
|
47
55
|
|
48
56
|
element = @locator.execute
|
49
57
|
@driver.disable_implicit_wait
|
@@ -3,19 +3,24 @@ require_relative 'scroll_actions/w3c_scroll_actions'
|
|
3
3
|
|
4
4
|
|
5
5
|
module TestaAppiumDriver
|
6
|
-
#noinspection RubyResolve,RubyTooManyInstanceVariablesInspection
|
7
|
-
class ScrollActions
|
8
6
|
|
7
|
+
# Class for handling scroll actions
|
8
|
+
class ScrollActions
|
9
|
+
# @param [TestaAppiumDriver::Locator, nil] scrollable container that will be used to determine the bounds for scrolling
|
10
|
+
# @param [Hash] params
|
11
|
+
# acceptable params
|
12
|
+
# - locator - element that should be found with scrolling actions
|
13
|
+
# - 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
|
14
|
+
# - max_scrolls - [Integer] maximum number of scrolls before exception is thrown
|
15
|
+
# - default_scroll_strategy - defines which scroll strategy will be used if a scroll action is valid for multiple strategies
|
9
16
|
def initialize(scrollable, params = {})
|
10
17
|
@scrollable = scrollable
|
11
18
|
@locator = params[:locator]
|
12
19
|
@deadzone = params[:deadzone]
|
13
|
-
@direction = params[:direction]
|
14
20
|
@max_scrolls = params[:max_scrolls]
|
15
21
|
@default_scroll_strategy = params[:default_scroll_strategy]
|
16
22
|
@driver = @locator.driver
|
17
23
|
|
18
|
-
@raise = params[:raise]
|
19
24
|
|
20
25
|
if @scrollable.nil?
|
21
26
|
# if we dont have a scrollable element or if we do have it, but it is not compatible with uiautomator
|
@@ -26,7 +31,7 @@ module TestaAppiumDriver
|
|
26
31
|
@strategy = nil
|
27
32
|
if @scrollable.strategy == FIND_STRATEGY_XPATH || # uiautomator cannot resolve scrollable from a xpath locator
|
28
33
|
!@deadzone.nil? ||
|
29
|
-
!@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver)
|
34
|
+
!@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver) # uiautomator cannot resolve nested scrollable
|
30
35
|
@strategy = SCROLL_STRATEGY_W3C
|
31
36
|
end
|
32
37
|
|
@@ -35,16 +40,33 @@ module TestaAppiumDriver
|
|
35
40
|
end
|
36
41
|
|
37
42
|
|
38
|
-
def align(with)
|
39
|
-
w3c_align(with)
|
43
|
+
def align(with, scroll_to_find)
|
44
|
+
w3c_align(with, scroll_to_find)
|
40
45
|
@locator
|
41
46
|
end
|
42
47
|
|
43
48
|
# @return [Array]
|
44
|
-
def each(
|
45
|
-
w3c_each(
|
49
|
+
def each(&block)
|
50
|
+
w3c_each(nil, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def each_down(&block)
|
54
|
+
w3c_each(:down, &block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def each_up(&block)
|
58
|
+
w3c_each(:up, &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
def each_right(&block)
|
62
|
+
w3c_each(:right, &block)
|
46
63
|
end
|
47
64
|
|
65
|
+
def each_left(&block)
|
66
|
+
w3c_each(:left, &block)
|
67
|
+
end
|
68
|
+
|
69
|
+
|
48
70
|
def resolve_strategy
|
49
71
|
if @strategy.nil?
|
50
72
|
@default_scroll_strategy
|
@@ -63,39 +85,19 @@ module TestaAppiumDriver
|
|
63
85
|
end
|
64
86
|
|
65
87
|
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
|
88
|
+
w3c_scroll_to(:down)
|
72
89
|
end
|
73
90
|
|
74
91
|
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
|
92
|
+
w3c_scroll_to(:up)
|
81
93
|
end
|
82
94
|
|
83
95
|
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
|
96
|
+
w3c_scroll_to(:right)
|
90
97
|
end
|
91
98
|
|
92
99
|
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
|
100
|
+
w3c_scroll_to(:left)
|
99
101
|
end
|
100
102
|
|
101
103
|
def page_next
|
@@ -202,6 +204,7 @@ module TestaAppiumDriver
|
|
202
204
|
|
203
205
|
|
204
206
|
private
|
207
|
+
|
205
208
|
def is_end_of_scroll?
|
206
209
|
old_elements = @previous_elements
|
207
210
|
@previous_elements = @scrollable.first_and_last_leaf
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Selenium
|
2
|
+
module WebDriver
|
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
|
@@ -1,24 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'em/pure_ruby'
|
4
|
+
require 'appium_lib_core'
|
5
|
+
|
3
6
|
require_relative 'common/bounds'
|
4
7
|
require_relative 'common/exceptions/strategy_mix_exception'
|
5
8
|
require_relative 'common/helpers'
|
6
9
|
require_relative 'common/locator'
|
7
10
|
require_relative 'common/scroll_actions'
|
11
|
+
require_relative 'common/selenium_element'
|
8
12
|
|
9
13
|
module TestaAppiumDriver
|
10
14
|
class Driver
|
15
|
+
include Helpers
|
16
|
+
|
17
|
+
# @return [::Appium::Core::Base::Driver] the ruby_lib_core appium driver
|
11
18
|
attr_accessor :driver
|
19
|
+
|
20
|
+
# @return [String] iOS or Android
|
12
21
|
attr_reader :device
|
22
|
+
|
23
|
+
# @return [String] driver automation name (uiautomator2 or xcuitest)
|
13
24
|
attr_reader :automation_name
|
14
25
|
|
15
26
|
# custom options
|
16
|
-
# -
|
27
|
+
# - default_find_strategy: default strategy to be used for finding elements. Available strategies :uiautomator or :xpath
|
28
|
+
# - default_scroll_strategy: default strategy to be used for scrolling. Available strategies: :uiautomator(android only), :w3c
|
17
29
|
def initialize(opts = {})
|
18
30
|
@testa_opts = opts[:testa_appium_driver] || {}
|
19
31
|
|
20
32
|
|
21
|
-
|
22
33
|
core = Appium::Core.for(opts)
|
23
34
|
extend_for(core.device, core.automation_name)
|
24
35
|
@device = core.device
|
@@ -27,15 +38,15 @@ module TestaAppiumDriver
|
|
27
38
|
handle_testa_opts
|
28
39
|
|
29
40
|
@driver = core.start_driver
|
30
|
-
invalidate_cache
|
31
|
-
|
41
|
+
invalidate_cache
|
32
42
|
|
33
43
|
|
34
|
-
|
44
|
+
Selenium::WebDriver::Element.set_driver(self, opts[:caps][:udid])
|
35
45
|
end
|
36
46
|
|
37
47
|
|
38
|
-
|
48
|
+
# invalidates current find_element cache
|
49
|
+
def invalidate_cache
|
39
50
|
@cache = {
|
40
51
|
strategy: nil,
|
41
52
|
selector: nil,
|
@@ -45,28 +56,16 @@ module TestaAppiumDriver
|
|
45
56
|
}
|
46
57
|
end
|
47
58
|
|
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
59
|
|
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
60
|
|
64
61
|
|
65
|
-
#
|
62
|
+
# Executes the find_element with the resolved locator strategy and selector. Find_element might be skipped if cache is hit.
|
63
|
+
# Cache stores last executed find_element with given selector, strategy and from_element. If given values are the same within
|
64
|
+
# last 5 seconds element is retrieved from cache.
|
66
65
|
# @param [TestaAppiumDriver::Locator, TestaAppiumDriver::Driver] from_element element from which start the search
|
67
|
-
# @param [String] selector resolved string of a [TestaAppiumDriver::Locator] selector xpath for xpath strategy, java UiSelectors for uiautomator
|
66
|
+
# @param [String] selector resolved string of a [TestaAppiumDriver::Locator] selector xpath for xpath strategy, java UiSelectors for uiautomator or id for ID strategy
|
68
67
|
# @param [Boolean] single fetch single or multiple results
|
69
|
-
# @param [Symbol, nil] strategy [TestaAppiumDriver
|
68
|
+
# @param [Symbol, nil] strategy [TestaAppiumDriver::FIND_STRATEGY_UIAUTOMATOR], [TestaAppiumDriver::FIND_STRATEGY_XPATH] or [TestaAppiumDriver::FIND_STRATEGY_ID]
|
70
69
|
# @param [Symbol] default_strategy if strategy is not enforced, default can be used
|
71
70
|
# @param [Boolean] skip_cache to skip checking and storing cache
|
72
71
|
# @return [Selenium::WebDriver::Element, Array] element is returned if single is true, array otherwise
|
@@ -75,13 +74,14 @@ module TestaAppiumDriver
|
|
75
74
|
# if user wants to wait for element to exist, he can use wait_until_present
|
76
75
|
disable_wait_for_idle
|
77
76
|
|
77
|
+
|
78
78
|
# if not restricted to a strategy, use the default one
|
79
79
|
strategy = default_strategy if strategy.nil?
|
80
80
|
|
81
81
|
# resolve from_element unique id, so that we can cache it properly
|
82
|
-
from_element_id = from_element.kind_of?(TestaAppiumDriver::Locator) ? from_element.
|
82
|
+
from_element_id = from_element.kind_of?(TestaAppiumDriver::Locator) ? from_element.strategy_and_selector[1] : nil
|
83
83
|
|
84
|
-
puts "Executing #{from_element_id ? "from #{from_element.strategy}: #{from_element.
|
84
|
+
puts "Executing #{from_element_id ? "from #{from_element.strategy}: #{from_element.strategy_and_selector} => " : ""}#{strategy}: #{selector}"
|
85
85
|
begin
|
86
86
|
if @cache[:selector] != selector || # cache miss, selector is different
|
87
87
|
@cache[:time] + 5 <= Time.now || # cache miss, older than 5 seconds
|
@@ -89,23 +89,13 @@ module TestaAppiumDriver
|
|
89
89
|
@cache[:from_element_id] != from_element_id || # cache miss, search is started from different element
|
90
90
|
skip_cache # cache is skipped
|
91
91
|
|
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
|
92
|
+
if single
|
93
|
+
execute_result = from_element.find_element("#{strategy}": selector)
|
105
94
|
else
|
106
|
-
|
95
|
+
execute_result = from_element.find_elements("#{strategy}": selector)
|
107
96
|
end
|
108
97
|
|
98
|
+
|
109
99
|
unless skip_cache
|
110
100
|
@cache[:selector] = selector
|
111
101
|
@cache[:strategy] = strategy
|
@@ -129,21 +119,26 @@ module TestaAppiumDriver
|
|
129
119
|
|
130
120
|
|
131
121
|
# method missing is used to forward methods to the actual appium driver
|
122
|
+
# after the method is executed, find element cache is invalidated
|
132
123
|
def method_missing(method, *args, &block)
|
133
124
|
@driver.send(method, *args, &block)
|
125
|
+
invalidate_cache
|
134
126
|
end
|
135
127
|
|
128
|
+
# disables implicit wait
|
136
129
|
def disable_implicit_wait
|
137
130
|
@implicit_wait_ms = @driver.get_timeouts["implicit"]
|
138
131
|
@driver.manage.timeouts.implicit_wait = 0
|
139
132
|
end
|
140
133
|
|
134
|
+
# enables implicit wait, can be called only after disabling implicit wait
|
141
135
|
def enable_implicit_wait
|
142
136
|
raise "Implicit wait is not disabled" if @implicit_wait_ms.nil?
|
143
137
|
# get_timeouts always returns in milliseconds, but we should set in seconds
|
144
138
|
@driver.manage.timeouts.implicit_wait = @implicit_wait_ms / 1000
|
145
139
|
end
|
146
140
|
|
141
|
+
# disables wait for idle, only executed for android devices
|
147
142
|
def disable_wait_for_idle
|
148
143
|
if @device == :android
|
149
144
|
@wait_for_idle_timeout = @driver.settings.get["waitForIdleTimeout"]
|
@@ -151,6 +146,7 @@ module TestaAppiumDriver
|
|
151
146
|
end
|
152
147
|
end
|
153
148
|
|
149
|
+
# enables wait for idle, only executed for android devices
|
154
150
|
def enable_wait_for_idle
|
155
151
|
if @device == :android
|
156
152
|
raise "Wait for idle is not disabled" if @wait_for_idle_timeout.nil?
|
@@ -158,12 +154,15 @@ module TestaAppiumDriver
|
|
158
154
|
end
|
159
155
|
end
|
160
156
|
|
157
|
+
|
158
|
+
# @@return [String] current package under test
|
161
159
|
def current_package
|
162
160
|
@driver.current_package
|
163
161
|
end
|
164
162
|
|
165
|
-
|
166
|
-
|
163
|
+
|
164
|
+
def window_size
|
165
|
+
@driver.window_size
|
167
166
|
end
|
168
167
|
|
169
168
|
def back
|
@@ -188,6 +187,7 @@ module TestaAppiumDriver
|
|
188
187
|
end
|
189
188
|
|
190
189
|
|
190
|
+
# @return [Array<Selenium::WebDriver::Element] array of 2 elements, the first element without children and the last element without children in the current page
|
191
191
|
def first_and_last_leaf(from_element = @driver)
|
192
192
|
disable_wait_for_idle
|
193
193
|
disable_implicit_wait
|