testa_appium_driver 0.1.6 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb79ce18b9e98f651e83630eff7efe2d71d77031231f88c04521e7d4f1baf483
4
- data.tar.gz: 94d1b8a88844c8726b1b87cd500ca07842b7b92190df7ef223f2cac4f929c9d9
3
+ metadata.gz: 81983750f782941f5fb92f5261e63e70a7ec3ebfc539d75cdcb0ae89e7466ee1
4
+ data.tar.gz: 0ebb35e812a6bbe96b3301e4420fac3ff4cfe0ab4dc6681d4db2b272f7a1fad9
5
5
  SHA512:
6
- metadata.gz: 9c2abf9c966c5e8d192c52e48226fcf0d73994315b3d865e48ce03f41aced48f3785dcaf7d46fd26b6e21fa51e0035cae6b00e416fffde3ae1ab0a5cf703b982
7
- data.tar.gz: e7e087b4b4227eb4d355df738f53d4ea72903b80fe51d3408c8c7ec6ac855a2066f40882dbae55de3418a1827895bcbefa14aa9b3322d767e22cd94393c1a67c
6
+ metadata.gz: 81235f7492aa031cbb25cfda0a74c1e08b14e723b293085e23f145fbf7eff59883fa677720b074306afef4ece650cad6f56e6d5a6f524b5a7eaaa5e160577c47
7
+ data.tar.gz: 4ad3449934ca4f3cec3b7b886970eb66fc2dc64207ef4cc14d50d21fb33cc0a232bdbe631922ec34e6a88228ab0735c466d58a6527cd11628f4919dc7199ee15
data/.gitignore CHANGED
@@ -13,4 +13,4 @@
13
13
  /.idea/deployment.xml
14
14
  /.idea/workspace.xml
15
15
  /.idea/misc.xml
16
- Gemfile.lock
16
+ Gemfile.lock
data/.idea/deployment.xml CHANGED
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <project version="4">
3
- <component name="PublishConfigData" autoUpload="On explicit save action" serverName="supertesta.com" autoUploadExternalChanges="true">
3
+ <component name="PublishConfigData" autoUpload="On explicit save action" serverName="supertesta.com" preserveTimestamps="false" autoUploadExternalChanges="true">
4
4
  <serverData>
5
5
  <paths name="supertesta.com">
6
6
  <serverdata>
@@ -12,7 +12,7 @@
12
12
  <paths name="testa.fun">
13
13
  <serverdata>
14
14
  <mappings>
15
- <mapping deploy="/testa_docker/path_data/testa_appium_driver" local="$PROJECT_DIR$" web="/" />
15
+ <mapping local="$PROJECT_DIR$" web="/" />
16
16
  </mappings>
17
17
  </serverdata>
18
18
  </paths>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="RunConfigurationProducerService">
4
+ <option name="ignoredProducers">
5
+ <set>
6
+ <option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
7
+ </set>
8
+ </option>
9
+ </component>
10
+ </project>
data/README.md CHANGED
@@ -202,12 +202,18 @@ siblings selector can only be used with xpath strategy.
202
202
  - search_views
203
203
  - spinner
204
204
  - spinners
205
+ - switch
206
+ - switches
205
207
  - toast
206
208
  - toasts
207
209
  - toolbar
208
210
  - toolbars
209
211
  - text_view
210
212
  - text_views
213
+ - web_view
214
+ - web_views
215
+ - card_view
216
+ - card_views
211
217
 
212
218
  Adjacent selectors
213
219
  - from_parent
@@ -323,11 +329,15 @@ Type Selector arguments
323
329
 
324
330
  # Scroll actions
325
331
  - each
326
- - align!
327
- - align_top!
328
- - align_bottom!
329
- - align_left!
330
- - align_right!
332
+ - each_down
333
+ - each_up
334
+ - each_left
335
+ - each_right
336
+ - align! (if does not exist, will scroll to find)
337
+ - align_top! (if does not exist, will scroll to find)
338
+ - align_bottom! (if does not exist, will scroll to find)
339
+ - align_left! (if does not exist, will scroll to find)
340
+ - align_right! (if does not exist, will scroll to find)
331
341
  - align
332
342
  - align_top
333
343
  - align_bottom
@@ -355,6 +365,9 @@ Type Selector arguments
355
365
  - as_scrollable
356
366
  - wait_until_exists
357
367
  - wait_while_exists
368
+ - wait_until
369
+ - wait_while
370
+ - when_exists
358
371
  - exists?
359
372
  - long_tap
360
373
 
@@ -24,6 +24,9 @@ module TestaAppiumDriver
24
24
  # @param selectors [Hash]
25
25
  # @return [TestaAppiumDriver::Locator] first element
26
26
  def element(selectors = {})
27
+ unless selectors[:image].nil?
28
+ selectors[:strategy] = FIND_STRATEGY_IMAGE
29
+ end
27
30
  add_selector(selectors)
28
31
  end
29
32
 
@@ -31,24 +34,9 @@ module TestaAppiumDriver
31
34
  # @param params [Hash]
32
35
  # @return [TestaAppiumDriver::Locator] all elements that match given selectors
33
36
  def elements(params = {})
34
- params[:single] = false
35
- add_selector(params)
36
- end
37
-
38
-
39
- # first element that has scrollable: true
40
- # @param selectors [Hash]
41
- # @return [TestaAppiumDriver::Locator] first scrollable element
42
- def scrollable(selectors = {})
43
- selectors[:scrollable] = true
44
- add_selector(selectors)
45
- end
46
-
47
- # all elements that have scrollable: true
48
- # @param params [Hash]
49
- # @return [TestaAppiumDriver::Locator] first scrollable element
50
- def scrollables(params = {})
51
- params[:scrollable] = true
37
+ unless params[:image].nil?
38
+ params[:strategy] = FIND_STRATEGY_IMAGE
39
+ end
52
40
  params[:single] = false
53
41
  add_selector(params)
54
42
  end
@@ -399,5 +387,52 @@ module TestaAppiumDriver
399
387
  add_selector(params)
400
388
  end
401
389
 
390
+
391
+ # first androidx.cardview.widget.CardView element that match given selectors
392
+ # @return [TestaAppiumDriver::Locator]
393
+ def card_view(params = {})
394
+ params[:class] = "androidx.cardview.widget.CardView"
395
+ add_selector(params)
396
+ end
397
+
398
+ # all androidx.cardview.widget.CardView elements that match given selectors
399
+ # @return [TestaAppiumDriver::Locator]
400
+ def card_views(params = {})
401
+ params[:class] = "androidx.cardview.widget.CardView"
402
+ params[:single] = false
403
+ add_selector(params)
404
+ end
405
+
406
+ # first android.widget.Switch element that match given selectors
407
+ # @return [TestaAppiumDriver::Locator]
408
+ def switch(params = {})
409
+ params[:class] = "android.widget.Switch"
410
+ add_selector(params)
411
+ end
412
+
413
+ # all android.widget.Switch elements that match given selectors
414
+ # @return [TestaAppiumDriver::Locator]
415
+ def switches(params = {})
416
+ params[:class] = "android.widget.Switch"
417
+ params[:single] = false
418
+ add_selector(params)
419
+ end
420
+
421
+
422
+ # first android.webkit.WebView element that match given selectors
423
+ # @return [TestaAppiumDriver::Locator]
424
+ def web_view(params = {})
425
+ params[:class] = "android.webkit.WebView"
426
+ add_selector(params)
427
+ end
428
+
429
+ # all android.webkit.WebView elements that match given selectors
430
+ # @return [TestaAppiumDriver::Locator]
431
+ def web_views(params = {})
432
+ params[:class] = "android.webkit.WebView"
433
+ params[:single] = false
434
+ add_selector(params)
435
+ end
436
+
402
437
  end
