appium_lib 2.1.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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