appium_lib 0.24.1 → 1.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.
- 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
|