appium_lib 0.24.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +17 -8
- data/android_tests/Gemfile +1 -0
- data/android_tests/LICENSE-2.0.txt +202 -0
- data/android_tests/Rakefile +61 -0
- data/android_tests/api.apk +0 -0
- data/android_tests/appium.txt +3 -0
- data/android_tests/flaky.txt +1 -0
- data/android_tests/lib/android/specs/android/dynamic.rb +5 -0
- data/android_tests/lib/android/specs/android/element/alert.rb +41 -0
- data/android_tests/lib/android/specs/android/element/button.rb +55 -0
- data/android_tests/lib/android/specs/android/element/generic.rb +48 -0
- data/android_tests/lib/android/specs/android/element/text.rb +39 -0
- data/android_tests/lib/android/specs/android/element/textfield.rb +60 -0
- data/android_tests/lib/android/specs/android/helper.rb +80 -0
- data/android_tests/lib/android/specs/android/patch.rb +14 -0
- data/android_tests/lib/android/specs/common/device.rb +117 -0
- data/android_tests/lib/android/specs/common/element/window.rb +9 -0
- data/android_tests/lib/android/specs/common/helper.rb +112 -0
- data/android_tests/lib/android/specs/common/patch.rb +69 -0
- data/android_tests/lib/android/specs/common/version.rb +9 -0
- data/android_tests/lib/android/specs/driver.rb +174 -0
- data/android_tests/lib/format.rb +49 -0
- data/android_tests/lib/run.rb +72 -0
- data/android_tests/readme.md +27 -0
- data/appium_lib.gemspec +8 -5
- data/docs/android_docs.md +1052 -716
- data/docs/ios_docs.md +657 -834
- data/docs_gen/make_docs.rb +1 -3
- data/ios_tests/Gemfile +1 -0
- data/ios_tests/LICENSE-2.0.txt +202 -0
- data/ios_tests/Rakefile +47 -0
- data/ios_tests/UICatalog.app.zip +0 -0
- data/ios_tests/UICatalog.app/12-6AM.png +0 -0
- data/ios_tests/UICatalog.app/12-6PM.png +0 -0
- data/ios_tests/UICatalog.app/6-12AM.png +0 -0
- data/ios_tests/UICatalog.app/6-12PM.png +0 -0
- data/ios_tests/UICatalog.app/Default-568h@2x.png +0 -0
- data/ios_tests/UICatalog.app/Default@2x.png +0 -0
- data/ios_tests/UICatalog.app/Info.plist +0 -0
- data/ios_tests/UICatalog.app/PkgInfo +1 -0
- data/ios_tests/UICatalog.app/UIButton_custom.png +0 -0
- data/ios_tests/UICatalog.app/UICatalog +0 -0
- data/ios_tests/UICatalog.app/blueButton.png +0 -0
- data/ios_tests/UICatalog.app/bookmarkImage.png +0 -0
- data/ios_tests/UICatalog.app/bookmarkImageHighlighted.png +0 -0
- data/ios_tests/UICatalog.app/divider.png +0 -0
- data/ios_tests/UICatalog.app/en.lproj/AlertsViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ButtonsViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ControlsViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ImagesViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/Localizable.strings +0 -0
- data/ios_tests/UICatalog.app/en.lproj/MainWindow.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/PickerViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/SearchBarController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/SegmentViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/TextFieldController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/TextViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/ToolbarViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/TransitionViewController.nib +0 -0
- data/ios_tests/UICatalog.app/en.lproj/WebViewController.nib +0 -0
- data/ios_tests/UICatalog.app/orangeslide.png +0 -0
- data/ios_tests/UICatalog.app/scene1.jpg +0 -0
- data/ios_tests/UICatalog.app/scene2.jpg +0 -0
- data/ios_tests/UICatalog.app/scene3.jpg +0 -0
- data/ios_tests/UICatalog.app/scene4.jpg +0 -0
- data/ios_tests/UICatalog.app/scene5.jpg +0 -0
- data/ios_tests/UICatalog.app/searchBarBackground.png +0 -0
- data/ios_tests/UICatalog.app/segment_check.png +0 -0
- data/ios_tests/UICatalog.app/segment_search.png +0 -0
- data/ios_tests/UICatalog.app/segment_tools.png +0 -0
- data/ios_tests/UICatalog.app/segmentedBackground.png +0 -0
- data/ios_tests/UICatalog.app/slider_ball.png +0 -0
- data/ios_tests/UICatalog.app/toolbarBackground.png +0 -0
- data/ios_tests/UICatalog.app/whiteButton.png +0 -0
- data/ios_tests/UICatalog.app/yellowslide.png +0 -0
- data/ios_tests/appium.txt +3 -0
- data/ios_tests/flaky.txt +1 -0
- data/ios_tests/lib/format.rb +25 -0
- data/ios_tests/lib/ios/specs/common/element/window.rb +15 -0
- data/ios_tests/lib/ios/specs/common/helper.rb +204 -0
- data/ios_tests/lib/ios/specs/common/patch.rb +50 -0
- data/ios_tests/lib/ios/specs/common/version.rb +17 -0
- data/ios_tests/lib/ios/specs/device/device.rb +82 -0
- data/ios_tests/lib/ios/specs/device/multi_touch.rb +12 -0
- data/ios_tests/lib/ios/specs/device/touch_actions.rb +15 -0
- data/ios_tests/lib/ios/specs/driver.rb +203 -0
- data/ios_tests/lib/ios/specs/ios/element/alert.rb +48 -0
- data/ios_tests/lib/ios/specs/ios/element/button.rb +58 -0
- data/ios_tests/lib/ios/specs/ios/element/generic.rb +35 -0
- data/ios_tests/lib/ios/specs/ios/element/text.rb +54 -0
- data/ios_tests/lib/ios/specs/ios/element/textfield.rb +123 -0
- data/ios_tests/lib/ios/specs/ios/helper.rb +27 -0
- data/ios_tests/lib/ios/specs/ios/patch.rb +30 -0
- data/ios_tests/lib/run.rb +106 -0
- data/ios_tests/readme.md +30 -0
- data/ios_tests/upload/sauce_storage.rb +64 -0
- data/ios_tests/upload/upload.rb +6 -0
- data/lib/appium_lib.rb +4 -14
- data/lib/appium_lib/android/dynamic.rb +30 -32
- data/lib/appium_lib/android/element/alert.rb +34 -33
- data/lib/appium_lib/android/element/button.rb +91 -0
- data/lib/appium_lib/android/element/generic.rb +51 -146
- data/lib/appium_lib/android/element/text.rb +54 -0
- data/lib/appium_lib/android/element/textfield.rb +46 -41
- data/lib/appium_lib/android/helper.rb +248 -417
- data/lib/appium_lib/android/mobile_methods.rb +17 -0
- data/lib/appium_lib/android/patch.rb +9 -8
- data/lib/appium_lib/awesome_print/ostruct.rb +33 -0
- data/lib/appium_lib/common/element/window.rb +9 -8
- data/lib/appium_lib/common/helper.rb +182 -243
- data/lib/appium_lib/common/patch.rb +65 -79
- data/lib/appium_lib/common/version.rb +2 -3
- data/lib/appium_lib/device/device.rb +339 -0
- data/lib/appium_lib/device/multi_touch.rb +94 -0
- data/lib/appium_lib/device/touch_actions.rb +142 -0
- data/lib/appium_lib/driver.rb +217 -306
- data/lib/appium_lib/ios/element/alert.rb +16 -92
- data/lib/appium_lib/ios/element/button.rb +55 -0
- data/lib/appium_lib/ios/element/generic.rb +27 -160
- data/lib/appium_lib/ios/element/text.rb +54 -0
- data/lib/appium_lib/ios/element/textfield.rb +78 -65
- data/lib/appium_lib/ios/helper.rb +300 -190
- data/lib/appium_lib/ios/mobile_methods.rb +17 -0
- data/lib/appium_lib/ios/patch.rb +55 -41
- data/lib/appium_lib/logger.rb +13 -0
- data/lib/appium_lib/rails/duplicable.rb +116 -0
- data/readme.md +6 -1
- data/release_notes.md +118 -0
- metadata +170 -12
- data/lib/appium_lib/common/element/button.rb +0 -83
- data/lib/appium_lib/common/element/text.rb +0 -61
@@ -1,209 +1,319 @@
|
|
1
|
-
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
@driver.execute_script js
|
43
|
-
end
|
44
|
-
|
45
|
-
# iOS only. On Android uiautomator always returns an empty string for EditText password.
|
46
|
-
#
|
47
|
-
# Password character returned from value of UIASecureTextField
|
48
|
-
# @param length [Integer] the length of the password to generate
|
49
|
-
# @return [String] the returned string is of size length
|
50
|
-
def ios_password length=1
|
51
|
-
'•' * length
|
52
|
-
end
|
53
|
-
|
54
|
-
# Returns a string of class counts.
|
55
|
-
def get_page_class
|
56
|
-
r = []
|
57
|
-
run_internal = lambda do |node|
|
58
|
-
if node.kind_of? Array
|
59
|
-
node.each { |node| run_internal.call node }
|
60
|
-
return
|
1
|
+
module Appium
|
2
|
+
module Ios
|
3
|
+
# iOS only. On Android uiautomator always returns an empty string for EditText password.
|
4
|
+
#
|
5
|
+
# Password character returned from value of UIASecureTextField
|
6
|
+
# @param length [Integer] the length of the password to generate
|
7
|
+
# @return [String] the returned string is of size length
|
8
|
+
def ios_password length=1
|
9
|
+
'•' * length
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns a string of interesting elements. iOS only.
|
13
|
+
#
|
14
|
+
# Defaults to inspecting the 1st windows source only.
|
15
|
+
# use get_page(get_source) for all window sources
|
16
|
+
#
|
17
|
+
# @param element [Object] the element to search. omit to search everything
|
18
|
+
# @return [String]
|
19
|
+
def get_page element=source_window(0), class_name=nil
|
20
|
+
lazy_load_strings # populate @strings_xml
|
21
|
+
|
22
|
+
# @private
|
23
|
+
def empty ele
|
24
|
+
(ele['name'] || ele['label'] || ele['value']) == nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# @private
|
28
|
+
def fix_space s
|
29
|
+
# if s is an int, we can't call .empty
|
30
|
+
return nil if s.nil? || (s.respond_to?(:empty) && s.empty?)
|
31
|
+
# ints don't respond to force encoding
|
32
|
+
# ensure we're converting to a string
|
33
|
+
unless s.respond_to? :force_encoding
|
34
|
+
s_s = s.to_s
|
35
|
+
return s_s.empty? ? nil : s_s
|
36
|
+
end
|
37
|
+
# char code 160 (name, label) vs 32 (value) will break comparison.
|
38
|
+
# convert string to binary and remove 160.
|
39
|
+
# \xC2\xA0
|
40
|
+
s = s.force_encoding('binary').gsub("\xC2\xA0".force_encoding('binary'), ' ') if s
|
41
|
+
s.empty? ? nil : s
|
61
42
|
end
|
62
43
|
|
63
|
-
|
64
|
-
|
65
|
-
|
44
|
+
unless empty(element) || element['visible'] == false
|
45
|
+
name = fix_space element['name']
|
46
|
+
label = fix_space element['label']
|
47
|
+
value = fix_space element['value']
|
48
|
+
hint = fix_space element['hint']
|
49
|
+
visible = fix_space element['visible']
|
50
|
+
type = fix_space element['type']
|
51
|
+
|
52
|
+
# if class_name is set, mark non-matches as invisible
|
53
|
+
visible = (type == class_name).to_s if class_name
|
54
|
+
|
55
|
+
if name == label && name == value
|
56
|
+
puts "#{type}" if name || label || value || hint
|
57
|
+
puts " name, label, value: #{name}" if name
|
58
|
+
puts " hint: #{hint}" if hint
|
59
|
+
elsif name == label
|
60
|
+
puts "#{type}" if name || label || value || hint
|
61
|
+
puts " name, label: #{name}" if name
|
62
|
+
puts " value: #{value}" if value
|
63
|
+
puts " hint: #{hint}" if hint
|
64
|
+
elsif name == value
|
65
|
+
puts "#{type}" if name || label || value || hint
|
66
|
+
puts " name, value: #{name}" if name
|
67
|
+
puts " label: #{label}" if label
|
68
|
+
puts " hint: #{hint}" if hint
|
69
|
+
else
|
70
|
+
puts "#{type}" if name || label || value || hint
|
71
|
+
puts " name: #{name}" if name
|
72
|
+
puts " label: #{label}" if label
|
73
|
+
puts " value: #{value}" if value
|
74
|
+
puts " hint: #{hint}" if hint
|
75
|
+
end if visible && visible == 'true'
|
66
76
|
|
67
|
-
|
77
|
+
# there may be many ids with the same value.
|
78
|
+
# output all exact matches.
|
79
|
+
id_matches = @strings_xml.select do |key, val|
|
80
|
+
val == name || val == label || val == value
|
81
|
+
end
|
82
|
+
|
83
|
+
if id_matches && id_matches.length > 0
|
84
|
+
match_str = ''
|
85
|
+
# [0] = key, [1] = value
|
86
|
+
id_matches.each do |match|
|
87
|
+
match_str += ' ' * 7 + "#{match[0]}\n"
|
88
|
+
end
|
89
|
+
puts " id: #{match_str.strip}\n"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
children = element['children']
|
94
|
+
children.each { |c| get_page c, class_name } if children
|
95
|
+
nil
|
68
96
|
end
|
69
|
-
json = get_source
|
70
|
-
run_internal.call json['children']
|
71
97
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
98
|
+
# Prints a string of interesting elements to the console.
|
99
|
+
# @return [void]
|
100
|
+
def page opts={}
|
101
|
+
window_number = opts.fetch :window, -1
|
102
|
+
class_name = opts.fetch :class, nil
|
103
|
+
|
104
|
+
if window_number == -1
|
105
|
+
# if the 0th window has no children, find the next window that does.
|
106
|
+
target_window = source_window 0
|
107
|
+
target_window = source_window 1 if target_window['children'].empty?
|
108
|
+
get_page target_window, class_name
|
109
|
+
else
|
110
|
+
get_page source_window(window_number || 0), class_name
|
111
|
+
end
|
112
|
+
nil
|
76
113
|
end
|
77
|
-
count_sort = ->(one, two) { two.match(/(\d+)x/)[1].to_i <=> one.match(/(\d+)x/)[1].to_i }
|
78
|
-
res.sort(&count_sort).join ''
|
79
|
-
end
|
80
114
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
115
|
+
# Gets the JSON source of window number
|
116
|
+
# @param window_number [Integer] the int index of the target window
|
117
|
+
# @return [JSON]
|
118
|
+
def source_window window_number=0
|
119
|
+
# appium 1.0 still returns JSON when getTree() is invoked so this
|
120
|
+
# doesn't need to change to XML. If getTree() is removed then
|
121
|
+
# source_window will need to parse the results of getTreeForXML()\
|
122
|
+
# https://github.com/appium/appium-uiauto/blob/247eb71383fa1a087ff8f8fc96fac25025731f3f/uiauto/appium/element.js#L145
|
123
|
+
execute_script "UIATarget.localTarget().frontMostApp().windows()[#{window_number}].getTree()"
|
124
|
+
end
|
125
|
+
|
126
|
+
# Prints parsed page source to console.
|
127
|
+
#
|
128
|
+
# example: page_window 0
|
129
|
+
#
|
130
|
+
# @param window_number [Integer] the int index of the target window
|
131
|
+
# @return [void]
|
132
|
+
def page_window window_number=0
|
133
|
+
get_page source_window window_number
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
|
137
|
+
# Find by id
|
138
|
+
# @param id [String] the id to search for
|
139
|
+
# @return [Element]
|
140
|
+
def id id
|
141
|
+
value = resolve_id id
|
142
|
+
raise "Invalid id `#{id}`" unless value
|
143
|
+
exact = string_visible_exact '*', value
|
144
|
+
contains = string_visible_contains '*', value
|
145
|
+
xpath "#{exact} | #{contains}"
|
146
|
+
end
|
85
147
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
148
|
+
# Return the iOS version as an array of integers
|
149
|
+
# @return [Array<Integer>]
|
150
|
+
def ios_version
|
151
|
+
ios_version = execute_script 'UIATarget.localTarget().systemVersion()'
|
152
|
+
ios_version.split('.').map { |e| e.to_i }
|
153
|
+
end
|
154
|
+
|
155
|
+
# Get the element of type class_name at matching index.
|
156
|
+
# @param class_name [String] the class name to find
|
157
|
+
# @param index [Integer] the index
|
158
|
+
# @return [Element]
|
159
|
+
def ele_index class_name, index
|
160
|
+
unless index == 'last()'
|
161
|
+
# XPath index starts at 1.
|
162
|
+
raise "#{index} is not a valid xpath index. Must be >= 1" if index <= 0
|
163
|
+
end
|
164
|
+
find_element :xpath, %Q(//#{class_name}[@visible="true"][#{index}])
|
165
|
+
end
|
95
166
|
|
96
167
|
# @private
|
97
|
-
def
|
98
|
-
(
|
168
|
+
def string_attr_exact class_name, attr, value
|
169
|
+
%Q(//#{class_name}[@visible="true" and @#{attr}='#{value}'])
|
170
|
+
end
|
171
|
+
|
172
|
+
# Find the first element exactly matching class and attribute value.
|
173
|
+
# @param class_name [String] the class name to search for
|
174
|
+
# @param attr [String] the attribute to inspect
|
175
|
+
# @param value [String] the expected value of the attribute
|
176
|
+
# @return [Element]
|
177
|
+
def find_ele_by_attr class_name, attr, value
|
178
|
+
@driver.find_element :xpath, string_attr_exact(class_name, attr, value)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Find all elements exactly matching class and attribute value.
|
182
|
+
# @param class_name [String] the class name to match
|
183
|
+
# @param attr [String] the attribute to compare
|
184
|
+
# @param value [String] the value of the attribute that the element must have
|
185
|
+
# @return [Array<Element>]
|
186
|
+
def find_eles_by_attr class_name, attr, value
|
187
|
+
@driver.find_elements :xpath, string_attr_exact(class_name, attr, value)
|
99
188
|
end
|
100
189
|
|
101
190
|
# @private
|
102
|
-
def
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
191
|
+
def string_attr_include class_name, attr, value
|
192
|
+
%Q(//#{class_name}[@visible="true" and contains(translate(@#{attr},'#{value.upcase}', '#{value}'), '#{value}')])
|
193
|
+
end
|
194
|
+
|
195
|
+
# Get the first tag by attribute that exactly matches value.
|
196
|
+
# @param class_name [String] the tag name to match
|
197
|
+
# @param attr [String] the attribute to compare
|
198
|
+
# @param value [String] the value of the attribute that the element must include
|
199
|
+
# @return [Element] the element of type tag who's attribute includes value
|
200
|
+
def find_ele_by_attr_include class_name, attr, value
|
201
|
+
@driver.find_element :xpath, string_attr_include(class_name, attr, value)
|
202
|
+
end
|
203
|
+
|
204
|
+
# Get tags by attribute that include value.
|
205
|
+
# @param class_name [String] the tag name to match
|
206
|
+
# @param attr [String] the attribute to compare
|
207
|
+
# @param value [String] the value of the attribute that the element must include
|
208
|
+
# @return [Array<Element>] the elements of type tag who's attribute includes value
|
209
|
+
def find_eles_by_attr_include class_name, attr, value
|
210
|
+
@driver.find_elements :xpath, string_attr_include(class_name, attr, value)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Get the first tag that matches class_name
|
214
|
+
# @param class_name [String] the tag to match
|
215
|
+
# @return [Element]
|
216
|
+
def first_ele class_name
|
217
|
+
# XPath index starts at 1
|
218
|
+
ele_index class_name, 1
|
219
|
+
end
|
220
|
+
|
221
|
+
# Get the last tag that matches class_name
|
222
|
+
# @param class_name [String] the tag to match
|
223
|
+
# @return [Element]
|
224
|
+
def last_ele class_name
|
225
|
+
ele_index class_name, 'last()'
|
226
|
+
end
|
227
|
+
|
228
|
+
# Returns the first element matching class_name
|
229
|
+
#
|
230
|
+
# @param class_name [String] the class_name to search for
|
231
|
+
# @return [Element]
|
232
|
+
def tag class_name
|
233
|
+
xpath %Q(//#{class_name}[@visible="true"])
|
234
|
+
end
|
235
|
+
|
236
|
+
# Returns all elements matching class_name
|
237
|
+
#
|
238
|
+
# @param class_name [String] the class_name to search for
|
239
|
+
# @return [Element]
|
240
|
+
def tags class_name
|
241
|
+
xpaths %Q(//#{class_name}[@visible="true"])
|
242
|
+
end
|
243
|
+
|
244
|
+
# @private
|
245
|
+
# Returns a string xpath that matches the first element that contains value
|
246
|
+
#
|
247
|
+
# example: xpath_visible_contains 'UIATextField', 'sign in'
|
248
|
+
#
|
249
|
+
# @param element [String] the class name for the element
|
250
|
+
# @param value [String] the value to search for
|
251
|
+
# @return [String]
|
252
|
+
def string_visible_contains element, value
|
253
|
+
result = []
|
254
|
+
attributes = %w[name hint label value]
|
137
255
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
256
|
+
value_up = value.upcase
|
257
|
+
value_down = value.downcase
|
258
|
+
|
259
|
+
attributes.each do |attribute|
|
260
|
+
result << %Q(contains(translate(@#{attribute},"#{value_up}","#{value_down}"), "#{value_down}"))
|
142
261
|
end
|
143
262
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
263
|
+
result = result.join(' or ')
|
264
|
+
result = %Q(@visible="true" and (#{result}))
|
265
|
+
"//#{element}[#{result}]"
|
266
|
+
end
|
267
|
+
|
268
|
+
# Find the first element that contains value
|
269
|
+
# @param element [String] the class name for the element
|
270
|
+
# @param value [String] the value to search for
|
271
|
+
# @return [Element]
|
272
|
+
def xpath_visible_contains element, value
|
273
|
+
xpath string_visible_contains element, value
|
274
|
+
end
|
275
|
+
|
276
|
+
# Find all elements containing value
|
277
|
+
# @param element [String] the class name for the element
|
278
|
+
# @param value [String] the value to search for
|
279
|
+
# @return [Array<Element>]
|
280
|
+
def xpaths_visible_contains element, value
|
281
|
+
xpaths string_visible_contains element, value
|
282
|
+
end
|
283
|
+
|
284
|
+
# @private
|
285
|
+
# Create an xpath string to exactly match the first element with target value
|
286
|
+
# @param element [String] the class name for the element
|
287
|
+
# @param value [String] the value to search for
|
288
|
+
# @return [String]
|
289
|
+
def string_visible_exact element, value
|
290
|
+
result = []
|
291
|
+
attributes = %w[name hint label value]
|
292
|
+
|
293
|
+
attributes.each do |attribute|
|
294
|
+
result << %Q(@#{attribute}="#{value}")
|
151
295
|
end
|
296
|
+
|
297
|
+
result = result.join(' or ')
|
298
|
+
result = %Q(@visible="true" and (#{result}))
|
299
|
+
|
300
|
+
"//#{element}[#{result}]"
|
152
301
|
end
|
153
302
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
|
173
|
-
# Gets the JSON source of window number
|
174
|
-
# @param window_number [Integer] the int index of the target window
|
175
|
-
# @return [JSON]
|
176
|
-
def source_window window_number=0
|
177
|
-
execute_script "UIATarget.localTarget().frontMostApp().windows()[#{window_number}].getTree()"
|
178
|
-
end
|
179
|
-
|
180
|
-
# Prints parsed page source to console.
|
181
|
-
# @param window_number [Integer] the int index of the target window
|
182
|
-
# example: page_window 0
|
183
|
-
def page_window window_number=0
|
184
|
-
get_page source_window window_number
|
185
|
-
nil
|
186
|
-
end
|
187
|
-
|
188
|
-
# The fastest duration that can be used on iOS.
|
189
|
-
# @return [Float]
|
190
|
-
def fast_duration
|
191
|
-
0.5
|
192
|
-
end
|
193
|
-
|
194
|
-
# Find by id. Useful for selendroid
|
195
|
-
# @param id [String] the id to search for
|
196
|
-
# @return [Element]
|
197
|
-
def id id
|
198
|
-
lazy_load_strings
|
199
|
-
raise "Invalid id `#{id}`" unless @strings_xml[id]
|
200
|
-
find_element :id, id
|
201
|
-
end
|
202
|
-
|
203
|
-
# Return the iOS version as an array of integers
|
204
|
-
# @return [Array<Integer>]
|
205
|
-
def ios_version
|
206
|
-
ios_version = execute_script 'UIATarget.localTarget().systemVersion()'
|
207
|
-
ios_version.split('.').map { |e| e.to_i }
|
208
|
-
end
|
209
|
-
end # module Appium::Ios
|
303
|
+
# Find the first element exactly matching value
|
304
|
+
# @param element [String] the class name for the element
|
305
|
+
# @param value [String] the value to search for
|
306
|
+
# @return [Element]
|
307
|
+
def xpath_visible_exact element, value
|
308
|
+
xpath string_visible_exact element, value
|
309
|
+
end
|
310
|
+
|
311
|
+
# Find all elements exactly matching value
|
312
|
+
# @param element [String] the class name for the element
|
313
|
+
# @param value [String] the value to search for
|
314
|
+
# @return [Element]
|
315
|
+
def xpaths_visible_exact element, value
|
316
|
+
xpaths string_visible_exact element, value
|
317
|
+
end
|
318
|
+
end # module Ios
|
319
|
+
end # module Appium
|