appium_lib 6.0.0 → 7.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/.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)
|