403
438
  end
@@ -24,6 +24,23 @@ module TestaAppiumDriver
24
24
  end
25
25
 
26
26
 
27
+ def scrollable
28
+ locator = Locator.new(self, self, {single: true})
29
+ locator.xpath_selector = "//androidx.recyclerview.widget.RecyclerView|//android.widget.ScrollView|//android.widget.ListView|//android.widget.HorizontalScrollView"
30
+ locator.ui_selector = "new UiSelector().scrollable(true).instance(0)"
31
+ locator
32
+ end
33
+
34
+
35
+ def scrollables
36
+ locator = Locator.new(self, self, {single: false})
37
+ locator.xpath_selector = "//androidx.recyclerview.widget.RecyclerView|//android.widget.ScrollView|//android.widget.ListView|//android.widget.HorizontalScrollView"
38
+ locator.ui_selector = "new UiSelector().scrollable(true)"
39
+ locator
40
+ end
41
+
42
+
43
+
27
44
  private
28
45
  def handle_testa_opts
29
46
  if @testa_opts[:default_find_strategy].nil?
@@ -7,7 +7,6 @@ module TestaAppiumDriver
7
7
 
8
8
  @driver = get_driver if self.instance_of?(Selenium::WebDriver::Element)
9
9
 
10
- @driver.disable_wait_for_idle
11
10
  if elements.kind_of?(Selenium::WebDriver::Element)
12
11
  r = elements.send(:attribute, name.to_s)
13
12
  r = TestaAppiumDriver::Bounds.from_android(r, @driver) if name.to_s == "bounds"
@@ -15,7 +14,6 @@ module TestaAppiumDriver
15
14
  r = elements.map { |e| e.send(:attribute, name.to_s) }
16
15
  r.map! { |b| TestaAppiumDriver::Bounds.from_android(b, @driver) } if name.to_s == "bounds"
17
16
  end
18
- @driver.enable_wait_for_idle
19
17
  r
20
18
  end
21
19
 
@@ -110,7 +108,7 @@ module TestaAppiumDriver
110
108
  children = self.dup.parent.children.execute
111
109
  index = children.index(this)
112
110
  raise "Index not found" if index.nil?
113
- index
111
+ index.to_i
114
112
  end
115
113
  end
116
114
  end
@@ -48,6 +48,10 @@ module TestaAppiumDriver
48
48
  if @strategy.nil? || @strategy == FIND_STRATEGY_XPATH
49
49
  ss.push({"#{FIND_STRATEGY_XPATH}": @xpath_selector})
50
50
  end
51
+
52
+ if @strategy == FIND_STRATEGY_IMAGE
53
+ ss.push({"#{FIND_STRATEGY_IMAGE}": @image_selector})
54
+ end
51
55
  ss
52
56
  end
53
57
 
@@ -93,6 +97,8 @@ module TestaAppiumDriver
93
97
  add_xpath_child_selectors(locator, selectors, single)
94
98
  elsif @strategy == FIND_STRATEGY_UIAUTOMATOR
95
99
  locator = add_uiautomator_child_selector(locator, selectors, single)
100
+ elsif @strategy == FIND_STRATEGY_IMAGE
101
+ locator = add_image_child_selector(locator, selectors, single)
96
102
  else
97
103
  # both paths are valid
98
104
  add_xpath_child_selectors(locator, selectors, single)
@@ -100,7 +106,7 @@ module TestaAppiumDriver
100
106
  end
101
107
 
102
108
  if is_scrollable_selector?(selectors, single)
103
- locator.scrollable_locator = self
109
+ locator.scrollable_locator = locator
104
110
  if selectors[:class] == "android.widget.HorizontalScrollView"
105
111
  locator.scrollable_locator.scroll_orientation = :horizontal
106
112
  else
@@ -127,5 +133,10 @@ module TestaAppiumDriver
127
133
  locator
128
134
  end
129
135
  end
136
+
137
+ def add_image_child_selector(locator, selectors, single)
138
+ params = selectors.merge({single: single, scrollable_locator: locator.scrollable_locator})
139
+ Locator.new(@driver, self, params)
140
+ end
130
141
  end
131
142
  end
@@ -4,8 +4,6 @@ module TestaAppiumDriver
4
4
  private
5
5
 
6
6
  def uiautomator_scroll_to_start_or_end(type)
7
- @driver.disable_wait_for_idle
8
- @driver.disable_implicit_wait
9
7
 
10
8
  scrollable_selector = @scrollable.ui_selector(false)
11
9
  orientation = @scrollable.scroll_orientation == :vertical ? ".setAsVerticalList()" : ".setAsHorizontalList()"
@@ -19,18 +17,12 @@ module TestaAppiumDriver
19
17
  end
20
18
 
21
19
 
22
- @driver.enable_implicit_wait
23
- @driver.enable_wait_for_idle
24
20
  end
25
21
 
26
22
 
27
23
  def uiautomator_scroll_to
28
24
  raise "UiAutomator scroll cannot work with specified direction" unless @direction.nil?
29
25
 
30
-
31
- @driver.disable_wait_for_idle
32
- @driver.disable_implicit_wait
33
-
34
26
  scrollable_selector = @scrollable.ui_selector(false)
35
27
  element_selector = @locator.ui_selector(false)
36
28
  orientation_command = @scrollable.scroll_orientation == :vertical ? ".setAsVerticalList()" : ".setAsHorizontalList()"
@@ -41,15 +33,11 @@ module TestaAppiumDriver
41
33
  rescue
42
34
  # Ignored
43
35
  ensure
44
- @driver.enable_implicit_wait
45
- @driver.enable_wait_for_idle
46
36
  end
47
37
  end
48
38
 
49
39
 
50
40
  def uiautomator_page_or_fling(type, direction)
51
- @driver.disable_wait_for_idle
52
- @driver.disable_implicit_wait
53
41
 
54
42
  scrollable_selector = @scrollable.ui_selector(false)
55
43
  orientation = direction == :up || direction == :down ? ".setAsVerticalList()" : ".setAsHorizontalList()"
@@ -67,8 +55,6 @@ module TestaAppiumDriver
67
55
  rescue
68
56
  # Ignored
69
57
  end
70
- @driver.enable_implicit_wait
71
- @driver.enable_wait_for_idle
72
58
  end
73
59
 
74
60
 
@@ -6,6 +6,8 @@ module TestaAppiumDriver
6
6
  FIND_STRATEGY_XPATH = :xpath
7
7
  FIND_STRATEGY_ID = :id
8
8
  FIND_STRATEGY_NAME = :name
9
+ FIND_STRATEGY_IMAGE = :image
10
+ FIND_STRATEGY_CLASS_CHAIN = :class_chain
9
11
 
10
12
  SCROLL_STRATEGY_UIAUTOMATOR = :uiautomator
11
13
  SCROLL_STRATEGY_W3C = :w3c
@@ -120,7 +120,9 @@ module TestaAppiumDriver
120
120
  command = "#{ command }[@focused=\"#{ hash[:focused] }\"]" unless hash[:focused].nil?
121
121
  command = "#{ command }[@index=\"#{ hash[:index] }\"]" unless hash[:index].nil?
