testa_appium_driver 0.1.6 → 0.1.10

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 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"