appium_lib 6.0.0 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +28 -0
- data/.travis.yml +10 -0
- data/Rakefile +9 -1
- data/android_tests/Gemfile +1 -1
- data/android_tests/Rakefile +20 -13
- data/android_tests/lib/android/specs/android/element/alert.rb +1 -1
- data/android_tests/lib/android/specs/android/element/button.rb +2 -2
- data/android_tests/lib/android/specs/android/element/generic.rb +1 -2
- data/android_tests/lib/android/specs/android/element/text.rb +2 -3
- data/android_tests/lib/android/specs/android/element/textfield.rb +2 -2
- data/android_tests/lib/android/specs/android/helper.rb +5 -3
- data/android_tests/lib/android/specs/android/patch.rb +2 -2
- data/android_tests/lib/android/specs/common/device.rb +16 -9
- data/android_tests/lib/android/specs/common/device_touchaction.rb +5 -2
- data/android_tests/lib/android/specs/common/element/window.rb +1 -1
- data/android_tests/lib/android/specs/common/helper.rb +14 -15
- data/android_tests/lib/android/specs/common/patch.rb +11 -9
- data/android_tests/lib/android/specs/common/version.rb +3 -3
- data/android_tests/lib/android/specs/common/web_context.rb +2 -3
- data/android_tests/lib/android/specs/driver.rb +38 -29
- data/android_tests/lib/android/specs/install.rb +3 -3
- data/android_tests/lib/format.rb +6 -8
- data/android_tests/lib/run.rb +25 -17
- data/android_tests/readme.md +4 -2
- data/appium_lib.gemspec +13 -11
- data/contributing.md +1 -1
- data/docs/android_docs.md +358 -274
- data/docs/ios_docs.md +333 -270
- data/docs/migration.md +10 -0
- data/docs_gen/make_docs.rb +3 -1
- data/ios_tests/Gemfile +1 -1
- data/ios_tests/Rakefile +17 -10
- data/ios_tests/appium.txt +1 -1
- data/ios_tests/lib/common.rb +8 -4
- data/ios_tests/lib/format.rb +5 -7
- data/ios_tests/lib/ios/specs/common/element/window.rb +1 -1
- data/ios_tests/lib/ios/specs/common/helper.rb +40 -39
- data/ios_tests/lib/ios/specs/common/patch.rb +15 -11
- data/ios_tests/lib/ios/specs/common/version.rb +3 -3
- data/ios_tests/lib/ios/specs/common/web_context.rb +1 -2
- data/ios_tests/lib/ios/specs/device/device.rb +7 -7
- data/ios_tests/lib/ios/specs/device/multi_touch.rb +6 -8
- data/ios_tests/lib/ios/specs/device/touch_actions.rb +12 -12
- data/ios_tests/lib/ios/specs/driver.rb +23 -22
- data/ios_tests/lib/ios/specs/ios/element/alert.rb +6 -2
- data/ios_tests/lib/ios/specs/ios/element/button.rb +2 -2
- data/ios_tests/lib/ios/specs/ios/element/generic.rb +1 -1
- data/ios_tests/lib/ios/specs/ios/element/text.rb +4 -1
- data/ios_tests/lib/ios/specs/ios/element/textfield.rb +6 -6
- data/ios_tests/lib/ios/specs/ios/helper.rb +5 -5
- data/ios_tests/lib/ios/specs/ios/patch.rb +2 -2
- data/ios_tests/lib/run.rb +1 -1
- data/ios_tests/readme.md +3 -3
- data/ios_tests/upload/sauce_storage.rb +8 -8
- data/ios_tests/upload/upload.rb +1 -1
- data/lib/appium_lib/android/client_xpath.rb +7 -7
- data/lib/appium_lib/android/element/alert.rb +2 -2
- data/lib/appium_lib/android/element/button.rb +16 -16
- data/lib/appium_lib/android/element/generic.rb +12 -13
- data/lib/appium_lib/android/element/text.rb +5 -5
- data/lib/appium_lib/android/element/textfield.rb +5 -5
- data/lib/appium_lib/android/helper.rb +82 -52
- data/lib/appium_lib/android/mobile_methods.rb +2 -2
- data/lib/appium_lib/android/patch.rb +3 -3
- data/lib/appium_lib/common/element/window.rb +1 -1
- data/lib/appium_lib/common/helper.rb +30 -35
- data/lib/appium_lib/common/patch.rb +22 -20
- data/lib/appium_lib/common/version.rb +3 -3
- data/lib/appium_lib/common/wait.rb +9 -10
- data/lib/appium_lib/device/device.rb +39 -33
- data/lib/appium_lib/device/multi_touch.rb +5 -7
- data/lib/appium_lib/device/touch_actions.rb +14 -15
- data/lib/appium_lib/driver.rb +97 -76
- data/lib/appium_lib/ios/element/alert.rb +1 -1
- data/lib/appium_lib/ios/element/button.rb +5 -5
- data/lib/appium_lib/ios/element/generic.rb +5 -6
- data/lib/appium_lib/ios/element/text.rb +5 -5
- data/lib/appium_lib/ios/element/textfield.rb +15 -15
- data/lib/appium_lib/ios/helper.rb +103 -90
- data/lib/appium_lib/ios/mobile_methods.rb +2 -2
- data/lib/appium_lib/ios/patch.rb +4 -4
- data/lib/appium_lib/logger.rb +7 -5
- data/lib/appium_lib/rails/duplicable.rb +3 -1
- data/readme.md +7 -1
- data/release_notes.md +152 -0
- metadata +28 -54
@@ -7,7 +7,7 @@ module Appium
|
|
7
7
|
# @param value [String, Integer] the value to exactly match.
|
8
8
|
# If int then the UIAButton at that index is returned.
|
9
9
|
# @return [UIAButton]
|
10
|
-
def button
|
10
|
+
def button(value)
|
11
11
|
# return button at index.
|
12
12
|
return ele_index UIAButton, value if value.is_a? Numeric
|
13
13
|
ele_by_json_visible_contains UIAButton, value
|
@@ -17,7 +17,7 @@ module Appium
|
|
17
17
|
# If value is omitted, all UIAButtons are returned.
|
18
18
|
# @param value [String] the value to search for
|
19
19
|
# @return [Array<UIAButton>]
|
20
|
-
def buttons
|
20
|
+
def buttons(value = false)
|
21
21
|
return tags UIAButton unless value
|
22
22
|
eles_by_json_visible_contains UIAButton, value
|
23
23
|
end
|
@@ -37,15 +37,15 @@ module Appium
|
|
37
37
|
# Find the first UIAButton that exactly matches value.
|
38
38
|
# @param value [String] the value to match exactly
|
39
39
|
# @return [UIAButton]
|
40
|
-
def button_exact
|
40
|
+
def button_exact(value)
|
41
41
|
ele_by_json_visible_exact UIAButton, value
|
42
42
|
end
|
43
43
|
|
44
44
|
# Find all UIAButtons that exactly match value.
|
45
45
|
# @param value [String] the value to match exactly
|
46
46
|
# @return [Array<UIAButton>]
|
47
|
-
def buttons_exact
|
47
|
+
def buttons_exact(value)
|
48
48
|
eles_by_json_visible_exact UIAButton, value
|
49
49
|
end
|
50
50
|
end # module Ios
|
51
|
-
end # module Appium
|
51
|
+
end # module Appium
|
@@ -1,32 +1,31 @@
|
|
1
1
|
module Appium
|
2
2
|
module Ios
|
3
|
-
|
4
3
|
# Find the first element containing value
|
5
4
|
# @param value [String] the value to search for
|
6
5
|
# @return [Element]
|
7
|
-
def find
|
6
|
+
def find(value)
|
8
7
|
ele_by_json_visible_contains '*', value
|
9
8
|
end
|
10
9
|
|
11
10
|
# Find all elements containing value
|
12
11
|
# @param value [String] the value to search for
|
13
12
|
# @return [Array<Element>]
|
14
|
-
def finds
|
13
|
+
def finds(value)
|
15
14
|
eles_by_json_visible_contains '*', value
|
16
15
|
end
|
17
16
|
|
18
17
|
# Find the first element exactly matching value
|
19
18
|
# @param value [String] the value to search for
|
20
19
|
# @return [Element]
|
21
|
-
def find_exact
|
20
|
+
def find_exact(value)
|
22
21
|
ele_by_json_visible_exact '*', value
|
23
22
|
end
|
24
23
|
|
25
24
|
# Find all elements exactly matching value
|
26
25
|
# @param value [String] the value to search for
|
27
26
|
# @return [Array<Element>]
|
28
|
-
def finds_exact
|
27
|
+
def finds_exact(value)
|
29
28
|
eles_by_json_visible_exact '*', value
|
30
29
|
end
|
31
30
|
end # module Ios
|
32
|
-
end # module Appium
|
31
|
+
end # module Appium
|
@@ -7,7 +7,7 @@ module Appium
|
|
7
7
|
# @param value [String, Integer] the value to find.
|
8
8
|
# If int then the UIAStaticText at that index is returned.
|
9
9
|
# @return [UIAStaticText]
|
10
|
-
def text
|
10
|
+
def text(value)
|
11
11
|
return ele_index UIAStaticText, value if value.is_a? Numeric
|
12
12
|
ele_by_json_visible_contains UIAStaticText, value
|
13
13
|
end
|
@@ -16,7 +16,7 @@ module Appium
|
|
16
16
|
# If value is omitted, all UIAStaticTexts are returned
|
17
17
|
# @param value [String] the value to search for
|
18
18
|
# @return [Array<UIAStaticText>]
|
19
|
-
def texts
|
19
|
+
def texts(value = false)
|
20
20
|
return tags UIAStaticText unless value
|
21
21
|
eles_by_json_visible_contains UIAStaticText, value
|
22
22
|
end
|
@@ -36,15 +36,15 @@ module Appium
|
|
36
36
|
# Find the first UIAStaticText that exactly matches value.
|
37
37
|
# @param value [String] the value to match exactly
|
38
38
|
# @return [UIAStaticText]
|
39
|
-
def text_exact
|
39
|
+
def text_exact(value)
|
40
40
|
ele_by_json_visible_exact UIAStaticText, value
|
41
41
|
end
|
42
42
|
|
43
43
|
# Find all UIAStaticTexts that exactly match value.
|
44
44
|
# @param value [String] the value to match exactly
|
45
45
|
# @return [Array<UIAStaticText>]
|
46
|
-
def texts_exact
|
46
|
+
def texts_exact(value)
|
47
47
|
eles_by_json_visible_exact UIAStaticText, value
|
48
48
|
end
|
49
49
|
end # module Ios
|
50
|
-
end # module Appium
|
50
|
+
end # module Appium
|
@@ -9,36 +9,36 @@ module Appium
|
|
9
9
|
def _textfield_visible
|
10
10
|
{
|
11
11
|
typeArray: [UIATextField, UIASecureTextField],
|
12
|
-
onlyVisible: true
|
12
|
+
onlyVisible: true
|
13
13
|
}
|
14
14
|
end
|
15
15
|
|
16
16
|
# @private
|
17
|
-
def _textfield_exact_string
|
17
|
+
def _textfield_exact_string(value)
|
18
18
|
exact = {
|
19
19
|
target: value,
|
20
20
|
substring: false,
|
21
|
-
insensitive: false
|
21
|
+
insensitive: false
|
22
22
|
}
|
23
23
|
exact_obj = {
|
24
24
|
name: exact,
|
25
25
|
label: exact,
|
26
|
-
value: exact
|
26
|
+
value: exact
|
27
27
|
}
|
28
28
|
_textfield_visible.merge(exact_obj)
|
29
29
|
end
|
30
30
|
|
31
31
|
# @private
|
32
|
-
def _textfield_contains_string
|
32
|
+
def _textfield_contains_string(value)
|
33
33
|
contains = {
|
34
34
|
target: value,
|
35
35
|
substring: true,
|
36
|
-
insensitive: true
|
36
|
+
insensitive: true
|
37
37
|
}
|
38
38
|
contains_obj = {
|
39
39
|
name: contains,
|
40
40
|
label: contains,
|
41
|
-
value: contains
|
41
|
+
value: contains
|
42
42
|
}
|
43
43
|
_textfield_visible.merge(contains_obj)
|
44
44
|
end
|
@@ -49,16 +49,16 @@ module Appium
|
|
49
49
|
# @param value [String, Integer] the text to match exactly.
|
50
50
|
# If int then the TextField at that index is returned.
|
51
51
|
# @return [TextField]
|
52
|
-
def textfield
|
52
|
+
def textfield(value)
|
53
53
|
# Don't use ele_index because that only works on one element type.
|
54
54
|
# iOS needs to combine textfield and secure to match Android.
|
55
55
|
if value.is_a? Numeric
|
56
56
|
index = value
|
57
|
-
|
57
|
+
fail "#{index} is not a valid index. Must be >= 1" if index <= 0
|
58
58
|
index -= 1 # eles_by_json is 0 indexed.
|
59
59
|
|
60
60
|
result = eles_by_json(_textfield_visible)[index]
|
61
|
-
|
61
|
+
fail _no_such_element if result.nil?
|
62
62
|
return result
|
63
63
|
end
|
64
64
|
|
@@ -69,7 +69,7 @@ module Appium
|
|
69
69
|
# If value is omitted, all TextFields are returned.
|
70
70
|
# @param value [String] the value to search for
|
71
71
|
# @return [Array<TextField>]
|
72
|
-
def textfields
|
72
|
+
def textfields(value = false)
|
73
73
|
return eles_by_json _textfield_visible unless value
|
74
74
|
eles_by_json _textfield_contains_string value
|
75
75
|
end
|
@@ -84,22 +84,22 @@ module Appium
|
|
84
84
|
# @return [TextField]
|
85
85
|
def last_textfield
|
86
86
|
result = eles_by_json(_textfield_visible).last
|
87
|
-
|
87
|
+
fail _no_such_element if result.nil?
|
88
88
|
result
|
89
89
|
end
|
90
90
|
|
91
91
|
# Find the first TextField that exactly matches value.
|
92
92
|
# @param value [String] the value to match exactly
|
93
93
|
# @return [TextField]
|
94
|
-
def textfield_exact
|
94
|
+
def textfield_exact(value)
|
95
95
|
ele_by_json _textfield_exact_string value
|
96
96
|
end
|
97
97
|
|
98
98
|
# Find all TextFields that exactly match value.
|
99
99
|
# @param value [String] the value to match exactly
|
100
100
|
# @return [Array<TextField>]
|
101
|
-
def textfields_exact
|
101
|
+
def textfields_exact(value)
|
102
102
|
eles_by_json _textfield_exact_string value
|
103
103
|
end
|
104
104
|
end # module Ios
|
105
|
-
end # module Appium
|
105
|
+
end # module Appium
|
@@ -5,7 +5,7 @@ module Appium
|
|
5
5
|
# Password character returned from value of UIASecureTextField
|
6
6
|
# @param length [Integer] the length of the password to generate
|
7
7
|
# @return [String] the returned string is of size length
|
8
|
-
def ios_password
|
8
|
+
def ios_password(length = 1)
|
9
9
|
8226.chr('UTF-8') * length
|
10
10
|
end
|
11
11
|
|
@@ -17,17 +17,17 @@ module Appium
|
|
17
17
|
# @option element [Object] the element to search. omit to search everything
|
18
18
|
# @option class_name [String,Symbol] the class name to filter on. case insensitive include match.
|
19
19
|
# @return [String]
|
20
|
-
def get_page
|
20
|
+
def get_page(element = source_window(0), class_name = nil)
|
21
21
|
lazy_load_strings # populate @strings_xml
|
22
22
|
class_name = class_name.to_s.downcase
|
23
23
|
|
24
24
|
# @private
|
25
|
-
def empty
|
26
|
-
(ele['name'] || ele['label'] || ele['value'])
|
25
|
+
def empty(ele)
|
26
|
+
(ele['name'] || ele['label'] || ele['value']).nil?
|
27
27
|
end
|
28
28
|
|
29
29
|
# @private
|
30
|
-
def fix_space
|
30
|
+
def fix_space(s)
|
31
31
|
# if s is an int, we can't call .empty
|
32
32
|
return nil if s.nil? || (s.respond_to?(:empty) && s.empty?)
|
33
33
|
# ints don't respond to force encoding
|
@@ -51,6 +51,9 @@ module Appium
|
|
51
51
|
visible = fix_space element['visible']
|
52
52
|
type = fix_space element['type']
|
53
53
|
|
54
|
+
# TODO: Rubocop warning cleanup
|
55
|
+
# rubocop:disable Metrics/BlockNesting
|
56
|
+
|
54
57
|
# if class_name is set, mark non-matches as invisible
|
55
58
|
visible = (type.downcase.include?(class_name)).to_s if class_name
|
56
59
|
if visible && visible == 'true'
|
@@ -75,6 +78,7 @@ module Appium
|
|
75
78
|
puts " value: #{value}" if value
|
76
79
|
puts " hint: #{hint}" if hint
|
77
80
|
end
|
81
|
+
# rubocop:enable Metrics/BlockNesting
|
78
82
|
|
79
83
|
# there may be many ids with the same value.
|
80
84
|
# output all exact matches.
|
@@ -93,10 +97,10 @@ module Appium
|
|
93
97
|
match_str = ''
|
94
98
|
max_len = id_matches.keys.max_by(&:length).length
|
95
99
|
|
96
|
-
# [0] = key, [1] =
|
97
|
-
id_matches.each do |key,
|
100
|
+
# [0] = key, [1] = val
|
101
|
+
id_matches.each do |key, val|
|
98
102
|
arrow_space = ' ' * (max_len - key.length).to_i
|
99
|
-
match_str
|
103
|
+
match_str += ' ' * 7 + "#{key} #{arrow_space}=> #{val}\n"
|
100
104
|
end
|
101
105
|
puts " id: #{match_str.strip}\n"
|
102
106
|
end
|
@@ -122,7 +126,7 @@ module Appium
|
|
122
126
|
# @option class [Symbol] class name to filter on
|
123
127
|
#
|
124
128
|
# @return [void]
|
125
|
-
def page
|
129
|
+
def page(opts = {})
|
126
130
|
if opts.is_a?(Hash)
|
127
131
|
window_number = opts.fetch :window, -1
|
128
132
|
class_name = opts.fetch :class, nil
|
@@ -154,7 +158,7 @@ module Appium
|
|
154
158
|
# Gets the JSON source of window number
|
155
159
|
# @param window_number [Integer] the int index of the target window
|
156
160
|
# @return [JSON]
|
157
|
-
def source_window
|
161
|
+
def source_window(window_number = 0)
|
158
162
|
# appium 1.0 still returns JSON when getTree() is invoked so this
|
159
163
|
# doesn't need to change to XML. If getTree() is removed then
|
160
164
|
# source_window will need to parse the elements of getTreeForXML()\
|
@@ -168,7 +172,7 @@ module Appium
|
|
168
172
|
#
|
169
173
|
# @param window_number [Integer] the int index of the target window
|
170
174
|
# @return [void]
|
171
|
-
def page_window
|
175
|
+
def page_window(window_number = 0)
|
172
176
|
get_page source_window window_number
|
173
177
|
nil
|
174
178
|
end
|
@@ -176,7 +180,7 @@ module Appium
|
|
176
180
|
# Find by id
|
177
181
|
# @param id [String] the id to search for
|
178
182
|
# @return [Element]
|
179
|
-
def id
|
183
|
+
def id(id)
|
180
184
|
find_element :id, id
|
181
185
|
end
|
182
186
|
|
@@ -184,32 +188,32 @@ module Appium
|
|
184
188
|
# @return [Array<Integer>]
|
185
189
|
def ios_version
|
186
190
|
ios_version = execute_script 'UIATarget.localTarget().systemVersion()'
|
187
|
-
ios_version.split('.').map
|
191
|
+
ios_version.split('.').map(&:to_i)
|
188
192
|
end
|
189
193
|
|
190
194
|
# Get the element of type class_name at matching index.
|
191
195
|
# @param class_name [String] the class name to find
|
192
196
|
# @param index [Integer] the index
|
193
197
|
# @return [Element]
|
194
|
-
def ele_index
|
195
|
-
|
198
|
+
def ele_index(class_name, index)
|
199
|
+
fail 'Index must be >= 1' unless index == 'last()' || (index.is_a?(Integer) && index >= 1)
|
196
200
|
elements = tags(class_name)
|
197
201
|
|
198
202
|
if index == 'last()'
|
199
203
|
result = elements.last
|
200
204
|
else
|
201
205
|
# elements array is 0 indexed
|
202
|
-
index
|
206
|
+
index -= 1
|
203
207
|
result = elements[index]
|
204
208
|
end
|
205
209
|
|
206
|
-
|
210
|
+
fail _no_such_element if result.nil?
|
207
211
|
result
|
208
212
|
end
|
209
213
|
|
210
214
|
# @private
|
211
|
-
def string_attr_exact
|
212
|
-
%
|
215
|
+
def string_attr_exact(class_name, attr, value)
|
216
|
+
%(//#{class_name}[@visible="true" and @#{attr}='#{value}'])
|
213
217
|
end
|
214
218
|
|
215
219
|
# Find the first element exactly matching class and attribute value.
|
@@ -218,7 +222,7 @@ module Appium
|
|
218
222
|
# @param attr [String] the attribute to inspect
|
219
223
|
# @param value [String] the expected value of the attribute
|
220
224
|
# @return [Element]
|
221
|
-
def find_ele_by_attr
|
225
|
+
def find_ele_by_attr(class_name, attr, value)
|
222
226
|
@driver.find_element :xpath, string_attr_exact(class_name, attr, value)
|
223
227
|
end
|
224
228
|
|
@@ -228,13 +232,13 @@ module Appium
|
|
228
232
|
# @param attr [String] the attribute to compare
|
229
233
|
# @param value [String] the value of the attribute that the element must have
|
230
234
|
# @return [Array<Element>]
|
231
|
-
def find_eles_by_attr
|
235
|
+
def find_eles_by_attr(class_name, attr, value)
|
232
236
|
@driver.find_elements :xpath, string_attr_exact(class_name, attr, value)
|
233
237
|
end
|
234
238
|
|
235
239
|
# @private
|
236
|
-
def string_attr_include
|
237
|
-
%
|
240
|
+
def string_attr_include(class_name, attr, value)
|
241
|
+
%(//#{class_name}[@visible="true" and contains(translate(@#{attr},'#{value.upcase}', '#{value}'), '#{value}')])
|
238
242
|
end
|
239
243
|
|
240
244
|
# Get the first tag by attribute that exactly matches value.
|
@@ -243,7 +247,7 @@ module Appium
|
|
243
247
|
# @param attr [String] the attribute to compare
|
244
248
|
# @param value [String] the value of the attribute that the element must include
|
245
249
|
# @return [Element] the element of type tag who's attribute includes value
|
246
|
-
def find_ele_by_attr_include
|
250
|
+
def find_ele_by_attr_include(class_name, attr, value)
|
247
251
|
@driver.find_element :xpath, string_attr_include(class_name, attr, value)
|
248
252
|
end
|
249
253
|
|
@@ -253,14 +257,14 @@ module Appium
|
|
253
257
|
# @param attr [String] the attribute to compare
|
254
258
|
# @param value [String] the value of the attribute that the element must include
|
255
259
|
# @return [Array<Element>] the elements of type tag who's attribute includes value
|
256
|
-
def find_eles_by_attr_include
|
260
|
+
def find_eles_by_attr_include(class_name, attr, value)
|
257
261
|
@driver.find_elements :xpath, string_attr_include(class_name, attr, value)
|
258
262
|
end
|
259
263
|
|
260
264
|
# Get the first tag that matches class_name
|
261
265
|
# @param class_name [String] the tag to match
|
262
266
|
# @return [Element]
|
263
|
-
def first_ele
|
267
|
+
def first_ele(class_name)
|
264
268
|
# XPath index starts at 1
|
265
269
|
ele_index class_name, 1
|
266
270
|
end
|
@@ -268,7 +272,7 @@ module Appium
|
|
268
272
|
# Get the last tag that matches class_name
|
269
273
|
# @param class_name [String] the tag to match
|
270
274
|
# @return [Element]
|
271
|
-
def last_ele
|
275
|
+
def last_ele(class_name)
|
272
276
|
ele_index class_name, 'last()'
|
273
277
|
end
|
274
278
|
|
@@ -276,22 +280,22 @@ module Appium
|
|
276
280
|
#
|
277
281
|
# @param class_name [String] the class_name to search for
|
278
282
|
# @return [Element]
|
279
|
-
def tag
|
280
|
-
ele_by_json(
|
281
|
-
|
282
|
-
|
283
|
-
|
283
|
+
def tag(class_name)
|
284
|
+
ele_by_json(
|
285
|
+
typeArray: [class_name],
|
286
|
+
onlyVisible: true
|
287
|
+
)
|
284
288
|
end
|
285
289
|
|
286
290
|
# Returns all visible elements matching class_name
|
287
291
|
#
|
288
292
|
# @param class_name [String] the class_name to search for
|
289
293
|
# @return [Element]
|
290
|
-
def tags
|
291
|
-
eles_by_json(
|
292
|
-
|
293
|
-
|
294
|
-
|
294
|
+
def tags(class_name)
|
295
|
+
eles_by_json(
|
296
|
+
typeArray: [class_name],
|
297
|
+
onlyVisible: true
|
298
|
+
)
|
295
299
|
end
|
296
300
|
|
297
301
|
# @private
|
@@ -302,11 +306,11 @@ module Appium
|
|
302
306
|
# @param element [String] the class name for the element
|
303
307
|
# @param value [String] the value to search for
|
304
308
|
# @return [String]
|
305
|
-
def string_visible_contains
|
309
|
+
def string_visible_contains(element, value)
|
306
310
|
contains = {
|
307
311
|
target: value,
|
308
312
|
substring: true,
|
309
|
-
insensitive: true
|
313
|
+
insensitive: true
|
310
314
|
}
|
311
315
|
|
312
316
|
{
|
@@ -314,7 +318,7 @@ module Appium
|
|
314
318
|
onlyVisible: true,
|
315
319
|
name: contains,
|
316
320
|
label: contains,
|
317
|
-
value: contains
|
321
|
+
value: contains
|
318
322
|
}
|
319
323
|
end
|
320
324
|
|
@@ -322,7 +326,7 @@ module Appium
|
|
322
326
|
# @param element [String] the class name for the element
|
323
327
|
# @param value [String] the value to search for
|
324
328
|
# @return [Element]
|
325
|
-
def ele_by_json_visible_contains
|
329
|
+
def ele_by_json_visible_contains(element, value)
|
326
330
|
ele_by_json string_visible_contains element, value
|
327
331
|
end
|
328
332
|
|
@@ -330,7 +334,7 @@ module Appium
|
|
330
334
|
# @param element [String] the class name for the element
|
331
335
|
# @param value [String] the value to search for
|
332
336
|
# @return [Array<Element>]
|
333
|
-
def eles_by_json_visible_contains
|
337
|
+
def eles_by_json_visible_contains(element, value)
|
334
338
|
eles_by_json string_visible_contains element, value
|
335
339
|
end
|
336
340
|
|
@@ -339,11 +343,11 @@ module Appium
|
|
339
343
|
# @param element [String] the class name for the element
|
340
344
|
# @param value [String] the value to search for
|
341
345
|
# @return [String]
|
342
|
-
def string_visible_exact
|
346
|
+
def string_visible_exact(element, value)
|
343
347
|
exact = {
|
344
348
|
target: value,
|
345
349
|
substring: false,
|
346
|
-
insensitive: false
|
350
|
+
insensitive: false
|
347
351
|
}
|
348
352
|
|
349
353
|
{
|
@@ -351,7 +355,7 @@ module Appium
|
|
351
355
|
onlyVisible: true,
|
352
356
|
name: exact,
|
353
357
|
label: exact,
|
354
|
-
value: exact
|
358
|
+
value: exact
|
355
359
|
}
|
356
360
|
end
|
357
361
|
|
@@ -359,7 +363,7 @@ module Appium
|
|
359
363
|
# @param element [String] the class name for the element
|
360
364
|
# @param value [String] the value to search for
|
361
365
|
# @return [Element]
|
362
|
-
def ele_by_json_visible_exact
|
366
|
+
def ele_by_json_visible_exact(element, value)
|
363
367
|
ele_by_json string_visible_exact element, value
|
364
368
|
end
|
365
369
|
|
@@ -367,7 +371,7 @@ module Appium
|
|
367
371
|
# @param element [String] the class name for the element
|
368
372
|
# @param value [String] the value to search for
|
369
373
|
# @return [Element]
|
370
|
-
def eles_by_json_visible_exact
|
374
|
+
def eles_by_json_visible_exact(element, value)
|
371
375
|
eles_by_json string_visible_exact element, value
|
372
376
|
end
|
373
377
|
|
@@ -377,22 +381,22 @@ module Appium
|
|
377
381
|
# If close key is present then tap it.
|
378
382
|
# @param close_key [String] close key to tap. Default value is 'Done'
|
379
383
|
# @return [void]
|
380
|
-
def hide_ios_keyboard
|
381
|
-
|
382
|
-
|
383
|
-
app specific circumstances. webview keyboard will require a window.tap for example.
|
384
|
-
|
385
|
-
Find the top left corner of the keyboard and move up 10 pixels (origin.y - 10)
|
386
|
-
now swipe down until the end of the window - 10 pixels.
|
387
|
-
-10 to ensure we're not going outside the window bounds.
|
388
|
-
|
389
|
-
Swiping inside the keyboard will not dismiss it.
|
390
|
-
|
391
|
-
If the 'Done' key exists then that should be pressed to dismiss the keyboard
|
392
|
-
because swiping to dismiss works only if such key doesn't exist.
|
393
|
-
|
394
|
-
Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
395
|
-
|
384
|
+
def hide_ios_keyboard(close_key = 'Done')
|
385
|
+
#
|
386
|
+
# TODO: there are many various ways to hide the keyboard that work in different
|
387
|
+
# app specific circumstances. webview keyboard will require a window.tap for example.
|
388
|
+
#
|
389
|
+
# Find the top left corner of the keyboard and move up 10 pixels (origin.y - 10)
|
390
|
+
# now swipe down until the end of the window - 10 pixels.
|
391
|
+
# -10 to ensure we're not going outside the window bounds.
|
392
|
+
#
|
393
|
+
# Swiping inside the keyboard will not dismiss it.
|
394
|
+
#
|
395
|
+
# If the 'Done' key exists then that should be pressed to dismiss the keyboard
|
396
|
+
# because swiping to dismiss works only if such key doesn't exist.
|
397
|
+
#
|
398
|
+
# Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
399
|
+
#
|
396
400
|
dismiss_keyboard = (<<-JS).strip
|
397
401
|
if (!au.mainApp().keyboard().isNil()) {
|
398
402
|
var key = au.mainApp().keyboard().buttons()['#{close_key}']
|
@@ -431,11 +435,11 @@ Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
|
431
435
|
#
|
432
436
|
# visible - if true, only visible elements are returned. default true
|
433
437
|
#
|
434
|
-
def _all_pred
|
438
|
+
def _all_pred(opts)
|
435
439
|
predicate = opts[:predicate]
|
436
|
-
|
440
|
+
fail 'predicate must be provided' unless predicate
|
437
441
|
visible = opts.fetch :visible, true
|
438
|
-
%
|
442
|
+
%($.mainApp().getAllWithPredicate("#{predicate}", #{visible});)
|
439
443
|
end
|
440
444
|
|
441
445
|
# returns element matching predicate contained in the main app
|
@@ -444,7 +448,7 @@ Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
|
444
448
|
#
|
445
449
|
# visible - if true, only visible elements are returned. default true
|
446
450
|
# @return [Element]
|
447
|
-
def ele_with_pred
|
451
|
+
def ele_with_pred(opts)
|
448
452
|
# true = return only visible
|
449
453
|
find_element(:uiautomation, _all_pred(opts))
|
450
454
|
end
|
@@ -455,7 +459,7 @@ Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
|
455
459
|
#
|
456
460
|
# visible - if true, only visible elements are returned. default true
|
457
461
|
# @return [Array<Element>]
|
458
|
-
def eles_with_pred
|
462
|
+
def eles_with_pred(opts)
|
459
463
|
find_elements(:uiautomation, _all_pred(opts))
|
460
464
|
end
|
461
465
|
|
@@ -465,23 +469,23 @@ Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
|
465
469
|
_print_source get_source
|
466
470
|
end
|
467
471
|
|
468
|
-
def _validate_object
|
469
|
-
|
472
|
+
def _validate_object(*objects)
|
473
|
+
fail 'objects must be an array' unless objects.is_a? Array
|
470
474
|
objects.each do |obj|
|
471
475
|
next unless obj # obj may be nil. if so, ignore.
|
472
476
|
|
473
477
|
valid_keys = [:target, :substring, :insensitive]
|
474
478
|
unknown_keys = obj.keys - valid_keys
|
475
|
-
|
479
|
+
fail "Unknown keys: #{unknown_keys}" unless unknown_keys.empty?
|
476
480
|
|
477
481
|
target = obj[:target]
|
478
|
-
|
482
|
+
fail 'target must be a string' unless target.is_a? String
|
479
483
|
|
480
484
|
substring = obj[:substring]
|
481
|
-
|
485
|
+
fail 'substring must be a boolean' unless [true, false].include? substring
|
482
486
|
|
483
487
|
insensitive = obj[:insensitive]
|
484
|
-
|
488
|
+
fail 'insensitive must be a boolean' unless [true, false].include? insensitive
|
485
489
|
end
|
486
490
|
end
|
487
491
|
|
@@ -513,33 +517,42 @@ Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
|
513
517
|
# }
|
514
518
|
# }
|
515
519
|
#
|
516
|
-
def _by_json
|
520
|
+
def _by_json(opts)
|
517
521
|
valid_keys = [:typeArray, :onlyFirst, :onlyVisible, :name, :label, :value]
|
518
522
|
unknown_keys = opts.keys - valid_keys
|
519
|
-
|
523
|
+
fail "Unknown keys: #{unknown_keys}" unless unknown_keys.empty?
|
520
524
|
|
521
|
-
|
522
|
-
|
525
|
+
type_array = opts[:typeArray]
|
526
|
+
fail 'typeArray must be an array' unless type_array.is_a? Array
|
523
527
|
|
524
|
-
|
525
|
-
|
528
|
+
only_first = opts[:onlyFirst]
|
529
|
+
fail 'onlyFirst must be a boolean' unless [true, false].include? only_first
|
526
530
|
|
527
|
-
|
528
|
-
|
531
|
+
only_visible = opts[:onlyVisible]
|
532
|
+
fail 'onlyVisible must be a boolean' unless [true, false].include? only_visible
|
529
533
|
|
530
534
|
# name/label/value are optional. when searching for class only, then none
|
531
535
|
# will be present.
|
532
536
|
_validate_object opts[:name], opts[:label], opts[:value]
|
533
537
|
|
538
|
+
# note that mainWindow is sometimes nil so it's passed as a param
|
539
|
+
# $._elementOrElementsByType will validate that the window isn't nil
|
534
540
|
element_or_elements_by_type = <<-JS
|
535
541
|
(function() {
|
536
|
-
var opts = #{opts.to_json}
|
542
|
+
var opts = #{opts.to_json};
|
543
|
+
var result = false;
|
544
|
+
|
545
|
+
try {
|
546
|
+
result = $._elementOrElementsByType($.mainWindow(), opts);
|
547
|
+
} catch (e) {
|
548
|
+
}
|
537
549
|
|
538
|
-
return
|
550
|
+
return result;
|
539
551
|
})();
|
540
552
|
JS
|
541
553
|
|
542
|
-
execute_script element_or_elements_by_type
|
554
|
+
res = execute_script element_or_elements_by_type
|
555
|
+
res ? res : fail(Selenium::Client::CommandError, 'mainWindow is nil')
|
543
556
|
end
|
544
557
|
|
545
558
|
# example usage:
|
@@ -553,16 +566,16 @@ Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
|
553
566
|
# insensitive: false,
|
554
567
|
# },
|
555
568
|
# })
|
556
|
-
def eles_by_json
|
569
|
+
def eles_by_json(opts)
|
557
570
|
opts[:onlyFirst] = false
|
558
|
-
|
571
|
+
_by_json opts
|
559
572
|
end
|
560
573
|
|
561
574
|
# see eles_by_json
|
562
|
-
def ele_by_json
|
575
|
+
def ele_by_json(opts)
|
563
576
|
opts[:onlyFirst] = true
|
564
577
|
result = _by_json(opts).first
|
565
|
-
|
578
|
+
fail _no_such_element if result.nil?
|
566
579
|
result
|
567
580
|
end
|
568
581
|
|
@@ -573,4 +586,4 @@ Don't use window.tap. See https://github.com/appium/appium-uiauto/issues/28
|
|
573
586
|
@driver.page_source
|
574
587
|
end
|
575
588
|
end # module Ios
|
576
|
-
end # module Appium
|
589
|
+
end # module Appium
|