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
@@ -1,5 +1,4 @@
|
|
1
1
|
module Appium
|
2
|
-
|
3
2
|
# MultiTouch actions allow for multiple touches to happen at the same time,
|
4
3
|
# for instance, to simulate multiple finger swipes.
|
5
4
|
#
|
@@ -17,7 +16,6 @@ module Appium
|
|
17
16
|
# multi_touch_action.perform
|
18
17
|
class MultiTouch
|
19
18
|
class << self
|
20
|
-
|
21
19
|
# Convenience method for pinching the screen.
|
22
20
|
# Places two fingers at the edges of the screen and brings them together.
|
23
21
|
# @param percentage (int) The percent size by which to shrink the screen when pinched.
|
@@ -27,8 +25,8 @@ module Appium
|
|
27
25
|
# action = pinch 75 #=> Pinch the screen from the top right and bottom left corners
|
28
26
|
# action.perform #=> to 25% of its size.
|
29
27
|
# ```
|
30
|
-
def pinch(percentage=25, auto_perform=true)
|
31
|
-
|
28
|
+
def pinch(percentage = 25, auto_perform = true)
|
29
|
+
fail ArgumentError("Can't pinch to greater than screen size.") if percentage > 100
|
32
30
|
|
33
31
|
p = Float(percentage) / 100
|
34
32
|
i = 1 - p
|
@@ -55,8 +53,8 @@ module Appium
|
|
55
53
|
# action = zoom 200 #=> Zoom in the screen from the center until it doubles in size.
|
56
54
|
# action.perform
|
57
55
|
# ```
|
58
|
-
def zoom(percentage=200, auto_perform=true)
|
59
|
-
|
56
|
+
def zoom(percentage = 200, auto_perform = true)
|
57
|
+
fail ArgumentError("Can't zoom to smaller then screen size.") if percentage < 100
|
60
58
|
|
61
59
|
p = 100 / Float(percentage)
|
62
60
|
i = 1 - p
|
@@ -91,4 +89,4 @@ module Appium
|
|
91
89
|
$driver.multi_touch @actions
|
92
90
|
end
|
93
91
|
end # class MultiTouch
|
94
|
-
end # module Appium
|
92
|
+
end # module Appium
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module Appium
|
2
|
-
|
3
2
|
# Perform a series of gestures, one after another. Gestures are chained
|
4
3
|
# together and only performed when `perform()` is called.
|
5
4
|
#
|
@@ -15,7 +14,7 @@ module Appium
|
|
15
14
|
class << self
|
16
15
|
COMPLEX_ACTIONS.each do |action|
|
17
16
|
define_method(action) do |opts|
|
18
|
-
auto_perform = opts.delete(:auto_perform) { |
|
17
|
+
auto_perform = opts.delete(:auto_perform) { |_k| true }
|
19
18
|
ta = TouchAction.new
|
20
19
|
ta.send(action, opts)
|
21
20
|
return ta unless auto_perform
|
@@ -45,7 +44,7 @@ module Appium
|
|
45
44
|
# @option y [integer] y co-ordinate to press on.
|
46
45
|
# @option duration [integer] Number of milliseconds to press.
|
47
46
|
def long_press(opts)
|
48
|
-
args = opts.select { |k,
|
47
|
+
args = opts.select { |k, _v| [:element, :x, :y, :duration].include? k }
|
49
48
|
args = args_with_ele_ref(args)
|
50
49
|
chain_method(:longPress, args) # longPress is what the appium server expects
|
51
50
|
end
|
@@ -57,7 +56,7 @@ module Appium
|
|
57
56
|
# @option opts [integer] :x x co-ordinate to press on
|
58
57
|
# @option opts [integer] :y y co-ordinate to press on
|
59
58
|
def press(opts)
|
60
|
-
args = opts.select { |k,
|
59
|
+
args = opts.select { |k, _v| [:element, :x, :y].include? k }
|
61
60
|
args = args_with_ele_ref(args)
|
62
61
|
chain_method(:press, args)
|
63
62
|
end
|
@@ -67,7 +66,7 @@ module Appium
|
|
67
66
|
# @option opts [WebDriver::Element] :element (Optional) Element to release from.
|
68
67
|
# @option opts [integer] :x x co-ordinate to release from
|
69
68
|
# @option opts [integer] :y y co-ordinate to release from
|
70
|
-
def release(opts=nil)
|
69
|
+
def release(opts = nil)
|
71
70
|
args = args_with_ele_ref(opts) if opts
|
72
71
|
chain_method(:release, args)
|
73
72
|
end
|
@@ -79,9 +78,9 @@ module Appium
|
|
79
78
|
# @option opts [integer] :y y co-ordinate to tap
|
80
79
|
# @option opts [integer] :fingers how many fingers to tap with (Default 1)
|
81
80
|
def tap(opts)
|
82
|
-
opts[:count]
|
83
|
-
|
84
|
-
args
|
81
|
+
opts[:count] = opts.delete(:fingers) if opts[:fingers]
|
82
|
+
opts[:count] ||= 1
|
83
|
+
args = args_with_ele_ref opts
|
85
84
|
chain_method(:tap, args)
|
86
85
|
end
|
87
86
|
|
@@ -108,10 +107,10 @@ module Appium
|
|
108
107
|
end_y = opts.fetch :end_y, 0
|
109
108
|
duration = opts[:duration]
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
110
|
+
press x: start_x, y: start_y
|
111
|
+
wait(duration) if duration
|
112
|
+
move_to x: end_x, y: end_y
|
113
|
+
release
|
115
114
|
self
|
116
115
|
end
|
117
116
|
|
@@ -130,7 +129,7 @@ module Appium
|
|
130
129
|
|
131
130
|
private
|
132
131
|
|
133
|
-
def chain_method(method, args=nil)
|
132
|
+
def chain_method(method, args = nil)
|
134
133
|
if args
|
135
134
|
@actions << { action: method, options: args }
|
136
135
|
else
|
@@ -140,8 +139,8 @@ module Appium
|
|
140
139
|
end
|
141
140
|
|
142
141
|
def args_with_ele_ref(args)
|
143
|
-
args[:element] = args[:element].ref if args.
|
142
|
+
args[:element] = args[:element].ref if args.key? :element
|
144
143
|
args
|
145
144
|
end
|
146
145
|
end # class TouchAction
|
147
|
-
end # module Appium
|
146
|
+
end # module Appium
|
data/lib/appium_lib/driver.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'ap'
|
3
3
|
require 'selenium-webdriver'
|
4
|
+
require 'selenium/client/errors' # used in helper.rb for CommandError
|
4
5
|
require 'nokogiri'
|
5
6
|
|
6
7
|
# common
|
@@ -66,29 +67,29 @@ module Appium
|
|
66
67
|
#
|
67
68
|
# @param opts [Hash] file: '/path/to/appium.txt', verbose: true
|
68
69
|
# @return [hash] the symbolized hash with updated :app and :require keys
|
69
|
-
def self.load_appium_txt
|
70
|
-
|
71
|
-
|
70
|
+
def self.load_appium_txt(opts = {})
|
71
|
+
fail 'opts must be a hash' unless opts.is_a? Hash
|
72
|
+
fail 'opts must not be empty' if opts.empty?
|
72
73
|
|
73
74
|
file = opts[:file]
|
74
|
-
|
75
|
+
fail 'Must pass file' unless file
|
75
76
|
verbose = opts.fetch :verbose, false
|
76
77
|
|
77
78
|
parent_dir = File.dirname file
|
78
79
|
toml = File.expand_path File.join parent_dir, 'appium.txt'
|
79
80
|
Appium::Logger.info "appium.txt path: #{toml}" if verbose
|
80
81
|
|
81
|
-
toml_exists = File.
|
82
|
+
toml_exists = File.exist? toml
|
82
83
|
Appium::Logger.info "Exists? #{toml_exists}" if verbose
|
83
84
|
|
84
|
-
|
85
|
+
fail "toml doesn't exist #{toml}" unless toml_exists
|
85
86
|
require 'toml'
|
86
87
|
Appium::Logger.info "Loading #{toml}" if verbose
|
87
88
|
|
88
89
|
data = File.read toml
|
89
90
|
data = TOML::Parser.new(data).parsed
|
90
91
|
# TOML creates string keys. must symbolize
|
91
|
-
data = Appium
|
92
|
+
data = Appium.symbolize_keys data
|
92
93
|
Appium::Logger.ap_info data unless data.empty? if verbose
|
93
94
|
|
94
95
|
if data && data[:caps] && data[:caps][:app] && !data[:caps][:app].empty?
|
@@ -99,14 +100,13 @@ module Appium
|
|
99
100
|
# nil if require doesn't exist
|
100
101
|
if data && data[:appium_lib] && data[:appium_lib][:require]
|
101
102
|
r = data[:appium_lib][:require]
|
102
|
-
r = r.
|
103
|
+
r = r.is_a?(Array) ? r : [r]
|
103
104
|
# ensure files are absolute
|
104
|
-
r.map! do |
|
105
|
-
file = File.
|
106
|
-
File.join(parent_dir, file)
|
105
|
+
r.map! do |f|
|
106
|
+
file = File.exist?(f) ? f : File.join(parent_dir, f)
|
107
107
|
file = File.expand_path file
|
108
108
|
|
109
|
-
File.
|
109
|
+
File.exist?(file) ? file : nil
|
110
110
|
end
|
111
111
|
r.compact! # remove nils
|
112
112
|
|
@@ -119,9 +119,9 @@ module Appium
|
|
119
119
|
files << item
|
120
120
|
next # only look inside folders
|
121
121
|
end
|
122
|
-
Dir.glob(File.expand_path(File.join(item, '**', '*.rb'))) do |
|
122
|
+
Dir.glob(File.expand_path(File.join(item, '**', '*.rb'))) do |f|
|
123
123
|
# do not add folders to the file list
|
124
|
-
files << File.expand_path(
|
124
|
+
files << File.expand_path(f) unless File.directory? f
|
125
125
|
end
|
126
126
|
end
|
127
127
|
|
@@ -136,21 +136,29 @@ module Appium
|
|
136
136
|
#
|
137
137
|
# based on deep_symbolize_keys & deep_transform_keys from rails
|
138
138
|
# https://github.com/rails/docrails/blob/a3b1105ada3da64acfa3843b164b14b734456a50/activesupport/lib/active_support/core_ext/hash/keys.rb#L84
|
139
|
-
def self.symbolize_keys
|
140
|
-
|
139
|
+
def self.symbolize_keys(hash)
|
140
|
+
fail 'symbolize_keys requires a hash' unless hash.is_a? Hash
|
141
141
|
result = {}
|
142
142
|
hash.each do |key, value|
|
143
|
-
key = key.to_sym rescue key
|
143
|
+
key = key.to_sym rescue key # rubocop:disable Style/RescueModifier
|
144
144
|
result[key] = value.is_a?(Hash) ? symbolize_keys(value) : value
|
145
145
|
end
|
146
146
|
result
|
147
147
|
end
|
148
148
|
|
149
|
+
# This method is intended to work with page objects that share
|
150
|
+
# a common module. For example, Page::HomePage, Page::SignIn
|
151
|
+
# those could be promoted on with Appium.promote_singleton_appium_methods Page
|
152
|
+
#
|
153
|
+
# If you are promoting on an individual class then you should use
|
154
|
+
# Appium.promote_appium_methods instead. The singleton method is intended
|
155
|
+
# only for the shared module use case.
|
156
|
+
#
|
149
157
|
# if modules is a module instead of an array, then the constants of
|
150
158
|
# that module are promoted on.
|
151
159
|
# otherwise, the array of modules will be used as the promotion target.
|
152
|
-
def self.promote_singleton_appium_methods
|
153
|
-
|
160
|
+
def self.promote_singleton_appium_methods(modules)
|
161
|
+
fail 'Driver is nil' if $driver.nil?
|
154
162
|
|
155
163
|
target_modules = []
|
156
164
|
|
@@ -159,12 +167,12 @@ module Appium
|
|
159
167
|
target_modules << modules.const_get(sub_module)
|
160
168
|
end
|
161
169
|
else
|
162
|
-
|
170
|
+
fail 'modules must be a module or an array' unless modules.is_a? Array
|
163
171
|
target_modules = modules
|
164
172
|
end
|
165
173
|
|
166
174
|
target_modules.each do |const|
|
167
|
-
#noinspection RubyResolve
|
175
|
+
# noinspection RubyResolve
|
168
176
|
$driver.public_methods(false).each do |m|
|
169
177
|
const.send(:define_singleton_method, m) do |*args, &block|
|
170
178
|
begin
|
@@ -173,8 +181,7 @@ module Appium
|
|
173
181
|
$driver.send m, *args, &block if $driver.respond_to?(m)
|
174
182
|
end
|
175
183
|
# override unless there's an existing method with matching arity
|
176
|
-
end unless const.respond_to?(m) &&
|
177
|
-
const.method(m).arity == $driver.method(m).arity
|
184
|
+
end unless const.respond_to?(m) && const.method(m).arity == $driver.method(m).arity
|
178
185
|
end
|
179
186
|
end
|
180
187
|
end
|
@@ -189,8 +196,20 @@ module Appium
|
|
189
196
|
# ```ruby
|
190
197
|
# Appium.promote_appium_methods Object
|
191
198
|
# ```
|
192
|
-
|
193
|
-
|
199
|
+
#
|
200
|
+
# It's better to promote on specific classes instead of Object
|
201
|
+
#
|
202
|
+
# ```ruby
|
203
|
+
# # promote on rspec
|
204
|
+
# Appium.promote_appium_methods RSpec::Core::ExampleGroup
|
205
|
+
# ```
|
206
|
+
#
|
207
|
+
# ```ruby
|
208
|
+
# # promote on minispec
|
209
|
+
# Appium.promote_appium_methods Minitest::Spec
|
210
|
+
# ```
|
211
|
+
def self.promote_appium_methods(class_array)
|
212
|
+
fail 'Driver is nil' if $driver.nil?
|
194
213
|
# Wrap single class into an array
|
195
214
|
class_array = [class_array] unless class_array.class == Array
|
196
215
|
# Promote Appium driver methods to class instance methods.
|
@@ -202,9 +221,10 @@ module Appium
|
|
202
221
|
# Prefer existing method.
|
203
222
|
# super will invoke method missing on driver
|
204
223
|
super(*args, &block)
|
205
|
-
|
206
|
-
|
207
|
-
|
224
|
+
|
225
|
+
# minitest also defines a name method,
|
226
|
+
# so rescue argument error
|
227
|
+
# and call the name method on $driver
|
208
228
|
rescue NoMethodError, ArgumentError
|
209
229
|
$driver.send m, *args, &block if $driver.respond_to?(m)
|
210
230
|
end
|
@@ -216,14 +236,11 @@ module Appium
|
|
216
236
|
end
|
217
237
|
|
218
238
|
class Driver
|
219
|
-
@@loaded = false
|
220
|
-
|
221
239
|
# attr readers are promoted to global scope. To avoid clobbering, they're
|
222
240
|
# made available via the driver_attributes method
|
223
241
|
#
|
224
242
|
# attr_accessor is repeated for each one so YARD documents them properly.
|
225
243
|
|
226
|
-
|
227
244
|
# The amount to sleep in seconds before every webdriver http call.
|
228
245
|
attr_accessor :global_webdriver_http_sleep
|
229
246
|
# Selenium webdriver capabilities
|
@@ -233,6 +250,9 @@ module Appium
|
|
233
250
|
# Export session id to textfile in /tmp for 3rd party tools
|
234
251
|
attr_accessor :export_session
|
235
252
|
# Default wait time for elements to appear
|
253
|
+
# Returns the default client side wait.
|
254
|
+
# This value is independent of what the server is using
|
255
|
+
# @return [Integer]
|
236
256
|
attr_accessor :default_wait
|
237
257
|
# Array of previous wait time values
|
238
258
|
attr_accessor :last_waits
|
@@ -247,6 +267,10 @@ module Appium
|
|
247
267
|
# Boolean debug mode for the Appium Ruby bindings
|
248
268
|
attr_accessor :appium_debug
|
249
269
|
|
270
|
+
# Returns the driver
|
271
|
+
# @return [Driver] the driver
|
272
|
+
attr_reader :driver
|
273
|
+
|
250
274
|
# Creates a new driver
|
251
275
|
#
|
252
276
|
# ```ruby
|
@@ -266,12 +290,12 @@ module Appium
|
|
266
290
|
#
|
267
291
|
# @param opts [Object] A hash containing various options.
|
268
292
|
# @return [Driver]
|
269
|
-
def initialize
|
293
|
+
def initialize(opts = {})
|
270
294
|
# quit last driver
|
271
295
|
$driver.driver_quit if $driver
|
272
|
-
|
296
|
+
fail 'opts must be a hash' unless opts.is_a? Hash
|
273
297
|
|
274
|
-
opts = Appium
|
298
|
+
opts = Appium.symbolize_keys opts
|
275
299
|
|
276
300
|
# default to {} to prevent nil.fetch and other nil errors
|
277
301
|
@caps = opts[:caps] || {}
|
@@ -280,7 +304,7 @@ module Appium
|
|
280
304
|
# appium_lib specific values
|
281
305
|
@custom_url = appium_lib_opts.fetch :server_url, false
|
282
306
|
@export_session = appium_lib_opts.fetch :export_session, false
|
283
|
-
@default_wait = appium_lib_opts.fetch :wait,
|
307
|
+
@default_wait = appium_lib_opts.fetch :wait, 0
|
284
308
|
@last_waits = [@default_wait]
|
285
309
|
@sauce_username = appium_lib_opts.fetch :sauce_username, ENV['SAUCE_USERNAME']
|
286
310
|
@sauce_username = nil if !@sauce_username || (@sauce_username.is_a?(String) && @sauce_username.empty?)
|
@@ -297,8 +321,8 @@ module Appium
|
|
297
321
|
# https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile
|
298
322
|
@appium_device = @caps[:platformName]
|
299
323
|
@appium_device = @appium_device.is_a?(Symbol) ? @appium_device : @appium_device.downcase.strip.intern if @appium_device
|
300
|
-
|
301
|
-
|
324
|
+
fail "platformName must be set. Not found in options: #{opts}" unless @appium_device
|
325
|
+
fail 'platformName must be Android or iOS' unless [:android, :ios].include?(@appium_device)
|
302
326
|
|
303
327
|
# load common methods
|
304
328
|
extend Appium::Common
|
@@ -325,18 +349,9 @@ module Appium
|
|
325
349
|
patch_webdriver_bridge
|
326
350
|
end
|
327
351
|
|
328
|
-
|
329
352
|
# Save global reference to last created Appium driver for top level methods.
|
330
353
|
$driver = self
|
331
354
|
|
332
|
-
# Promote exactly once the first time the driver is created.
|
333
|
-
# Subsequent drivers do not trigger promotion.
|
334
|
-
unless @@loaded
|
335
|
-
@@loaded = true
|
336
|
-
# Promote only on Minitest::Spec (minitest 5) by default
|
337
|
-
Appium.promote_appium_methods ::Minitest::Spec
|
338
|
-
end
|
339
|
-
|
340
355
|
self # return newly created driver
|
341
356
|
end
|
342
357
|
|
@@ -351,7 +366,7 @@ module Appium
|
|
351
366
|
sauce_access_key: @sauce_access_key,
|
352
367
|
port: @appium_port,
|
353
368
|
device: @appium_device,
|
354
|
-
debug: @appium_debug
|
369
|
+
debug: @appium_debug
|
355
370
|
}
|
356
371
|
|
357
372
|
# Return duplicates so attributes are immutable
|
@@ -389,14 +404,14 @@ module Appium
|
|
389
404
|
# if app isn't set then an error is raised.
|
390
405
|
#
|
391
406
|
# @return [String] APP_PATH as an absolute path
|
392
|
-
def self.absolute_app_path
|
393
|
-
|
407
|
+
def self.absolute_app_path(opts)
|
408
|
+
fail 'opts must be a hash' unless opts.is_a? Hash
|
394
409
|
caps = opts[:caps] || {}
|
395
410
|
appium_lib_opts = opts[:appium_lib] || {}
|
396
411
|
server_url = appium_lib_opts.fetch :server_url, false
|
397
412
|
|
398
413
|
app_path = caps[:app]
|
399
|
-
|
414
|
+
fail 'absolute_app_path invoked and app is not set!' if app_path.nil? || app_path.empty?
|
400
415
|
# may be absolute path to file on remote server.
|
401
416
|
# if the file is on the remote server then we can't check if it exists
|
402
417
|
return app_path if server_url
|
@@ -405,7 +420,7 @@ module Appium
|
|
405
420
|
return app_path if app_path.match(/^http/) # public URL for Sauce
|
406
421
|
if app_path.match(/^(\/|[a-zA-Z]:)/) # absolute file path
|
407
422
|
app_path = File.expand_path app_path unless File.exist? app_path
|
408
|
-
|
423
|
+
fail "App doesn't exist. #{app_path}" unless File.exist? app_path
|
409
424
|
return app_path
|
410
425
|
end
|
411
426
|
|
@@ -416,7 +431,7 @@ module Appium
|
|
416
431
|
# absolute_app_path is called from load_appium_txt
|
417
432
|
# and the txt file path is the base of the app path in that case.
|
418
433
|
app_path = File.expand_path app_path
|
419
|
-
|
434
|
+
fail "App doesn't exist #{app_path}" unless File.exist? app_path
|
420
435
|
app_path
|
421
436
|
end
|
422
437
|
|
@@ -438,19 +453,13 @@ module Appium
|
|
438
453
|
start_driver
|
439
454
|
end
|
440
455
|
|
441
|
-
# Returns the driver
|
442
|
-
# @return [Driver] the driver
|
443
|
-
def driver
|
444
|
-
@driver
|
445
|
-
end
|
446
|
-
|
447
456
|
# Takes a png screenshot and saves to the target path.
|
448
457
|
#
|
449
458
|
# Example: screenshot '/tmp/hi.png'
|
450
459
|
#
|
451
460
|
# @param png_save_path [String] the full path to save the png
|
452
461
|
# @return [nil]
|
453
|
-
def screenshot
|
462
|
+
def screenshot(png_save_path)
|
454
463
|
@driver.save_screenshot png_save_path
|
455
464
|
nil
|
456
465
|
end
|
@@ -459,6 +468,7 @@ module Appium
|
|
459
468
|
# @return [void]
|
460
469
|
def driver_quit
|
461
470
|
# rescue NoSuchDriverError or nil driver
|
471
|
+
# rubocop:disable Style/RescueModifier
|
462
472
|
@driver.quit rescue nil
|
463
473
|
end
|
464
474
|
|
@@ -466,17 +476,19 @@ module Appium
|
|
466
476
|
#
|
467
477
|
# @return [Selenium::WebDriver] the new global driver
|
468
478
|
def start_driver
|
469
|
-
@client
|
470
|
-
@client.timeout =
|
479
|
+
@client ||= Selenium::WebDriver::Remote::Http::Default.new
|
480
|
+
@client.timeout = 999_999
|
471
481
|
|
472
482
|
begin
|
473
483
|
driver_quit
|
474
484
|
@driver = Selenium::WebDriver.for :remote, http_client: @client, desired_capabilities: @caps, url: server_url
|
475
485
|
# Load touch methods.
|
476
486
|
@driver.extend Selenium::WebDriver::DriverExtensions::HasTouchScreen
|
487
|
+
@driver.extend Selenium::WebDriver::DriverExtensions::HasLocation
|
477
488
|
|
478
489
|
# export session
|
479
490
|
if @export_session
|
491
|
+
# rubocop:disable Style/RescueModifier
|
480
492
|
File.open('/tmp/appium_lib_session', 'w') do |f|
|
481
493
|
f.puts @driver.session_id
|
482
494
|
end rescue nil
|
@@ -510,7 +522,7 @@ module Appium
|
|
510
522
|
#
|
511
523
|
# @param timeout [Integer] the timeout in seconds
|
512
524
|
# @return [void]
|
513
|
-
def set_wait
|
525
|
+
def set_wait(timeout = nil)
|
514
526
|
if timeout.nil?
|
515
527
|
# Appium::Logger.info "timeout = @default_wait = @last_wait"
|
516
528
|
# Appium::Logger.info "timeout = @default_wait = #{@last_waits}"
|
@@ -525,13 +537,6 @@ module Appium
|
|
525
537
|
@driver.manage.timeouts.implicit_wait = timeout
|
526
538
|
end
|
527
539
|
|
528
|
-
# Returns the default client side wait.
|
529
|
-
# This value is independent of what the server is using
|
530
|
-
# @return [Integer]
|
531
|
-
def default_wait
|
532
|
-
@default_wait
|
533
|
-
end
|
534
|
-
|
535
540
|
# Returns existence of element.
|
536
541
|
#
|
537
542
|
# Example:
|
@@ -544,7 +549,7 @@ module Appium
|
|
544
549
|
# wait to after checking existance
|
545
550
|
# @param search_block [Block] the block to call
|
546
551
|
# @return [Boolean]
|
547
|
-
def exists
|
552
|
+
def exists(pre_check = 0, post_check = @default_wait, &search_block)
|
548
553
|
# do not uset set_wait here.
|
549
554
|
# it will cause problems with other methods reading the default_wait of 0
|
550
555
|
# which then gets converted to a 1 second wait.
|
@@ -568,7 +573,7 @@ module Appium
|
|
568
573
|
# @param script [String] the script to execute
|
569
574
|
# @param args [*args] the args to pass to the script
|
570
575
|
# @return [Object]
|
571
|
-
def execute_script
|
576
|
+
def execute_script(script, *args)
|
572
577
|
@driver.execute_script script, *args
|
573
578
|
end
|
574
579
|
|
@@ -576,16 +581,32 @@ module Appium
|
|
576
581
|
#
|
577
582
|
# @param args [*args] the args to use
|
578
583
|
# @return [Array<Element>] Array is empty when no elements are found.
|
579
|
-
def find_elements
|
580
|
-
@driver.find_elements
|
584
|
+
def find_elements(*args)
|
585
|
+
@driver.find_elements(*args)
|
581
586
|
end
|
582
587
|
|
583
588
|
# Calls @driver.find_elements
|
584
589
|
#
|
585
590
|
# @param args [*args] the args to use
|
586
591
|
# @return [Element]
|
587
|
-
def find_element
|
588
|
-
@driver.find_element
|
592
|
+
def find_element(*args)
|
593
|
+
@driver.find_element(*args)
|
594
|
+
end
|
595
|
+
|
596
|
+
# Calls @driver.set_location
|
597
|
+
#
|
598
|
+
# @note This method does not work on real devices.
|
599
|
+
#
|
600
|
+
# @param [Hash] opts consisting of:
|
601
|
+
# @option opts [Float] :latitude the latitude in degrees (required)
|
602
|
+
# @option opts [Float] :longitude the longitude in degees (required)
|
603
|
+
# @option opts [Float] :altitude the altitude, defaulting to 75
|
604
|
+
# @return [Selenium::WebDriver::Location] the location constructed by the selenium webdriver
|
605
|
+
def set_location(opts = {})
|
606
|
+
latitude = opts.fetch(:latitude)
|
607
|
+
longitude = opts.fetch(:longitude)
|
608
|
+
altitude = opts.fetch(:altitude, 75)
|
609
|
+
@driver.set_location(latitude, longitude, altitude)
|
589
610
|
end
|
590
611
|
|
591
612
|
# Quit the driver and Pry.
|
@@ -601,4 +622,4 @@ end # module Appium
|
|
601
622
|
# Paging in Pry is annoying :q required to exit.
|
602
623
|
# With pager disabled, the output is similar to IRB
|
603
624
|
# Only set if Pry is defined.
|
604
|
-
Pry.config.pager = false if defined?(Pry)
|
625
|
+
Pry.config.pager = false if defined?(Pry)
|