122
122
  command = "#{ command }[@selected=\"#{ hash[:selected] }\"]" unless hash[:selected].nil?
123
- command = "#{ command }[@scrollable=\"#{ hash[:scrollable] }\"]" unless hash[:scrollable].nil?
123
+
124
+ # it seems like you cannot query by scrollable
125
+ # command = "#{ command }[@scrollable=\"#{ hash[:scrollable] }\"]" unless hash[:scrollable].nil?
124
126
  else
125
127
 
126
128
  hash[:type] = hash[:class] unless hash[:class].nil?
@@ -155,6 +157,33 @@ module TestaAppiumDriver
155
157
  command
156
158
  end
157
159
 
160
+
161
+ def hash_to_class_chain(hash, single = true)
162
+ command = "**/"
163
+
164
+ hash[:type] = hash[:class] unless hash[:class].nil?
165
+ hash[:label] = hash[:text] unless hash[:text].nil?
166
+ hash[:name] = hash[:id] unless hash[:id].nil?
167
+ if hash[:type] && hash[:type].kind_of?(String)
168
+ command = "#{ command }#{hash[:type] }"
169
+ else
170
+ command = "#{command}*"
171
+ end
172
+
173
+ command = "#{ command }[`enabled == #{ hash[:enabled] }`]" unless hash[:enabled].nil?
174
+ command = "#{ command }[`label == \"#{ %(#{hash[:label] }) }\"`]" if hash[:label] && hash[:label].kind_of?(String)
175
+ command = "#{ command }[`label CONTAINS \"#{ %(#{hash[:label].source }) }\"`]" if hash[:label] && hash[:label].kind_of?(Regexp)
176
+ command = "#{ command }[`name == \"#{ %(#{hash[:name] }) }\"`]" if hash[:name] && hash[:name].kind_of?(String)
177
+ command = "#{ command }[`name CONTAINS \"#{ %(#{hash[:name].source }) }\"`]" if hash[:name] && hash[:name].kind_of?(Regexp)
178
+ command = "#{ command }[`value == \"#{ %(#{hash[:value] }) }\"`]" if hash[:value] && hash[:value].kind_of?(String)
179
+ command = "#{ command }[`value CONTAINS \"#{ %(#{hash[:value].source }) }\"`]" if hash[:value] && hash[:value].kind_of?(Regexp)
180
+ command = "#{ command }[`visible == #{ hash[:visible] }`]" unless hash[:visible].nil?
181
+
182
+ command += "[1]" if single
183
+
184
+ command
185
+ end
186
+
158
187
  # check if selectors are for a scrollable element
159
188
  # @param [Boolean] single should the command return first instance or all of matched elements
160
189
  # @param [Hash] selectors for fetching elements
@@ -205,6 +234,8 @@ module TestaAppiumDriver
205
234
  :visible,
206
235
  :name,
207
236
  :value,
237
+
238
+ :image
208
239
  ].include?(key) }
209
240
  params = Hash[params.to_a - selectors.to_a]
210
241
 
@@ -250,6 +250,22 @@ module TestaAppiumDriver
250
250
  _fling(:right, _process_deadzone(top, bottom, right, left))
251
251
  end
252
252
 
253
+ def drag_up_by(amount)
254
+ drag_by(amount, direction: :top)
255
+ end
256
+
257
+ def drag_down_by(amount)
258
+ drag_by(amount, direction: :bottom)
259
+ end
260
+
261
+ def drag_left_by(amount)
262
+ drag_by(amount, direction: :left)
263
+ end
264
+
265
+ def drag_right_by(amount)
266
+ drag_by(amount, direction: :right)
267
+ end
268
+
253
269
 
254
270
  # @param [TestaAppiumDriver::Locator, Hash, Selenium::WebDriver::Element, String] to
255
271
  #noinspection RubyYardParamTypeMatch,RubyScope
@@ -273,7 +289,7 @@ module TestaAppiumDriver
273
289
  x = to[:x]
274
290
  y = to[:y]
275
291
  end
276
- _drag_to(x, y)
292
+ _drag_to(bounds.center.x, bounds.center.y, x, y)
277
293
  end
278
294
 
279
295
  def drag_by(amount, direction: :top)
@@ -292,7 +308,7 @@ module TestaAppiumDriver
292
308
  else
293
309
  raise "Unknown direction #{direction}"
294
310
  end
295
- _drag_to(x, y)
311
+ _drag_to(b.center.x, b.center.y, x, y)
296
312
  end
297
313
 
298
314
 
@@ -310,11 +326,11 @@ module TestaAppiumDriver
310
326
  deadzone
311
327
  end
312
328
 
313
- def _drag_to(x, y)
329
+ def _drag_to(x0, y0, x1, y1)
314
330
  sa = ScrollActions.new(@scrollable_locator,
315
331
  locator: self,
316
332
  default_scroll_strategy: @default_scroll_strategy)
317
- sa.drag_to(x, y)
333
+ sa.drag_to(x0, y0, x1, y1)
318
334
  self
319
335
  end
320
336
 
@@ -17,6 +17,8 @@ module TestaAppiumDriver
17
17
  attr_accessor :last_selector_adjacent
18
18
  attr_accessor :can_use_id_strategy
19
19
 
20
+ attr_accessor :image_selector
21
+
20
22
  attr_accessor :from_element
21
23
  attr_accessor :scroll_orientation
22
24
  attr_accessor :scroll_deadzone
@@ -41,12 +43,21 @@ module TestaAppiumDriver
41
43
  # @type [TestaAppiumDriver::Driver]
42
44
  @driver = driver
43
45
  @index_for_multiple = nil
46
+ @image_selector = nil
44
47
 
45
48
  params, selectors = extract_selectors_from_params(params)
46
49
  single = params[:single]
47
50
 
48
51
  @single = single
49
52
 
53
+ if selectors[:image].nil?
54
+ if from_element.instance_of?(TestaAppiumDriver::Locator) && !from_element.image_selector.nil?
55
+ raise "Cannot chain non-image selectors to image selectors"
56
+ end
57
+ else
58
+ handle_image_selector(selectors, params)
59
+ end
60
+
50
61
  selectors[:id] = selectors[:name] unless selectors[:name].nil?
51
62
  if from_element.instance_of?(Selenium::WebDriver::Element)
52
63
  @xpath_selector = "//*" # to select current element
@@ -80,6 +91,8 @@ module TestaAppiumDriver
80
91
  end
81
92
 
82
93
 
94
+
95
+
83
96
  def is_only_id_selector?(selectors)
84
97
  # since, name and id is the same thing for iOS,
85
98
  if @driver.device == :android
@@ -95,7 +108,6 @@ module TestaAppiumDriver
95
108
  def method_missing(method, *args, &block)
96
109
  r = execute.send(method, *args, &block)
97
110
  @driver.invalidate_cache
98
- r = r[@index_for_multiple] if !@index_for_multiple.nil? && !@single
99
111
  r
100
112
  end
101
113
 
@@ -103,14 +115,16 @@ module TestaAppiumDriver
103
115
  # @param [Boolean] skip_cache if true it will skip cache check and store
104
116
  # @param [Selenium::WebDriver::Element] force_cache_element, for internal use where we have already the element, and want to execute custom locator methods on it
105
117
  # @return [Selenium::WebDriver::Element, Array]
