appium_lib 2.1.0 → 3.0.0

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.
@@ -30,6 +30,9 @@ module Appium
30
30
  26 => ['classNameMatches(String regex)', 'SELECTOR_CLASS_REGEX', 26],
31
31
  27 => ['descriptionMatches(String regex)', 'SELECTOR_DESCRIPTION_REGEX', 27],
32
32
  28 => ['packageNameMatches(String regex)', 'SELECTOR_PACKAGE_NAME_REGEX', 28],
33
+ 29 => ['resourceId(String id)', 'SELECTOR_RESOURCE_ID', 29],
34
+ 30 => ['checkable(boolean val)', 'SELECTOR_CHECKABLE', 30],
35
+ 31 => ['resourceIdMatches(String regex)', 'SELECTOR_RESOURCE_ID_REGEX', 31],
33
36
  # // start internal methods at 100
34
37
  100 => ['getStringAttribute("name")', 'GET_NAME', 100]
35
38
  }
@@ -7,12 +7,28 @@ module Appium
7
7
  private
8
8
 
9
9
  # @private
10
- def _button_visible_string opts={}
11
- index = opts.fetch :index, false
12
- if index
13
- %Q(//#{Button}[#{index}] | //#{ImageButton}[#{index}])
10
+ def _button_visible_selectors opts={}
11
+ button_index = opts.fetch :button_index, false
12
+ image_button_index = opts.fetch :image_button_index, false
13
+
14
+ # complex_find(...)
15
+ # 4 = className(String className)
16
+ # 9 = instance(final int instance)
17
+
18
+ if button_index && image_button_index
19
+ [
20
+ # className().instance()
21
+ [[4, Button], [9, button_index]],
22
+ # className().instance()
23
+ [[4, ImageButton], [9, image_button_index]]
24
+ ]
14
25
  else
15
- %Q(//#{Button} | //#{ImageButton})
26
+ [
27
+ # className()
28
+ [[4, Button]],
29
+ # className()
30
+ [[4, ImageButton]]
31
+ ]
16
32
  end
17
33
  end
18
34
 
@@ -20,14 +36,14 @@ module Appium
20
36
  def _button_exact_string value
21
37
  button = string_visible_exact Button, value
22
38
  image_button = string_visible_exact ImageButton, value
23
- "#{button} | #{image_button}"
39
+ button + image_button
24
40
  end
25
41
 
26
42
  # @private
27
43
  def _button_contains_string value
28
44
  button = string_visible_contains Button, value
29
45
  image_button = string_visible_contains ImageButton, value
30
- "#{button} | #{image_button}"
46
+ button + image_button
31
47
  end
32
48
 
33
49
  public
@@ -41,12 +57,12 @@ module Appium
41
57
  # Android needs to combine button and image button to match iOS.
42
58
  if value.is_a? Numeric
43
59
  index = value
44
- raise "#{index} is not a valid xpath index. Must be >= 1" if index <= 0
60
+ raise "#{index} is not a valid index. Must be >= 1" if index <= 0
45
61
 
46
- return xpath _button_visible_string index: index
62
+ return complex_find _button_visible_selectors index: index
47
63
  end
48
64
 
49
- xpath _button_contains_string value
65
+ complex_find _button_contains_string value
50
66
  end
51
67
 
52
68
  # Find all buttons containing value.
@@ -54,34 +70,41 @@ module Appium
54
70
  # @param value [String] the value to search for
55
71
  # @return [Array<Button>]
56
72
  def buttons value=false
57
- return xpaths _button_visible_string unless value
58
- xpaths _button_contains_string value
73
+ return complex_find mode: 'all', selectors: _button_visible_selectors unless value
74
+ complex_find mode: 'all', selectors: _button_contains_string(value)
59
75
  end
60
76
 
61
77
  # Find the first button.
62
78
  # @return [Button]
63
79
  def first_button
64
- xpath _button_visible_string
80
+ complex_find _button_visible_selectors button_index: 0, image_button_index: 0
65
81
  end
66
82
 
67
83
  # Find the last button.
68
84
  # @return [Button]
69
85
  def last_button
70
- xpath _button_visible_string index: 'last()'
86
+ # uiautomator index doesn't support last
87
+ # and it's 0 indexed
88
+ button_index = tags(Button).length
89
+ button_index -= 1 if button_index >= 0
90
+ image_button_index = tags(ImageButton).length
91
+ image_button_index -= 1 if image_button_index >= 0
92
+
93
+ complex_find _button_visible_selectors button_index: button_index, image_button_index: image_button_index
71
94
  end
72
95
 
73
96
  # Find the first button that exactly matches value.
74
97
  # @param value [String] the value to match exactly
75
98
  # @return [Button]
76
99
  def button_exact value
77
- xpath _button_exact_string value
100
+ complex_find _button_exact_string value
78
101
  end
79
102
 
80
103
  # Find all buttons that exactly match value.
81
104
  # @param value [String] the value to match exactly
82
105
  # @return [Array<Button>]
83
106
  def buttons_exact value
84
- xpaths _button_exact_string value
107
+ complex_find mode: 'all', selectors: _button_exact_string(value)
85
108
  end
86
109
  end # module Android
87
110
  end # module Appium
@@ -5,28 +5,28 @@ module Appium
5
5
  # @param value [String] the value to search for
6
6
  # @return [Element]
7
7
  def find value
8
- xpath_visible_contains '*', value
8
+ complex_find_contains '*', value
9
9
  end
10
10
 
11
11
  # Find all elements containing value
12
12
  # @param value [String] the value to search for
13
13
  # @return [Array<Element>]
14
14
  def finds value
15
- xpaths_visible_contains '*', value
15
+ complex_finds_contains '*', value
16
16
  end
17
17
 
18
18
  # Find the first element exactly matching value
19
19
  # @param value [String] the value to search for
20
20
  # @return [Element]
21
21
  def find_exact value
22
- xpath_visible_exact '*', value
22
+ complex_find_exact '*', value
23
23
  end
24
24
 
25
25
  # Find all elements exactly matching value
26
26
  # @param value [String] the value to search for
27
27
  # @return [Array<Element>]
28
28
  def finds_exact value
29
- xpaths_visible_exact '*', value
29
+ complex_finds_exact '*', value
30
30
  end
31
31
 
32
32
  # Scroll to the first element containing target text or description.
@@ -9,7 +9,7 @@ module Appium
9
9
  # @return [TextView]
10
10
  def text value
11
11
  return ele_index TextView, value if value.is_a? Numeric
12
- xpath_visible_contains TextView, value
12
+ complex_find_contains TextView, value
13
13
  end
14
14
 
15
15
  # Find all TextViews containing value.
@@ -18,7 +18,7 @@ module Appium
18
18
  # @return [Array<TextView>]
19
19
  def texts value=false
20
20
  return tags TextView unless value
21
- xpaths_visible_contains TextView, value
21
+ complex_finds_contains TextView, value
22
22
  end
23
23
 
24
24
  # Find the first TextView.
@@ -37,14 +37,14 @@ module Appium
37
37
  # @param value [String] the value to match exactly
38
38
  # @return [TextView]
39
39
  def text_exact value
40
- xpath_visible_exact TextView, value
40
+ complex_find_exact TextView, value
41
41
  end
42
42
 
43
43
  # Find all TextViews that exactly match value.
44
44
  # @param value [String] the value to match exactly
45
45
  # @return [Array<TextView>]
46
46
  def texts_exact value
47
- xpaths_visible_exact TextView, value
47
+ complex_finds_exact TextView, value
48
48
  end
49
49
  end # module Android
50
50
  end # module Appium
@@ -8,7 +8,7 @@ module Appium
8
8
  # @return [EditText]
9
9
  def textfield value
10
10
  return ele_index EditText, value if value.is_a? Numeric
11
- xpath_visible_contains EditText, value
11
+ complex_find_contains EditText, value
12
12
  end
13
13
 
14
14
  # Find all EditTexts containing value.
@@ -17,7 +17,7 @@ module Appium
17
17
  # @return [Array<EditText>]
18
18
  def textfields value=false
19
19
  return tags EditText unless value
20
- xpaths_visible_contains EditText, value
20
+ complex_finds_contains EditText, value
21
21
  end
22
22
 
23
23
  # Find the first EditText.
@@ -36,14 +36,14 @@ module Appium
36
36
  # @param value [String] the value to match exactly
37
37
  # @return [EditText]
38
38
  def textfield_exact value
39
- xpath_visible_exact EditText, value
39
+ complex_find_exact EditText, value
40
40
  end
41
41
 
42
42
  # Find all EditTexts that exactly match value.
43
43
  # @param value [String] the value to match exactly
44
44
  # @return [Array<EditText>]
45
45
  def textfields_exact value
46
- xpaths_visible_exact EditText, value
46
+ complex_finds_exact EditText, value
47
47
  end
48
48
  end # module Android
49
49
  end # module Appium
@@ -130,29 +130,20 @@ module Appium
130
130
  am_start: pkg + '/' + act)
131
131
  end
132
132
 
133
- # @private
134
- def string_id_xpath id
135
- value = resolve_id id
136
- # If the id doesn't resolve in strings.xml then use it as is
137
- # It's probably a resource id which won't be in strings.xml
138
- value = id unless value
139
- exact = string_visible_exact '*', value
140
- contains = string_visible_contains '*', value
141
- "#{exact} | #{contains}"
142
- end
143
-
144
133
  # Find the first matching element by id
145
134
  # @param id [String] the id to search for
146
135
  # @return [Element]
147
136
  def id id
148
- xpath string_id_xpath id
137
+ # Android auto resolves strings.xml ids
138
+ find_element :id, id
149
139
  end
150
140
 
151
141
  # Find all matching elements by id
152
142
  # @param id [String] the id to search for
153
143
  # @return [Element]
154
144
  def ids id
155
- xpaths string_id_xpath id
145
+ # Android auto resolves strings.xml ids
146
+ find_elements :id, value
156
147
  end
157
148
 
158
149
  # Find the element of type class_name at matching index.
@@ -160,65 +151,21 @@ module Appium
160
151
  # @param index [Integer] the index
161
152
  # @return [Element] the found element of type class_name
162
153
  def ele_index class_name, index
163
- unless index == 'last()'
164
- # XPath index starts at 1.
165
- raise "#{index} is not a valid xpath index. Must be >= 1" if index <= 0
154
+ if index == 'last()'
155
+ index = tags(class_name).length
156
+ index -= 1 if index >= 0
157
+ else
158
+ raise 'Index must be >= 1' unless index >= 1
159
+ index -= 1 if index >= 1
166
160
  end
167
- find_element :xpath, %Q(//#{class_name}[#{index}])
168
- end
169
-
170
- # @private
171
- def string_attr_exact class_name, attr, value
172
- %Q(//#{class_name}[@#{attr}='#{value}'])
173
- end
174
-
175
- # Find the first element exactly matching class and attribute value.
176
- # @param class_name [String] the class name to search for
177
- # @param attr [String] the attribute to inspect
178
- # @param value [String] the expected value of the attribute
179
- # @return [Element]
180
- def find_ele_by_attr class_name, attr, value
181
- @driver.find_element :xpath, string_attr_exact(class_name, attr, value)
182
- end
183
-
184
- # Find all elements exactly matching class and attribute value.
185
- # @param class_name [String] the class name to match
186
- # @param attr [String] the attribute to compare
187
- # @param value [String] the value of the attribute that the element must have
188
- # @return [Array<Element>]
189
- def find_eles_by_attr class_name, attr, value
190
- @driver.find_elements :xpath, string_attr_exact(class_name, attr, value)
191
- end
192
-
193
- # @private
194
- def string_attr_include class_name, attr, value
195
- %Q(//#{class_name}[contains(translate(@#{attr},'#{value.upcase}', '#{value}'), '#{value}')])
196
- end
197
-
198
- # Find the first element by attribute that exactly matches value.
199
- # @param class_name [String] the class name to match
200
- # @param attr [String] the attribute to compare
201
- # @param value [String] the value of the attribute that the element must include
202
- # @return [Element] the element of type tag who's attribute includes value
203
- def find_ele_by_attr_include class_name, attr, value
204
- @driver.find_element :xpath, string_attr_include(class_name, attr, value)
205
- end
206
-
207
- # Find elements by attribute that include value.
208
- # @param class_name [String] the tag name to match
209
- # @param attr [String] the attribute to compare
210
- # @param value [String] the value of the attribute that the element must include
211
- # @return [Array<Element>] the elements of type tag who's attribute includes value
212
- def find_eles_by_attr_include class_name, attr, value
213
- @driver.find_elements :xpath, string_attr_include(class_name, attr, value)
161
+ complex_find [[[4, class_name], [9, index]]]
214
162
  end
215
163
 
216
164
  # Find the first element that matches class_name
217
165
  # @param class_name [String] the tag to match
218
166
  # @return [Element]
219
167
  def first_ele class_name
220
- # XPath index starts at 1
221
- ele_index class_name, 1
168
+ tag(class_name)
222
169
  end
223
170
 
224
171
  # Find the last element that matches class_name
@@ -233,7 +180,7 @@ module Appium
233
180
  # @param class_name [String] the class_name to search for
234
181
  # @return [Element]
235
182
  def tag class_name
236
- xpath %Q(//#{class_name})
183
+ find_element :class, class_name
237
184
  end
238
185
 
239
186
  # Find all elements of type class_name
@@ -241,84 +188,108 @@ module Appium
241
188
  # @param class_name [String] the class_name to search for
242
189
  # @return [Element]
243
190
  def tags class_name
244
- xpaths %Q(//#{class_name})
191
+ find_elements :class, class_name
245
192
  end
246
193
 
247
194
  # @private
248
- # Returns a string xpath that matches the first element that contains value
195
+ # Returns a string that matches the first element that contains value
249
196
  #
250
- # example: xpath_visible_contains 'UIATextField', 'sign in'
197
+ # example: complex_find_contains 'UIATextField', 'sign in'
251
198
  #
252
- # @param element [String] the class name for the element
199
+ # @param class_name [String] the class name for the element
253
200
  # @param value [String] the value to search for
254
201
  # @return [String]
255
- def string_visible_contains element, value
256
- result = []
257
- attributes = %w[content-desc text]
258
-
259
- value_up = value.upcase
260
- value_down = value.downcase
261
-
262
- attributes.each do |attribute|
263
- result << %Q(contains(translate(@#{attribute},"#{value_up}","#{value_down}"), "#{value_down}"))
202
+ def string_visible_contains class_name, value
203
+ # 4 = className(String className)
204
+ # 29 = resourceId(String id
205
+ # 7 = descriptionContains(String desc)
206
+ # 3 = textContains(String text)
207
+ # todo: textContains isn't case insensitive
208
+ # descriptionContains is case insensitive
209
+
210
+ if class_name == '*'
211
+ return [
212
+ # resourceId()
213
+ [[29, value]],
214
+ # descriptionContains()
215
+ [[7, value]],
216
+ # textContains()
217
+ [[3, value]]
218
+ ]
264
219
  end
265
220
 
266
- # never partial match on a resource id
267
- result << %Q(@resource-id="#{value}")
268
-
269
- result = result.join(' or ')
270
-
271
- "//#{element}[#{result}]"
221
+ [
222
+ # className().resourceId()
223
+ [[4, class_name], [29, value]],
224
+ # className().descriptionContains()
225
+ [[4, class_name], [7, value]],
226
+ # className().textContains()
227
+ [[4, class_name], [3, value]]
228
+ ]
272
229
  end
273
230
 
274
231
  # Find the first element that contains value
275
232
  # @param element [String] the class name for the element
276
233
  # @param value [String] the value to search for
277
234
  # @return [Element]
278
- def xpath_visible_contains element, value
279
- xpath string_visible_contains element, value
235
+ def complex_find_contains element, value
236
+ complex_find string_visible_contains element, value
280
237
  end
281
238
 
282
239
  # Find all elements containing value
283
240
  # @param element [String] the class name for the element
284
241
  # @param value [String] the value to search for
285
242
  # @return [Array<Element>]
286
- def xpaths_visible_contains element, value
287
- xpaths string_visible_contains element, value
243
+ def complex_finds_contains element, value
244
+ complex_find mode: 'all', selectors: string_visible_contains(element, value)
288
245
  end
289
246
 
290
247
  # @private
291
- # Create an xpath string to exactly match the first element with target value
292
- # @param element [String] the class name for the element
248
+ # Create an string to exactly match the first element with target value
249
+ # @param class_name [String] the class name for the element
293
250
  # @param value [String] the value to search for
294
251
  # @return [String]
295
- def string_visible_exact element, value
296
- result = []
297
- attributes = %w[content-desc resource-id text]
298
-
299
- attributes.each do |attribute|
300
- result << %Q(@#{attribute}="#{value}")
252
+ def string_visible_exact class_name, value
253
+ # 4 = className(String className)
254
+ # 29 = resourceId(String id
255
+ # 5 = description(String desc)
256
+ # 1 = text(String text)
257
+
258
+ if class_name == '*'
259
+ return [
260
+ # resourceId()
261
+ [[29, value]],
262
+ # description()
263
+ [[5, value]],
264
+ # text()
265
+ [[1, value]]
266
+ ]
301
267
  end
302
268
 
303
- result = result.join(' or ')
304
-
305
- "//#{element}[#{result}]"
269
+ [
270
+ # className().resourceId()
271
+ [[4, class_name], [29, value]],
272
+ # className().description()
273
+ [[4, class_name], [5, value]],
274
+ # className().text()
275
+ [[4, class_name], [1, value]]
276
+ ]
306
277
  end
307
278
 
308
279
  # Find the first element exactly matching value
309
- # @param element [String] the class name for the element
280
+ # @param class_name [String] the class name for the element
310
281
  # @param value [String] the value to search for
311
282
  # @return [Element]
312
- def xpath_visible_exact element, value
313
- xpath string_visible_exact element, value
283
+ def complex_find_exact class_name, value
284
+ complex_find string_visible_exact class_name, value
314
285
  end
315
286
 
316
287
  # Find all elements exactly matching value
317
- # @param element [String] the class name for the element
288
+ # @param class_name [String] the class name for the element
318
289
  # @param value [String] the value to search for
319
290
  # @return [Element]
320
- def xpaths_visible_exact element, value
321
- xpaths string_visible_exact element, value
291
+ def complex_finds_exact class_name, value
292
+ complex_find mode: 'all', selectors: string_visible_exact(class_name, value)
322
293
  end
323
294
  end # module Android
324
295
  end # module Appium