appium_lib 0.0.30 → 0.3.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 +8 -8
- data/Rakefile +15 -7
- data/appium_lib.gemspec +3 -3
- data/docs.md +7 -5
- data/lib/appium_lib.rb +34 -6
- data/lib/appium_lib/android/element/alert.rb +43 -0
- data/lib/appium_lib/android/element/generic.rb +94 -0
- data/lib/appium_lib/android/element/textfield.rb +43 -0
- data/lib/appium_lib/android/helper.rb +120 -0
- data/lib/appium_lib/android/patch.rb +10 -0
- data/lib/appium_lib/common/element/button.rb +83 -0
- data/lib/appium_lib/common/element/text.rb +44 -0
- data/lib/appium_lib/common/element/window.rb +9 -0
- data/lib/appium_lib/common/helper.rb +140 -0
- data/lib/appium_lib/common/patch.rb +83 -0
- data/lib/appium_lib/common/version.rb +6 -0
- data/lib/appium_lib/driver.rb +265 -0
- data/lib/appium_lib/ios/element/alert.rb +56 -0
- data/lib/appium_lib/ios/element/generic.rb +170 -0
- data/lib/appium_lib/ios/element/textfield.rb +90 -0
- data/lib/appium_lib/ios/helper.rb +103 -0
- data/lib/appium_lib/ios/patch.rb +15 -0
- data/readme.md +10 -3
- data/release_notes.md +8 -0
- metadata +19 -15
- data/lib/appium_lib/console.rb +0 -254
- data/lib/appium_lib/element/android/alert.rb +0 -45
- data/lib/appium_lib/element/android/generic.rb +0 -88
- data/lib/appium_lib/element/android/textfield.rb +0 -44
- data/lib/appium_lib/element/button.rb +0 -83
- data/lib/appium_lib/element/ios/alert.rb +0 -49
- data/lib/appium_lib/element/ios/generic.rb +0 -140
- data/lib/appium_lib/element/ios/textfield.rb +0 -93
- data/lib/appium_lib/element/text.rb +0 -43
- data/lib/appium_lib/element/window.rb +0 -12
- data/lib/appium_lib/helper.rb +0 -278
- data/lib/appium_lib/patch.rb +0 -90
- data/lib/appium_lib/version.rb +0 -4
data/lib/appium_lib/helper.rb
DELETED
@@ -1,278 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
# Generic helper methods not specific
|
3
|
-
# to a particular tag name
|
4
|
-
|
5
|
-
# json and ap are required for the source method.
|
6
|
-
require 'json'
|
7
|
-
require 'ap' # awesome print
|
8
|
-
require 'timeout' # for wait
|
9
|
-
|
10
|
-
# iOS .name returns the accessibility attribute if it's set. if not set, the string value is used.
|
11
|
-
# Android .name returns the accessibility attribute and nothing if it's not set.
|
12
|
-
#
|
13
|
-
# .text should be cross platform so prefer that over name, unless both
|
14
|
-
# Android and iOS have proper accessibility attributes.
|
15
|
-
# .text and .value should be the same so use .text over .value.
|
16
|
-
#
|
17
|
-
# secure tag_name is iOS only because it can't be implemented using uiautomator for Android.
|
18
|
-
#
|
19
|
-
# find_element :text doesn't work so use XPath to find by text.
|
20
|
-
|
21
|
-
# Check every 0.5 seconds to see if block.call is true.
|
22
|
-
# Give up after 30 seconds.
|
23
|
-
# @param block [Block] the block to call
|
24
|
-
# @return [Object] the result of block.call
|
25
|
-
def wait &block
|
26
|
-
# Rescue Timeout::Error: execution expired
|
27
|
-
result = nil
|
28
|
-
timeout(30) { while(!(result = begin;block.call;rescue;end)) do; sleep(0.5) end }
|
29
|
-
result
|
30
|
-
end
|
31
|
-
|
32
|
-
# Presses the back button on Android.
|
33
|
-
# @return [void]
|
34
|
-
def back
|
35
|
-
$driver.navigate.back
|
36
|
-
end
|
37
|
-
|
38
|
-
# Get the element of type tag_name at matching index.
|
39
|
-
# @param tag_name [String] the tag name to find
|
40
|
-
# @param index [Integer] the index
|
41
|
-
# @return [Element] the found element of type tag_name
|
42
|
-
def ele_index tag_name, index
|
43
|
-
find_eles(tag_name)[index]
|
44
|
-
end
|
45
|
-
|
46
|
-
# Get all elements exactly matching tag name
|
47
|
-
# @param tag_name [String] the tag name to find
|
48
|
-
# @return [Array<Element>] the found elements of type tag_name
|
49
|
-
def find_eles tag_name
|
50
|
-
$driver.find_elements :tag_name, tag_name
|
51
|
-
end
|
52
|
-
|
53
|
-
# iOS only. Android uses uiautomator instead of uiautomation.
|
54
|
-
# Get an array of attribute values from elements exactly matching tag name.
|
55
|
-
# @param tag_name [String] the tag name to find
|
56
|
-
# @param attribute [String] the attribute to collect
|
57
|
-
# @result [Array<String>] an array of strings containing the attribute from found elements of type tag_name.
|
58
|
-
def find_eles_attr tag_name, attribute
|
59
|
-
# Use au.lookup(tag_name) instead of $(tag_name)
|
60
|
-
# See https://github.com/appium/appium/issues/214
|
61
|
-
js = %Q(
|
62
|
-
var eles = au.lookup('#{tag_name}');
|
63
|
-
var result = [];
|
64
|
-
for (var a = 0, length = eles.length; a < length; a++) {
|
65
|
-
result.push(eles[a].#{attribute}());
|
66
|
-
}
|
67
|
-
result
|
68
|
-
)
|
69
|
-
|
70
|
-
$driver.execute_script js
|
71
|
-
end
|
72
|
-
|
73
|
-
# iOS only. Android uses uiautomator instead of uiautomation.
|
74
|
-
# Get an array of attribute values from elements exactly matching tag name.
|
75
|
-
# @param tag_name_1 [String] the 1st tag name to find
|
76
|
-
# @param tag_name_2 [String] the 2nd tag name to find
|
77
|
-
# @param attribute [String] the attribute to collect
|
78
|
-
# @result [Array<String>] an array of strings containing the attribute from found elements of type tag_name.
|
79
|
-
def find_2_eles_attr tag_name_1, tag_name_2, attribute
|
80
|
-
# Use au.lookup(tag_name) instead of $(tag_name)
|
81
|
-
# See https://github.com/appium/appium/issues/214
|
82
|
-
js = %Q(
|
83
|
-
var eles = au.lookup('#{tag_name_1}');
|
84
|
-
eles = $(eles.concat(au.lookup('#{tag_name_2}')));
|
85
|
-
var result = [];
|
86
|
-
for (var a = 0, length = eles.length; a < length; a++) {
|
87
|
-
result.push(eles[a].#{attribute}());
|
88
|
-
}
|
89
|
-
result
|
90
|
-
)
|
91
|
-
|
92
|
-
$driver.execute_script js
|
93
|
-
end
|
94
|
-
|
95
|
-
# Get the first tag that exactly matches tag and text.
|
96
|
-
# @param tag [String] the tag name to match
|
97
|
-
# @param text [String] the text to exactly match
|
98
|
-
# @return [Element] the element of type tag exactly matching text
|
99
|
-
def find_ele_by_text tag, text
|
100
|
-
$driver.find_element :xpath, %Q(#{tag}[@text='#{text}'])
|
101
|
-
end
|
102
|
-
|
103
|
-
# Get all tags that exactly match tag and text.
|
104
|
-
# @param tag [String] the tag name to match
|
105
|
-
# @param text [String] the text to exactly match
|
106
|
-
# @return [Array<Element>] the elements of type tag exactly matching text
|
107
|
-
def find_eles_by_text tag, text
|
108
|
-
$driver.find_elements :xpath, %Q(#{tag}[@text='#{text}'])
|
109
|
-
end
|
110
|
-
|
111
|
-
# Get the first tag by attribute that exactly matches value.
|
112
|
-
# @param tag [String] the tag name to match
|
113
|
-
# @param attr [String] the attribute to compare
|
114
|
-
# @param value [String] the value of the attribute that the element must include
|
115
|
-
# @return [Element] the element of type tag who's attribute includes value
|
116
|
-
def find_ele_by_attr_include tag, attr, value
|
117
|
-
$driver.find_element :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
|
118
|
-
end
|
119
|
-
|
120
|
-
# Get tags by attribute that include value.
|
121
|
-
# @param tag [String] the tag name to match
|
122
|
-
# @param attr [String] the attribute to compare
|
123
|
-
# @param value [String] the value of the attribute that the element must include
|
124
|
-
# @return [Array<Element>] the elements of type tag who's attribute includes value
|
125
|
-
def find_eles_by_attr_include tag, attr, value
|
126
|
-
$driver.find_elements :xpath, %Q(#{tag}[contains(@#{attr}, '#{value}')])
|
127
|
-
end
|
128
|
-
|
129
|
-
# Get the first tag that includes text.
|
130
|
-
# @param tag [String] the tag name to match
|
131
|
-
# @param text [String] the text the element must include
|
132
|
-
# @return [Element] the element of type tag that includes text
|
133
|
-
# element.attribute(:text).include? text
|
134
|
-
def find_ele_by_text_include tag, text
|
135
|
-
find_ele_by_attr_include tag, :text, text
|
136
|
-
end
|
137
|
-
|
138
|
-
# Get the tags that include text.
|
139
|
-
# @param tag [String] the tag name to match
|
140
|
-
# @param text [String] the text the element must include
|
141
|
-
# @return [Array<Element>] the elements of type tag that includes text
|
142
|
-
# element.attribute(:text).include? text
|
143
|
-
def find_eles_by_text_include tag, text
|
144
|
-
find_eles_by_attr_include tag, :text, text
|
145
|
-
end
|
146
|
-
|
147
|
-
# Get the first tag that matches tag_name
|
148
|
-
# @param tag_name [String] the tag to match
|
149
|
-
# @return [Element]
|
150
|
-
def first_ele tag_name
|
151
|
-
tag = find_eles tag_name
|
152
|
-
tag = tag.first unless tag.nil?
|
153
|
-
end
|
154
|
-
|
155
|
-
# Get the last tag that matches tag_name
|
156
|
-
# @param tag_name [String] the tag to match
|
157
|
-
# @return [Element]
|
158
|
-
def last_ele tag_name
|
159
|
-
tag = find_eles tag_name
|
160
|
-
tag = tag.last unless tag.nil?
|
161
|
-
end
|
162
|
-
|
163
|
-
# Prints a JSON view of the current page
|
164
|
-
# @return [void]
|
165
|
-
def source
|
166
|
-
ap JSON.parse($driver.page_source)
|
167
|
-
end
|
168
|
-
|
169
|
-
# Gets a JSON view of the current page
|
170
|
-
# @return [JSON]
|
171
|
-
def get_source
|
172
|
-
JSON.parse($driver.page_source)
|
173
|
-
end
|
174
|
-
|
175
|
-
# iOS only. On Android uiautomator always returns an empty string for EditText password.
|
176
|
-
#
|
177
|
-
# Password character returned from value of UIASecureTextField
|
178
|
-
# @param length [Integer] the length of the password to generate
|
179
|
-
# @return [String] the returned string is of size length
|
180
|
-
def password length=1
|
181
|
-
'•' * length
|
182
|
-
end
|
183
|
-
|
184
|
-
# Android only.
|
185
|
-
def get_inspect
|
186
|
-
def run node
|
187
|
-
r = []
|
188
|
-
|
189
|
-
run_internal = lambda do |node|
|
190
|
-
if node.kind_of? Array
|
191
|
-
node.each { |node| run_internal.call node }
|
192
|
-
return
|
193
|
-
end
|
194
|
-
|
195
|
-
keys = node.keys
|
196
|
-
return if keys.empty?
|
197
|
-
|
198
|
-
obj = {}
|
199
|
-
obj.merge!( { desc: node["@content-desc"] } ) if keys.include?("@content-desc") && !node["@content-desc"].empty?
|
200
|
-
obj.merge!( { text: node["@text"] } ) if keys.include?("@text") && !node["@text"].empty?
|
201
|
-
obj.merge!( { class: node["@class"] } ) if keys.include?("@class") && !obj.empty?
|
202
|
-
|
203
|
-
r.push obj if !obj.empty?
|
204
|
-
run_internal.call node['node'] if keys.include?('node')
|
205
|
-
end
|
206
|
-
|
207
|
-
run_internal.call node
|
208
|
-
r
|
209
|
-
end
|
210
|
-
|
211
|
-
json = JSON.parse($driver.page_source)
|
212
|
-
node = json['hierarchy']
|
213
|
-
results = run node
|
214
|
-
|
215
|
-
out = ''
|
216
|
-
results.each { |e|
|
217
|
-
out += e[:class].split('.').last + "\n"
|
218
|
-
out += " text: #{e[:text]}\n" unless e[:text].nil?
|
219
|
-
out += " name: #{e[:desc]}\n" unless e[:desc].nil?
|
220
|
-
}
|
221
|
-
out
|
222
|
-
end if $os == :android
|
223
|
-
|
224
|
-
# Android only. Intended for use with console.
|
225
|
-
# Inspects and prints the current page.
|
226
|
-
def page
|
227
|
-
puts get_inspect
|
228
|
-
nil
|
229
|
-
end if $os == :android
|
230
|
-
|
231
|
-
def page element
|
232
|
-
|
233
|
-
def empty ele
|
234
|
-
(ele['name'] || ele['label'] || ele['value']) == nil
|
235
|
-
end
|
236
|
-
|
237
|
-
def fix_space s
|
238
|
-
# char code 160 (name, label) vs 32 (value) will break comparison.
|
239
|
-
# convert string to binary and remove 160.
|
240
|
-
# \xC2\xA0
|
241
|
-
s.force_encoding('binary').gsub("\xC2\xA0".force_encoding('binary'), ' ') if s
|
242
|
-
end
|
243
|
-
|
244
|
-
if ! empty( element )
|
245
|
-
puts "#{element['type']}"
|
246
|
-
name = fix_space element['name']
|
247
|
-
label = fix_space element['label']
|
248
|
-
value = fix_space element['value']
|
249
|
-
|
250
|
-
if name == label && name == value
|
251
|
-
puts " name, label, value: #{name}" if name
|
252
|
-
elsif name == label
|
253
|
-
puts " name, label: #{name}" if name
|
254
|
-
puts " value: #{value}" if value
|
255
|
-
elsif name == value
|
256
|
-
puts " name, value: #{name}" if name
|
257
|
-
puts " label: #{label}" if label
|
258
|
-
else
|
259
|
-
puts " name: #{name}" if name
|
260
|
-
puts " label: #{label}" if label
|
261
|
-
puts " value: #{value}" if value
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
children = element['children']
|
266
|
-
children.each { |c| page c } if children
|
267
|
-
nil
|
268
|
-
end if $os == :ios
|
269
|
-
|
270
|
-
# JavaScript code from https://github.com/appium/appium/blob/master/app/android.js
|
271
|
-
#
|
272
|
-
# Math.round((duration * 1000) / 200)
|
273
|
-
# (.20 * 1000) / 200 = 1
|
274
|
-
#
|
275
|
-
# We want steps to be exactly 1. If it's zero then a tap is used instead of a swipe.
|
276
|
-
def fast_duration
|
277
|
-
0.20
|
278
|
-
end
|
data/lib/appium_lib/patch.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
# Implement useful features for element.
|
2
|
-
class Selenium::WebDriver::Element
|
3
|
-
# Note: For testing .text should be used over value, and name.
|
4
|
-
|
5
|
-
# Fixes NoMethodError: undefined method `value' for #<Selenium::WebDriver::Element:0x..fa4a9148235390a44 id="1">
|
6
|
-
def value
|
7
|
-
self.attribute :value
|
8
|
-
end
|
9
|
-
|
10
|
-
# Fixes NoMethodError: undefined method `name' for #<Selenium::WebDriver::Element
|
11
|
-
def name
|
12
|
-
self.attribute :name
|
13
|
-
end
|
14
|
-
|
15
|
-
# Use tag_name to get element's type.
|
16
|
-
#
|
17
|
-
# Tag name appears to be the same as type.
|
18
|
-
#
|
19
|
-
# Fixes Selenium::WebDriver::Error::UnknownError: Not yet implemented
|
20
|
-
def tag_name
|
21
|
-
self.attribute :type
|
22
|
-
end
|
23
|
-
|
24
|
-
# Cross platform way of entering text into a textfield
|
25
|
-
def type text
|
26
|
-
# enter text then tap window to hide the keyboard.
|
27
|
-
js = %Q(
|
28
|
-
au.getElement('#{self.ref}').setValue('#{text}');
|
29
|
-
au.lookup('window')[0].tap()
|
30
|
-
)
|
31
|
-
$driver.execute_script js
|
32
|
-
end if $os == :ios
|
33
|
-
|
34
|
-
# Cross platform way of entering text into a textfield
|
35
|
-
def type text
|
36
|
-
self.send_keys text
|
37
|
-
end if $os == :android
|
38
|
-
|
39
|
-
# For use with mobile tap.
|
40
|
-
#
|
41
|
-
# $driver.execute_script 'mobile: tap', :x => 0.0, :y => 0.98
|
42
|
-
#
|
43
|
-
# https://github.com/appium/appium/wiki/Automating-mobile-gestures
|
44
|
-
# @return [OpenStruct] the relative x, y in a struct. ex: { x: 0.50, y: 0.20 }
|
45
|
-
def location_rel
|
46
|
-
xy = self.location
|
47
|
-
w = window_size
|
48
|
-
OpenStruct.new( x: xy.x.to_f / w.width.to_f,
|
49
|
-
y: xy.y.to_f / w.height.to_f )
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# Print JSON posted to Appium
|
54
|
-
#
|
55
|
-
# Requires from lib/selenium/webdriver/remote.rb
|
56
|
-
require 'selenium/webdriver/remote/capabilities'
|
57
|
-
require 'selenium/webdriver/remote/bridge'
|
58
|
-
require 'selenium/webdriver/remote/server_error'
|
59
|
-
require 'selenium/webdriver/remote/response'
|
60
|
-
require 'selenium/webdriver/remote/commands'
|
61
|
-
require 'selenium/webdriver/remote/http/common'
|
62
|
-
require 'selenium/webdriver/remote/http/default'
|
63
|
-
|
64
|
-
# Show http calls to the Selenium server.
|
65
|
-
#
|
66
|
-
# Invaluable for debugging.
|
67
|
-
module Selenium::WebDriver::Remote
|
68
|
-
class Bridge
|
69
|
-
# Code from lib/selenium/webdriver/remote/bridge.rb
|
70
|
-
def raw_execute(command, opts = {}, command_hash = nil)
|
71
|
-
verb, path = COMMANDS[command] || raise(ArgumentError, "unknown command: #{command.inspect}")
|
72
|
-
path = path.dup
|
73
|
-
|
74
|
-
path[':session_id'] = @session_id if path.include?(":session_id")
|
75
|
-
|
76
|
-
begin
|
77
|
-
opts.each { |key, value| path[key.inspect] = escaper.escape(value.to_s) }
|
78
|
-
rescue IndexError
|
79
|
-
raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
|
80
|
-
end
|
81
|
-
|
82
|
-
puts verb
|
83
|
-
puts path
|
84
|
-
puts command_hash.to_json
|
85
|
-
|
86
|
-
puts "-> #{verb.to_s.upcase} #{path}" if $DEBUG
|
87
|
-
http.call verb, path, command_hash
|
88
|
-
end # def
|
89
|
-
end # class
|
90
|
-
end if defined?(Pry)# module
|
data/lib/appium_lib/version.rb
DELETED