106
- def execute(skip_cache: false, force_cache_element: nil)
118
+ def execute(skip_cache: false, force_cache_element: nil, ignore_implicit_wait: false)
107
119
  return force_cache_element unless force_cache_element.nil?
108
120
  # if we are looking for current element, then return from_element
109
121
  # for example when we have driver.element.elements[1].click
110
122
  # elements[2] will be resolved with xpath because we are looking for multiple elements from element
111
123
  # and since we are looking for instance 2, [](instance) method will return new "empty locator"
112
124
  # we are executing click on that "empty locator" so we have to return the instance 2 of elements for the click
113
- if @xpath_selector == "//*/*[1]" && @from_element.instance_of?(Selenium::WebDriver::Element)
125
+ if @xpath_selector == "//*[1]" && !@from_element.nil? && @image_selector.nil?
126
+ return @from_element if @from_element.instance_of?(Selenium::WebDriver::Element)
127
+ 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)
114
128
  return @from_element
115
129
  end
116
130
 
@@ -119,11 +133,30 @@ module TestaAppiumDriver
119
133
 
120
134
 
121
135
 
122
- r = @driver.execute(@from_element, @single, strategies_and_selectors, skip_cache)
136
+ r = @driver.execute(@from_element, @single, strategies_and_selectors, skip_cache: skip_cache, ignore_implicit_wait: ignore_implicit_wait)
123
137
  r = r[@index_for_multiple] if !@index_for_multiple.nil? && !@single
124
138
  r
125
139
  end
126
140
 
141
+ def when_exists(timeout = nil, &block)
142
+ timeout = @driver.get_timeouts["implicit"] / 1000 if timeout.nil?
143
+ found = false
144
+ begin
145
+ wait_until_exists(timeout)
146
+ found = true
147
+ rescue
148
+ #ignored
149
+ end
150
+ if found
151
+ if block_given? # block is given
152
+ block.call(self) # use call to execute the block
153
+ else # the value of block_argument becomes nil if you didn't give a block
154
+ # block was not given
155
+ end
156
+ end
157
+ self
158
+ end
159
+
127
160
 
128
161
  # @param [Integer] timeout in seconds
129
162
  # @return [TestaAppiumDriver::Locator]
@@ -157,16 +190,12 @@ module TestaAppiumDriver
157
190
  # all timeouts are disabled before check, and enabled after check
158
191
  # @return [boolean] true if it exists in the page regardless if visible or not
159
192
  def exists?
160
- @driver.disable_wait_for_idle
161
- @driver.disable_implicit_wait
162
193
  found = true
163
194
  begin
164
- execute(skip_cache: true)
195
+ execute(skip_cache: true, ignore_implicit_wait: true)
165
196
  rescue StandardError
166
197
  found = false
167
198
  end
168
- @driver.enable_implicit_wait
169
- @driver.enable_wait_for_idle
170
199
  found
171
200
  end
172
201
 
@@ -192,15 +221,23 @@ module TestaAppiumDriver
192
221
 
193
222
  def [](instance)
194
223
  raise "Cannot add index selector to non-Array" if @single
195
- if ((@strategy.nil? && !@last_selector_adjacent) || @strategy == FIND_STRATEGY_UIAUTOMATOR) && instance >= 0
224
+ if ((@strategy.nil? && !@last_selector_adjacent && @driver.device == :android) || @strategy == FIND_STRATEGY_UIAUTOMATOR) && instance >= 0
196
225
  locator = self.dup
197
226
  locator.strategy = FIND_STRATEGY_UIAUTOMATOR
198
227
  locator.ui_selector = "#{@ui_selector}.instance(#{instance})"
199
228
  locator.single = true
200
229
  locator.can_use_id_strategy = false
201
230
  locator
231
+ elsif (@driver.device == :ios && !@last_selector_adjacent && @strategy.nil?) || @strategy == FIND_STRATEGY_CLASS_CHAIN
232
+ locator = self.dup
233
+ locator.strategy = FIND_STRATEGY_CLASS_CHAIN
234
+ locator.class_chain_selector += "[#{instance + 1}]"
235
+ locator.single = true
236
+ locator.can_use_id_strategy = false
237
+ locator
202
238
  else
203
- from_element = self.index_for_multiple = instance
239
+ from_element = self.dup
240
+ from_element.index_for_multiple = instance
204
241
  params = {}.merge({single: true, scrollable_locator: @scrollable_locator})
205
242
  #params[:strategy] = FIND_STRATEGY_XPATH
206
243
  #params[:strategy_reason] = "retrieved instance of a array"
@@ -276,7 +313,15 @@ module TestaAppiumDriver
276
313
  end
277
314
 
278
315
  def click
279
- perform_driver_method(:click)
316
+ if @driver.device == :android
317
+ perform_driver_method(:click)
318
+ else
319
+ # on ios, if element is not visible, first click will scroll to it
320
+ # then on second click actually perform the click
321
+ visible = visible?
322
+ perform_driver_method(:click)
323
+ perform_driver_method(:click) unless visible rescue nil
324
+ end
280
325
  end
281
326
 
282
327
  def send_key(*args)
@@ -306,15 +351,20 @@ module TestaAppiumDriver
306
351
  # @return [TestaAppiumDriver::Locator]
307
352
  def children
308
353
  raise "Cannot add children selector to array" unless @single
309
- raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "children") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
354
+ raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "children") if @strategy != FIND_STRATEGY_XPATH && @strategy != FIND_STRATEGY_CLASS_CHAIN && !@strategy.nil?
310
355
 
311
356
  locator = self.dup
312
- locator.strategy = FIND_STRATEGY_XPATH
313
357
  locator.strategy_reason = "children"
314
358
  locator.xpath_selector += "/*"
315
359
  locator.single = false
316
360
  locator.last_selector_adjacent = true
317
361
  locator.can_use_id_strategy = false
362
+
363
+ if @driver.device == :android
364
+ locator.strategy = FIND_STRATEGY_XPATH
365
+ else
366
+ locator.class_chain_selector += "/*"
367
+ end
318
368
  locator
319
369
  end
320
370
 
@@ -323,14 +373,20 @@ module TestaAppiumDriver
323
373
  # @return [TestaAppiumDriver::Locator]
324
374
  def child
325
375
  raise "Cannot add children selector to array" unless @single
326
- raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "child") if @strategy != FIND_STRATEGY_XPATH && !@strategy.nil?
376
+ raise StrategyMixException.new(@strategy, @strategy_reason, FIND_STRATEGY_XPATH, "child") if @strategy != FIND_STRATEGY_XPATH && @strategy != FIND_STRATEGY_CLASS_CHAIN && !@strategy.nil?
327
377
 
328
378
  locator = self.dup
329
- locator.strategy = FIND_STRATEGY_XPATH
379
+
330
380
  locator.strategy_reason = "child"
331
381
  locator.xpath_selector += "/*[1]"
332
382
  locator.single = true
333
383
  locator.can_use_id_strategy = false
384
+
385
+ if @driver.device == :android
386
+ locator.strategy = FIND_STRATEGY_XPATH
387
+ else
388
+ locator.class_chain_selector += "/*[1]"
389
+ end
334
390
  locator
335
391
  end
336
392
 
@@ -482,6 +538,42 @@ module TestaAppiumDriver
482
538
  locator.single = false unless single # switching from single result to multiple
483
539
  locator.xpath_selector += hash_to_xpath(@driver.device, selectors, single)
484
540
  end
541
+
542
+
543
+ def handle_image_selector(selectors, params)
544
+ image_match_threshold = 0.4
545
+ image_match_threshold = params[:imageMatchThreshold] unless params[:imageMatchThreshold].nil?
546
+ image_match_threshold = params[:threshold] unless params[:threshold].nil?
547
+ fix_image_find_screenshot_dims = true
548
+ fix_image_find_screenshot_dims = params[:fixImageFindScreenshotDims] unless params[:fixImageFindScreenshotDims].nil?
549
+ fix_image_template_size = false
550
+ fix_image_template_size = params[:fixImageTemplateSize] unless params[:fixImageTemplateSize].nil?
551
+ fix_image_template_scale = false
552
+ fix_image_template_scale = params[:fixImageTemplateScale] unless params[:fixImageTemplateScale].nil?
553
+ default_image_template_scale = 1.0
554
+ default_image_template_scale = params[:defaultImageTemplateScale] unless params[:defaultImageTemplateScale].nil?
555
+ check_for_image_element_staleness = true
556
+ check_for_image_element_staleness = params[:checkForImageElementStaleness] unless params[:checkForImageElementStaleness].nil?
557
+ auto_update_image_element_position = false
558
+ auto_update_image_element_position = params[:autoUpdateImageElementPosition] unless params[:autoUpdateImageElementPosition].nil?
559
+ image_element_tap_strategy = "w3cActions"
560
+ image_element_tap_strategy = params[:imageElementTapStrategy] unless params[:imageElementTapStrategy].nil?
561
+ get_matched_image_result = false
562
+ get_matched_image_result = params[:getMatchedImageResult] unless params[:getMatchedImageResult].nil?
563
+
564
+ @image_selector = {
565
+ image: selectors[:image],
566
+ imageMatchThreshold: image_match_threshold,
567
+ fixImageFindScreenshotDims: fix_image_find_screenshot_dims,
568
+ fixImageTemplateSize: fix_image_template_size,
569
+ fixImageTemplateScale: fix_image_template_scale,
570
+ defaultImageTemplateScale: default_image_template_scale,
571
+ checkForImageElementStaleness: check_for_image_element_staleness,
572
+ autoUpdateImageElementPosition: auto_update_image_element_position,
573
+ imageElementTapStrategy: image_element_tap_strategy,
574
+ getMatchedImageResult: get_matched_image_result,
575
+ }
576
+ end
485
577
  end
486
578
 
487
579
  end
@@ -6,8 +6,6 @@ module TestaAppiumDriver
6
6
  def w3c_each(direction, &block)
7
7
  elements = []
8
8
  begin
9
- @driver.disable_wait_for_idle
10
- @driver.disable_implicit_wait
11
9
  default_deadzone!
12
10
 
13
11
  iterations = 0
@@ -25,6 +23,7 @@ module TestaAppiumDriver
25
23
  until is_end_of_scroll?
26
24
  matches = @locator.execute(skip_cache: true)
27
25
  matches.each_with_index do |m|
26
+ next if elements.include?(m)
28
27
  elements << m
29
28
  if block_given? # block is given
30
29
  block.call(m) # use call to execute the block
@@ -38,15 +37,12 @@ module TestaAppiumDriver
38
37
  end
39
38
  rescue => e
40
39
  raise e
41
- ensure
42
- @driver.enable_implicit_wait
43
- @driver.enable_wait_for_idle
40
+
44
41
  end
45
42
  elements
46
43
  end
47
44
 
48
45
  def w3c_align(with, scroll_to_find)
49
- @driver.disable_wait_for_idle
50
46
  default_deadzone!
51
47
 
52
48
 
@@ -54,20 +50,6 @@ module TestaAppiumDriver
54
50
  @locator.scroll_to if scroll_to_find
55
51
 
56
52
  element = @locator.execute
57
- @driver.disable_implicit_wait
58
-
59
- case with
60
- when :top
61
- page_down if is_aligned?(with, element)
62
- when :bottom
63
- page_up if is_aligned?(with, element)
64
- when :right
65
- page_right if is_aligned?(with, element)
66
- when :left
67
- page_left if is_aligned?(with, element)
68
- else
69
- raise "Unsupported align with option: #{with}"
70
- end
71
53
 
72
54
  timeout = 0
73
55
  until is_aligned?(with, element) || timeout == 3
@@ -75,8 +57,6 @@ module TestaAppiumDriver
75
57
  timeout += 1
76
58
  end
77
59
 
78
- @driver.enable_implicit_wait
79
- @driver.enable_wait_for_idle
80
60
  end
81
61
 
82
62
 
@@ -150,8 +130,6 @@ module TestaAppiumDriver
150
130
  end
151
131
 
152
132
  def w3c_scroll_to_start_or_end(type)
153
- @driver.disable_wait_for_idle
154
- @driver.disable_implicit_wait
155
133
  default_deadzone!
156
134
 
157
135
  @previous_elements = nil
@@ -179,15 +157,10 @@ module TestaAppiumDriver
179
157
 
180
158
  # reset the flag for end of scroll elements
181
159
  @previous_elements = nil
182
-
183
- @driver.enable_implicit_wait
184
- @driver.enable_wait_for_idle
185
160
  end
186
161
 
187
162
 
188
163
  def w3c_page_or_fling(type, direction)
189
- @driver.disable_wait_for_idle
190
- @driver.disable_implicit_wait
191
164
  default_deadzone!
192
165
 
193
166
  if direction == :down || direction == :up
@@ -216,8 +189,6 @@ module TestaAppiumDriver
216
189
 
217
190
  w3c_action(x0, y0, x1, y1, type)
218
191
 
219
- @driver.enable_implicit_wait
220
- @driver.enable_wait_for_idle
221
192
  end
222
193
 
223
194
 
@@ -258,10 +229,8 @@ module TestaAppiumDriver
258
229
 
259
230
 
260
231
 
261
- def drag_to(x, y)
262
- x0 = @bounds.center.x
263
- y0 = @bounds.center.y
264
- w3c_action(x0, y0, x, y, SCROLL_ACTION_TYPE_DRAG)
232
+ def w3c_drag_to(x0, y0, x1, y1)
233
+ w3c_action(x0, y0, x1, y1, SCROLL_ACTION_TYPE_DRAG)
265
234
  end
266
235
 
267
236
  end
@@ -1,7 +1,6 @@
1
1
  require_relative 'scroll_actions/json_wire_scroll_actions'
2
2
  require_relative 'scroll_actions/w3c_scroll_actions'
3
3
 
4
-
5
4
  module TestaAppiumDriver
6
5
 
7
6
  # Class for handling scroll actions
@@ -21,7 +20,6 @@ module TestaAppiumDriver
21
20
  @default_scroll_strategy = params[:default_scroll_strategy]
22
21
  @driver = @locator.driver
23
22
 
24
-
25
23
  if @scrollable.nil?
26
24
  # if we dont have a scrollable element or if we do have it, but it is not compatible with uiautomator
27
25
  # then find first scrollable in document
@@ -30,16 +28,14 @@ module TestaAppiumDriver
30
28
 
31
29
  @strategy = nil
32
30
  if @scrollable.strategy == FIND_STRATEGY_XPATH || # uiautomator cannot resolve scrollable from a xpath locator
33
- !@deadzone.nil? ||
34
- !@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver) # uiautomator cannot resolve nested scrollable
31
+ !@deadzone.nil? ||
32
+ !@scrollable.from_element.instance_of?(TestaAppiumDriver::Driver) # uiautomator cannot resolve nested scrollable
35
33
  @strategy = SCROLL_STRATEGY_W3C
36
34
  end
37
35
 
38
-
39
36
  @bounds = @scrollable.bounds
40
37
  end
41
38
 
42
-
43
39
  def align(with, scroll_to_find)
44
40
  w3c_align(with, scroll_to_find)
45
41
  @locator
@@ -66,7 +62,6 @@ module TestaAppiumDriver
66
62
  w3c_each(:left, &block)
67
63
  end
68
64
 
69
-
70
65
  def resolve_strategy
71
66
  if @strategy.nil?
72
67
  @default_scroll_strategy
@@ -75,7 +70,6 @@ module TestaAppiumDriver
75
70
  end
76
71
  end
77
72
 
78
-
79
73
  def scroll_to
80
74
  if @locator.strategy != FIND_STRATEGY_XPATH && resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
81
75
  uiautomator_scroll_to
@@ -116,7 +110,6 @@ module TestaAppiumDriver
116
110
  end
117
111
  end
118
112
 
119
-
120
113
  def page_down
121
114
  if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
122
115
  uiautomator_page_or_fling(SCROLL_ACTION_TYPE_SCROLL, :down)
@@ -149,10 +142,10 @@ module TestaAppiumDriver
149
142
  end
150
143
  end
151
144
 
152
-
153
145
  def scroll_to_start
154
146
  if resolve_strategy == SCROLL_STRATEGY_UIAUTOMATOR
155
147
  uiautomator_scroll_to_start_or_end(:start)
148
+
156
149
  elsif resolve_strategy == SCROLL_STRATEGY_W3C
157
150
  w3c_scroll_to_start_or_end(:start)
158
151
  end
@@ -198,11 +191,10 @@ module TestaAppiumDriver
198
191
  end
199
192
  end
200
193
 
201
- def drag_to(x, y)
202
- w3c_drag_to(x, y)
194
+ def drag_to(x0, y0, x1, y1)
195
+ w3c_drag_to(x0, y0, x1, y1)
203
196
  end
204
197
 
205
-
206
198
  private
207
199
 
208
200
  def is_end_of_scroll?
@@ -211,7 +203,6 @@ module TestaAppiumDriver
211
203
  old_elements == @previous_elements
212
204
  end
213
205
 
214
-
215
206
  def default_deadzone!
216
207
  @deadzone = {} if @deadzone.nil?
217
208
  if @deadzone[:top].nil?
@@ -29,7 +29,6 @@ module TestaAppiumDriver
29
29
  def initialize(opts = {})
30
30
  @testa_opts = opts[:testa_appium_driver] || {}
31
31
 
32
-
33
32
  core = Appium::Core.for(opts)
34
33
  extend_for(core.device, core.automation_name)
35
34
  @device = core.device
@@ -41,6 +40,9 @@ module TestaAppiumDriver
41
40
  invalidate_cache
42
41
 
43
42
 
43
+ disable_wait_for_idle
44
+ disable_implicit_wait
45
+
44
46
  Selenium::WebDriver::Element.set_driver(self, opts[:caps][:udid])
45
47
  end
46
48
 
@@ -67,11 +69,9 @@ module TestaAppiumDriver
67
69
  # @param [Array<Hash>] strategies_and_selectors array of usable strategies and selectors
68
70
  # @param [Boolean] skip_cache to skip checking and storing cache
69
71
  # @return [Selenium::WebDriver::Element, Array] element is returned if single is true, array otherwise
70
- def execute(from_element, single, strategies_and_selectors, skip_cache = false)
72
+ def execute(from_element, single, strategies_and_selectors, skip_cache: false, ignore_implicit_wait: false)
71
73
 
72
74
  # if user wants to wait for element to exist, he can use wait_until_present
73
- disable_wait_for_idle
74
- disable_implicit_wait
75
75
  start_time = Time.now.to_f
76
76
  ss_index = 0
77
77
 
@@ -79,13 +79,13 @@ module TestaAppiumDriver
79
79
 
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.strategy_and_selector[1] : nil
82
+ from_element_id = from_element.instance_of?(TestaAppiumDriver::Locator) ? from_element.strategies_and_selectors : nil
83
83
 
84
84
  begin
85
85
  ss = strategies_and_selectors[ss_index % strategies_and_selectors.count]
86
86
  ss_index +=1
87
87
 
88
- puts "Executing #{from_element_id ? "from #{from_element.strategy}: #{from_element.strategy_and_selector} => " : ""}#{ss.keys[0]}: #{ss.values[0]}"
88
+ puts "Executing #{from_element_id ? "from #{from_element.strategy}: #{from_element.strategies_and_selectors} => " : ""}#{ss.keys[0]}: #{ss.values[0]}"
89
89
 
90
90
  if @cache[:selector] != ss.values[0] || # cache miss, selector is different
91
91
  @cache[:time] + 5 <= Time.now || # cache miss, older than 5 seconds
@@ -93,13 +93,24 @@ module TestaAppiumDriver
93
93
  @cache[:from_element_id] != from_element_id || # cache miss, search is started from different element
94
94
  skip_cache # cache is skipped
95
95
 
96
- if single
97
- execute_result = from_element.find_element(ss)
96
+ if ss.keys[0] == FIND_STRATEGY_IMAGE
97
+ set_find_by_image_settings(ss.values[0].dup)
98
+ if single
99
+ execute_result = from_element.find_element_by_image(ss.values[0][:image])
100
+ else
101
+ execute_result = from_element.find_elements_by_image(ss.values[0][:image])
102
+ end
103
+ restore_set_by_image_settings
98
104
  else
99
- execute_result = from_element.find_elements(ss)
105
+ if single
106
+ execute_result = from_element.find_element(ss)
107
+ else
108
+ execute_result = from_element.find_elements(ss)
109
+ end
100
110
  end
101
111
 
102
112
 
113
+
103
114
  unless skip_cache
104
115
  @cache[:selector] = ss.values[0]
105
116
  @cache[:strategy] = ss.keys[0]
@@ -113,15 +124,13 @@ module TestaAppiumDriver
113
124
  puts "Using cache from #{@cache[:time].strftime("%H:%M:%S.%L")}, strategy: #{@cache[:strategy]}"
114
125
  end
115
126
  rescue => e
116
- if start_time + @implicit_wait_ms/1000 < Time.now.to_f || ss_index < strategies_and_selectors.count
127
+ #if (start_time + @implicit_wait_ms/1000 < Time.now.to_f && !ignore_implicit_wait) || ss_index < strategies_and_selectors.count
128
+ if ss_index < strategies_and_selectors.count
117
129
  sleep EXISTS_WAIT if ss_index >= strategies_and_selectors.count
118
130
  retry
119
131
  else
120
132
  raise e
121
133
  end
122
- ensure
123
- enable_implicit_wait
124
- enable_wait_for_idle
125
134
  end
126
135
 
127
136
  execute_result
@@ -131,22 +140,20 @@ module TestaAppiumDriver
131
140
  # method missing is used to forward methods to the actual appium driver
132
141
  # after the method is executed, find element cache is invalidated
133
142
  def method_missing(method, *args, &block)
143
+ r = @driver.send(method, *args, &block)
134
144
  invalidate_cache
135
- @driver.send(method, *args, &block)
145
+ r
136
146
  end
137
147
 
138
148
  # disables implicit wait
139
149
  def disable_implicit_wait
140
- @implicit_wait_ms = @driver.get_timeouts["implicit"]
141
- @driver.manage.timeouts.implicit_wait = 0
150
+ @implicit_wait_ms = @driver.get_timeouts["implicit"].to_i
151
+ @implicit_wait_ms = @implicit_wait_ms/1000 if @implicit_wait_ms > 100000
152
+ @implicit_wait_uiautomator_ms = @driver.get_settings["waitForSelectorTimeout"]
153
+ @driver.manage.timeouts.implicit_wait = 0
154
+ @driver.update_settings({waitForSelectorTimeout: 0})
142
155
  end
143
156
 
144
- # enables implicit wait, can be called only after disabling implicit wait
145
- def enable_implicit_wait
146
- raise "Implicit wait is not disabled" if @implicit_wait_ms.nil?
147
- # get_timeouts always returns in milliseconds, but we should set in seconds
148
- @driver.manage.timeouts.implicit_wait = @implicit_wait_ms / 1000
149
- end
150
157
 
151
158
  # disables wait for idle, only executed for android devices
152
159
  def disable_wait_for_idle
@@ -156,12 +163,26 @@ module TestaAppiumDriver
156
163
  end
157
164
  end
158
165
 
159
- # enables wait for idle, only executed for android devices
160
- def enable_wait_for_idle
161
- if @device == :android
162
- raise "Wait for idle is not disabled" if @wait_for_idle_timeout.nil?
163
- @driver.update_settings({waitForIdleTimeout: @wait_for_idle_timeout})
164
- end
166
+
167
+ def set_find_by_image_settings(settings)
168
+ settings.delete(:image)
169
+ @default_find_image_settings = {}
170
+ old_settings = @driver.get_settings
171
+ @default_find_image_settings[:imageMatchThreshold] = old_settings["imageMatchThreshold"]
172
+ @default_find_image_settings[:fixImageFindScreenshotDims] = old_settings["fixImageFindScreenshotDims"]
173
+ @default_find_image_settings[:fixImageTemplateSize] = old_settings["fixImageTemplateSize"]
174
+ @default_find_image_settings[:fixImageTemplateScale] = old_settings["fixImageTemplateScale"]
175
+ @default_find_image_settings[:defaultImageTemplateScale] = old_settings["defaultImageTemplateScale"]
176
+ @default_find_image_settings[:checkForImageElementStaleness] = old_settings["checkForImageElementStaleness"]
177
+ @default_find_image_settings[:autoUpdateImageElementPosition] = old_settings["autoUpdateImageElementPosition"]
178
+ @default_find_image_settings[:imageElementTapStrategy] = old_settings["imageElementTapStrategy"]
179
+ @default_find_image_settings[:getMatchedImageResult] = old_settings["getMatchedImageResult"]
180
+
181
+ @driver.update_settings(settings)
182
+ end
183
+
184
+ def restore_set_by_image_settings
185
+ @driver.update_settings(@default_find_image_settings) if @default_find_image_settings
165
186
  end
166
187
 
167
188
 
@@ -188,6 +209,33 @@ module TestaAppiumDriver
188
209
  @driver.hide_keyboard
189
210
  end
190
211
 
212
+ def home_key
213
+ @driver.press_keycode(3)
214
+ end
215
+ def tab_key
216
+ @driver.press_keycode(61)
217
+ end
218
+
219
+ def dpad_up_key
220
+ @driver.press_keycode(19)
221
+ end
222
+
223
+ def dpad_down_key
224
+ @driver.press_keycode(20)
225
+ end
226
+
227
+ def dpad_right_key
228
+ @driver.press_keycode(22)
229
+ end
230
+
231
+ def dpad_left_key
232
+ @driver.press_keycode(23)
233
+ end
234
+
235
+ def enter_key
236
+ @driver.press_keycode(66)
237
+ end
238
+
191
239
  def press_keycode(code)
192
240
  @driver.press_keycode(code)
193
241
  end
@@ -197,13 +245,11 @@ module TestaAppiumDriver
197
245
  end
198
246
 
199
247
 
248
+
249
+
200
250
  # @return [Array<Selenium::WebDriver::Element] array of 2 elements, the first element without children and the last element without children in the current page
201
251
  def first_and_last_leaf(from_element = @driver)
202
- disable_wait_for_idle
203
- disable_implicit_wait
204
252
  elements = from_element.find_elements(xpath: "//*[not(*)]")
205
- enable_implicit_wait
206
- enable_wait_for_idle
207
253
  return nil if elements.count == 0
208
254
  [elements[0], elements[-1]]
209
255
  end
@@ -7,6 +7,19 @@ module TestaAppiumDriver
7
7
  include TypeSelectors
8
8
 
9
9
 
10
+
11
+ # @param params [Hash]
12
+ # @return [TestaAppiumDriver::Locator] first scrollable element
13
+ def scrollable(params = {})
14
+ scroll_view(params)
15
+ end
16
+
17
+ # @param params [Hash]
18
+ # @return [TestaAppiumDriver::Locator] first scrollable element
19
+ def scrollables(params = {})
20
+ scroll_views(params)
21
+ end
22
+
10
23
  private
11
24
  def handle_testa_opts
12
25
  if @testa_opts[:default_find_strategy].nil?
@@ -3,6 +3,7 @@ require_relative 'locator/attributes'
3
3
  module TestaAppiumDriver
4
4
  class Locator
5
5
  include TypeSelectors
6
+ attr_accessor :class_chain_selector
6
7
 
7
8
  def init(params, selectors, single)
8
9
  if is_scrollable_selector?(selectors, single)
@@ -19,6 +20,9 @@ module TestaAppiumDriver
19
20
  params[:scrollable_locator] = self.dup
20
21
  end
21
22
 
23
+ @class_chain_selector = hash_to_class_chain(selectors, single)
24
+
25
+
22
26
  @scrollable_locator = params[:scrollable_locator] if params[:scrollable_locator]
23
27
  end
24
28
 
@@ -29,7 +33,9 @@ module TestaAppiumDriver
29
33
  if @can_use_id_strategy
30
34
  ss.push({"#{FIND_STRATEGY_NAME}": @can_use_id_strategy})
31
35
  end
32
- ss.push({"#{FIND_STRATEGY_XPATH}": @xpath_selector})
36
+ ss.push({"#{FIND_STRATEGY_CLASS_CHAIN}": @class_chain_selector}) if @strategy.nil? || @strategy == FIND_STRATEGY_CLASS_CHAIN
37
+ ss.push({"#{FIND_STRATEGY_XPATH}": @xpath_selector}) if @strategy.nil? || @strategy == FIND_STRATEGY_XPATH
38
+ ss.push({"#{FIND_STRATEGY_IMAGE}": @image_selector}) if @strategy == FIND_STRATEGY_IMAGE
33
39
  ss
34
40
  end
35
41
 
@@ -43,13 +49,23 @@ module TestaAppiumDriver
43
49
 
44
50
  locator = self.dup
45
51
  add_xpath_child_selectors(locator, selectors, single)
52
+ if @strategy.nil? || @strategy == FIND_STRATEGY_CLASS_CHAIN
53
+ add_class_chain_child_selectors(locator, selectors, single)
54
+ end
55
+
46
56
  if is_scrollable_selector?(selectors, single)
47
57
  locator.scrollable_locator.scroll_orientation = :vertical
48
- locator.scrollable_locator = self.dup
58
+ locator.scrollable_locator = locator
49
59
  end
50
60
 
51
61
  locator.last_selector_adjacent = false
52
62
  locator
53
63
  end
64
+
65
+
66
+ def add_class_chain_child_selectors(locator, selectors, single)
67
+ locator.single = false unless single # switching from single result to multiple
68
+ locator.class_chain_selector += "/" + hash_to_class_chain(selectors, single)
69
+ end
54
70
  end
55
71
  end
@@ -5,10 +5,15 @@ module TestaAppiumDriver
5
5
  # @return [TestaAppiumDriver::Locator]
6
6
  def add_selector(*args, &block)
7
7
  # if class selector is executed from driver, create new locator instance
8
- if self.kind_of?(TestaAppiumDriver::Driver) || self.kind_of(Selenium::WebDriver::Element)
8
+ if self.kind_of?(TestaAppiumDriver::Driver) || self.instance_of?(Selenium::WebDriver::Element)
9
9
  args.last[:default_find_strategy] = @default_find_strategy
10
10
  args.last[:default_scroll_strategy] = @default_scroll_strategy
11
- Locator.new(self, self, *args)
11
+ if self.instance_of?(Selenium::WebDriver::Element)
12
+ driver = self.get_driver
13
+ else
14
+ driver = self
15
+ end
16
+ Locator.new(driver, self, *args)
12
17
  else
13
18
  # class selector is executed from locator, just add child selector criteria
14
19
  self.add_child_selector(*args)
@@ -111,19 +116,6 @@ module TestaAppiumDriver
111
116
  end
112
117
 
113
118
 
114
- # @param params [Hash]
115
- # @return [TestaAppiumDriver::Locator] first scrollable element
116
- def scrollable(params = {})
117
- scroll_view(params)
118
- end
119
-
120
- # @param params [Hash]
121
- # @return [TestaAppiumDriver::Locator] first scrollable element
122
- def scrollables(params = {})
123
- scroll_views(params)
124
- end
125
-
126
-
127
119
  # @return [TestaAppiumDriver::Locator]
128
120
  def scroll_view(params = {})
129
121
  params[:type] = "XCUIElementTypeScrollView"
@@ -163,5 +155,34 @@ module TestaAppiumDriver
163
155
  params[:single] = false
164
156
  add_selector(params)
165
157
  end
158
+
159
+
160
+
161
+ # @return [TestaAppiumDriver::Locator]
162
+ def text_field(params = {})
163
+ params[:type] = "XCUIElementTypeTextField"
164
+ add_selector(params)
165
+ end
166
+
167
+ # @return [TestaAppiumDriver::Locator]
168
+ def text_fields(params = {})
169
+ params[:type] = "XCUIElementTypeTextField"
170
+ params[:single] = false
171
+ add_selector(params)
172
+ end
173
+
174
+
175
+ # @return [TestaAppiumDriver::Locator]
176
+ def secure_text_field(params = {})
177
+ params[:type] = "XCUIElementTypeSecureTextField"
178
+ add_selector(params)
179
+ end
180
+
181
+ # @return [TestaAppiumDriver::Locator]
182
+ def secure_text_fields(params = {})
183
+ params[:type] = "XCUIElementTypeSecureTextField"
184
+ params[:single] = false
185
+ add_selector(params)
186
+ end
166
187
  end
167
188
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TestaAppiumDriver
4
- VERSION = "0.1.6"
4
+ VERSION = "0.1.10"
5
5
  end
@@ -11,12 +11,12 @@
11
11
  <orderEntry type="sourceFolder" forTests="false" />
12
12
  <orderEntry type="library" scope="PROVIDED" name="appium_lib_core (v4.7.0, ruby-2.6.5-p114) [gem]" level="application" />
13
13
  <orderEntry type="library" scope="PROVIDED" name="ast (v2.4.2, ruby-2.6.5-p114) [gem]" level="application" />
14
- <orderEntry type="library" scope="PROVIDED" name="bundler (v2.2.24, ruby-2.6.5-p114) [gem]" level="application" />
14
+ <orderEntry type="library" scope="PROVIDED" name="bundler (v2.1.4, ruby-2.6.5-p114) [gem]" level="application" />
15
15
  <orderEntry type="library" scope="PROVIDED" name="childprocess (v3.0.0, ruby-2.6.5-p114) [gem]" level="application" />
16
16
  <orderEntry type="library" scope="PROVIDED" name="diff-lcs (v1.4.4, ruby-2.6.5-p114) [gem]" level="application" />
17
17
  <orderEntry type="library" scope="PROVIDED" name="eventmachine (v1.2.7, ruby-2.6.5-p114) [gem]" level="application" />
18
18
  <orderEntry type="library" scope="PROVIDED" name="faye-websocket (v0.11.1, ruby-2.6.5-p114) [gem]" level="application" />
19
- <orderEntry type="library" scope="PROVIDED" name="json (v2.5.1, ruby-2.6.5-p114) [gem]" level="application" />
19
+ <orderEntry type="library" scope="PROVIDED" name="json (v2.1.0, ruby-2.6.5-p114) [gem]" level="application" />
20
20
  <orderEntry type="library" scope="PROVIDED" name="parallel (v1.20.1, ruby-2.6.5-p114) [gem]" level="application" />
21
21
  <orderEntry type="library" scope="PROVIDED" name="parser (v3.0.2.0, ruby-2.6.5-p114) [gem]" level="application" />
22
22
  <orderEntry type="library" scope="PROVIDED" name="rainbow (v3.0.0, ruby-2.6.5-p114) [gem]" level="application" />
@@ -28,8 +28,8 @@
28
28
  <orderEntry type="library" scope="PROVIDED" name="rspec-expectations (v3.10.1, ruby-2.6.5-p114) [gem]" level="application" />
29
29
  <orderEntry type="library" scope="PROVIDED" name="rspec-mocks (v3.10.2, ruby-2.6.5-p114) [gem]" level="application" />
30
30
  <orderEntry type="library" scope="PROVIDED" name="rspec-support (v3.10.2, ruby-2.6.5-p114) [gem]" level="application" />
31
- <orderEntry type="library" scope="PROVIDED" name="rubocop (v1.20.0, ruby-2.6.5-p114) [gem]" level="application" />
32
- <orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.11.0, ruby-2.6.5-p114) [gem]" level="application" />
31
+ <orderEntry type="library" scope="PROVIDED" name="rubocop (v1.19.0, ruby-2.6.5-p114) [gem]" level="application" />
32
+ <orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.10.0, ruby-2.6.5-p114) [gem]" level="application" />
33
33
  <orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.11.0, ruby-2.6.5-p114) [gem]" level="application" />
34
34
  <orderEntry type="library" scope="PROVIDED" name="rubyzip (v2.3.2, ruby-2.6.5-p114) [gem]" level="application" />
35
35
  <orderEntry type="library" scope="PROVIDED" name="selenium-webdriver (v3.142.7, ruby-2.6.5-p114) [gem]" level="application" />
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: testa_appium_driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - karlo.razumovic
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-09-03 00:00:00.000000000 Z
11
+ date: 2021-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: appium_lib_core
@@ -80,6 +80,7 @@ files:
80
80
  - ".idea/inspectionProfiles/Project_Default.xml"
81
81
  - ".idea/misc.xml"
82
82
  - ".idea/modules.xml"
83
+ - ".idea/runConfigurations.xml"
83
84
  - ".idea/runConfigurations/Android_Test.xml"
84
85
  - ".idea/sshConfigs.xml"
85
86
  - ".idea/vcs.xml"