appium_lib_core 4.1.0 → 5.5.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/CHANGELOG.md +158 -275
- data/README.md +13 -8
- data/Rakefile +4 -0
- data/appium_lib_core.gemspec +5 -8
- data/bin/console +0 -4
- data/lib/appium_lib_core/android/device/auth_finger_print.rb +2 -1
- data/lib/appium_lib_core/android/device.rb +4 -4
- data/lib/appium_lib_core/common/base/bridge.rb +291 -92
- data/lib/appium_lib_core/common/base/capabilities.rb +8 -9
- data/lib/appium_lib_core/common/base/device_ime.rb +49 -0
- data/lib/appium_lib_core/common/base/driver.rb +225 -187
- data/lib/appium_lib_core/common/base/driver_settings.rb +51 -0
- data/lib/appium_lib_core/common/base/has_location.rb +80 -0
- data/lib/appium_lib_core/common/base/has_network_connection.rb +56 -0
- data/lib/appium_lib_core/common/base/http_default.rb +1 -3
- data/lib/appium_lib_core/common/base/remote_status.rb +31 -0
- data/lib/appium_lib_core/common/base/rotable.rb +54 -0
- data/lib/appium_lib_core/common/base/screenshot.rb +6 -6
- data/lib/appium_lib_core/common/base/search_context.rb +20 -5
- data/lib/appium_lib_core/common/base.rb +1 -3
- data/lib/appium_lib_core/common/command.rb +255 -4
- data/lib/appium_lib_core/common/device/app_management.rb +2 -14
- data/lib/appium_lib_core/common/device/image_comparison.rb +12 -4
- data/lib/appium_lib_core/common/device/keyevent.rb +4 -4
- data/lib/appium_lib_core/common/{command/mjsonwp.rb → device/orientation.rb} +14 -11
- data/lib/appium_lib_core/common/device/touch_actions.rb +2 -0
- data/lib/appium_lib_core/common/device/value.rb +6 -6
- data/lib/appium_lib_core/common/error.rb +4 -1
- data/lib/appium_lib_core/common/log.rb +4 -1
- data/lib/appium_lib_core/common/touch_action/multi_touch.rb +19 -0
- data/lib/appium_lib_core/common/touch_action/touch_actions.rb +16 -2
- data/lib/appium_lib_core/common/wait.rb +38 -6
- data/lib/appium_lib_core/device.rb +1 -5
- data/lib/appium_lib_core/driver.rb +41 -75
- data/lib/appium_lib_core/{patch.rb → element.rb} +66 -9
- data/lib/appium_lib_core/ios/uiautomation/patch.rb +1 -1
- data/lib/appium_lib_core/{common/base/command.rb → mac2/bridge.rb} +9 -8
- data/lib/appium_lib_core/mac2/device/screen.rb +48 -0
- data/lib/appium_lib_core/mac2/device.rb +92 -0
- data/lib/appium_lib_core/mac2.rb +17 -0
- data/lib/appium_lib_core/version.rb +2 -2
- data/lib/appium_lib_core.rb +2 -5
- metadata +29 -82
- data/.github/ISSUE_TEMPLATE/issue-report.md +0 -29
- data/.github/contributing.md +0 -26
- data/.github/issue_template.md +0 -20
- data/.github/workflows/unittest.yml +0 -68
- data/.gitignore +0 -18
- data/.rubocop.yml +0 -58
- data/azure-pipelines.yml +0 -15
- data/ci-jobs/functional/android_setup.yml +0 -3
- data/ci-jobs/functional/ios_setup.yml +0 -7
- data/ci-jobs/functional/publish_test_result.yml +0 -18
- data/ci-jobs/functional/run_appium.yml +0 -25
- data/ci-jobs/functional/start-emulator.sh +0 -26
- data/ci-jobs/functional_test.yml +0 -298
- data/docs/mobile_command.md +0 -34
- data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +0 -81
- data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -252
- data/lib/appium_lib_core/common/command/common.rb +0 -110
- data/lib/appium_lib_core/common/command/w3c.rb +0 -56
- data/release_notes.md +0 -816
- data/script/commands.rb +0 -200
@@ -13,8 +13,15 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
require 'base64'
|
16
|
+
require_relative 'device_ime'
|
17
|
+
require_relative 'driver_settings'
|
16
18
|
require_relative 'search_context'
|
17
19
|
require_relative 'screenshot'
|
20
|
+
require_relative 'rotable'
|
21
|
+
require_relative 'remote_status'
|
22
|
+
require_relative 'has_location'
|
23
|
+
require_relative 'has_network_connection'
|
24
|
+
require_relative '../wait'
|
18
25
|
|
19
26
|
module Appium
|
20
27
|
module Core
|
@@ -22,42 +29,56 @@ module Appium
|
|
22
29
|
class Driver < ::Selenium::WebDriver::Driver
|
23
30
|
include ::Selenium::WebDriver::DriverExtensions::UploadsFiles
|
24
31
|
include ::Selenium::WebDriver::DriverExtensions::HasSessionId
|
25
|
-
include ::Selenium::WebDriver::DriverExtensions::Rotatable
|
26
|
-
include ::Selenium::WebDriver::DriverExtensions::HasRemoteStatus
|
27
32
|
include ::Selenium::WebDriver::DriverExtensions::HasWebStorage
|
28
33
|
|
34
|
+
include ::Appium::Core::Base::Rotatable
|
29
35
|
include ::Appium::Core::Base::SearchContext
|
30
|
-
include ::Appium::Core::Base::
|
36
|
+
include ::Appium::Core::Base::TakesScreenshot
|
37
|
+
include ::Appium::Core::Base::HasRemoteStatus
|
38
|
+
include ::Appium::Core::Base::HasLocation
|
39
|
+
include ::Appium::Core::Base::HasNetworkConnection
|
40
|
+
|
41
|
+
include ::Appium::Core::Waitable
|
31
42
|
|
32
43
|
# Private API.
|
33
44
|
# Do not use this for general use. Used by flutter driver to get bridge for creating a new element
|
34
45
|
attr_reader :bridge
|
35
46
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
49
|
-
super(@bridge, listener: listener)
|
47
|
+
private
|
48
|
+
|
49
|
+
def initialize(bridge: nil, listener: nil, **opts)
|
50
|
+
# For ::Appium::Core::Waitable
|
51
|
+
@wait_timeout = opts.delete(:wait_timeout)
|
52
|
+
@wait_interval = opts.delete(:wait_interval)
|
53
|
+
|
54
|
+
# For logging.
|
55
|
+
# TODO: Remove when appium core no longer uses this in this bridge.
|
56
|
+
@automation_name = opts.delete(:automation_name)
|
57
|
+
|
58
|
+
super
|
50
59
|
end
|
51
60
|
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
55
|
-
|
61
|
+
# Create a proper bridge instance.
|
62
|
+
#
|
63
|
+
# @return [::Appium::Core::Base::Bridge]
|
64
|
+
#
|
65
|
+
def create_bridge(**opts)
|
66
|
+
capabilities = opts.delete(:capabilities)
|
67
|
+
bridge_opts = { http_client: opts.delete(:http_client), url: opts.delete(:url) }
|
68
|
+
raise ::Appium::Core::Error::ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
|
69
|
+
|
70
|
+
bridge = ::Appium::Core::Base::Bridge.new(**bridge_opts)
|
71
|
+
|
72
|
+
bridge.create_session(capabilities)
|
73
|
+
bridge
|
56
74
|
end
|
57
75
|
|
76
|
+
public
|
77
|
+
|
58
78
|
# Update +server_url+ and HTTP clients following this arguments, protocol, host, port and path.
|
59
79
|
# After this method, +@bridge.http+ will be a new instance following them instead of +server_url+ which is
|
60
80
|
# set before creating session.
|
81
|
+
# If +@bridge.http+ did not have +update_sending_request_to+ method, this method returns immediately.
|
61
82
|
#
|
62
83
|
# @example
|
63
84
|
#
|
@@ -66,14 +87,124 @@ module Appium
|
|
66
87
|
# driver.manage.timeouts.implicit_wait = 10 # @bridge.http is for 'https://example2.com:9000/wd/hub/'
|
67
88
|
#
|
68
89
|
def update_sending_request_to(protocol:, host:, port:, path:)
|
69
|
-
@bridge.http
|
70
|
-
|
71
|
-
|
72
|
-
|
90
|
+
unless @bridge.http&.class&.method_defined? :update_sending_request_to
|
91
|
+
::Appium::Logger.warn "#{@bridge.http&.class} has no 'update_sending_request_to'. " \
|
92
|
+
'It keeps current connection target.'
|
93
|
+
return
|
94
|
+
end
|
95
|
+
|
96
|
+
@bridge.http&.update_sending_request_to(scheme: protocol,
|
97
|
+
host: host,
|
98
|
+
port: port,
|
99
|
+
path: path)
|
100
|
+
end
|
101
|
+
|
102
|
+
AVAILABLE_METHODS = [
|
103
|
+
:get, :head, :post, :put, :delete,
|
104
|
+
:connect, :options, :trace, :patch
|
105
|
+
].freeze
|
106
|
+
# Define a new custom method to the driver so that you can define your own method for
|
107
|
+
# drivers/plugins in Appium 2.0. Appium 2.0 and its custom drivers/plugins allow you
|
108
|
+
# to define custom commands that are not part of W3C spec.
|
109
|
+
#
|
110
|
+
# @param [Symbol] method HTTP request method as https://www.w3.org/TR/webdriver/#endpoints
|
111
|
+
# @param [string] url The url to URL template as https://www.w3.org/TR/webdriver/#endpoints.
|
112
|
+
# +:session_id+ is the placeholder of 'session id'.
|
113
|
+
# Other place holders can be specified with +:+ prefix like +:id+.
|
114
|
+
# Then, the +:id+ will be replaced with a given value as the seconds argument of +execute+
|
115
|
+
# @param [Symbol] name The name of method that is called as the driver instance method.
|
116
|
+
# @param [Proc] block The block to involve as the method.
|
117
|
+
# Please define a method that has the same +name+ with arguments you want.
|
118
|
+
# The method must has +execute+ method. tHe +execute+ is calls the +url+
|
119
|
+
# with the given parameters.
|
120
|
+
# The first argument should be +name+ as symbol.
|
121
|
+
# The second argument should be hash. If keys in the hash matches +:+ prefix
|
122
|
+
# string in the given url, the matched string in the given url will be
|
123
|
+
# values in the hash.
|
124
|
+
# The third argument should be hash. The hash will be the request body.
|
125
|
+
# Please read examples below for more details.
|
126
|
+
# @raise [ArgumentError] If the given +method+ is invalid value.
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
#
|
130
|
+
# @driver.add_command(
|
131
|
+
# method: :get,
|
132
|
+
# url: 'session/:session_id/path/to/custom/url',
|
133
|
+
# name: :test_command
|
134
|
+
# )
|
135
|
+
# # Send a GET request to 'session/<session id>/path/to/custom/url'
|
136
|
+
# @driver.test_command
|
137
|
+
#
|
138
|
+
#
|
139
|
+
# @driver.add_command(
|
140
|
+
# method: :post,
|
141
|
+
# url: 'session/:session_id/path/to/custom/url',
|
142
|
+
# name: :test_command
|
143
|
+
# ) do
|
144
|
+
# def test_command(argument)
|
145
|
+
# execute(:test_command, {}, { dummy: argument })
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
# # Send a POST request to 'session/<session id>/path/to/custom/url'
|
149
|
+
# # with body "{ dummy: 1 }" as JSON object. "1" is the argument.
|
150
|
+
# # ':session_id' in the given 'url' is replaced with current 'session id'.
|
151
|
+
# @driver.test_command(1)
|
152
|
+
#
|
153
|
+
#
|
154
|
+
# @driver.add_command(
|
155
|
+
# method: :post,
|
156
|
+
# url: 'session/:session_id/element/:id/custom/action',
|
157
|
+
# name: :test_action_command
|
158
|
+
# ) do
|
159
|
+
# def test_action_command(element_id, action)
|
160
|
+
# execute(:test_action_command, {id: element_id}, { dummy_action: action })
|
161
|
+
# end
|
162
|
+
# end
|
163
|
+
# # Send a POST request to 'session/<session id>/element/<element id>/custom/action'
|
164
|
+
# # with body "{ dummy_action: #{action} }" as JSON object. "action" is the seconds argument.
|
165
|
+
# # ':session_id' in the given url is replaced with current 'session id'.
|
166
|
+
# # ':id' in the given url is replaced with the given 'element_id'.
|
167
|
+
# e = @driver.find_element :accessibility_id, 'an element'
|
168
|
+
# @driver.test_action_command(e.id, 'action')
|
169
|
+
#
|
170
|
+
def add_command(method:, url:, name:, &block)
|
171
|
+
unless AVAILABLE_METHODS.include? method
|
172
|
+
raise ::Appium::Core::Error::ArgumentError, "Available method is either #{AVAILABLE_METHODS}"
|
173
|
+
end
|
174
|
+
|
175
|
+
# TODO: Remove this logger before Appium 2.0 release
|
176
|
+
::Appium::Logger.info '[Experimental] this method is experimental for Appium 2.0. This interface may change.'
|
177
|
+
|
178
|
+
@bridge.add_command method: method, url: url, name: name, &block
|
73
179
|
end
|
74
180
|
|
75
181
|
### Methods for Appium
|
76
182
|
|
183
|
+
# Perform 'key' actions for W3C module.
|
184
|
+
# Generate +key+ pointer action here and users can use this via +driver.key_action+
|
185
|
+
# - https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/W3CActionBuilder.html
|
186
|
+
# - https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/KeyActions.html
|
187
|
+
#
|
188
|
+
# The pointer type is 'key' by default in the Appium Ruby client.
|
189
|
+
# +driver.action+ in Appium Ruby client has 'pointer' action by default.
|
190
|
+
# This method is a shortcut to set 'key' type.
|
191
|
+
# Hense this method is equal to +driver.action(devices: [::Selenium::WebDriver::Interactions.key('keyboard')])+
|
192
|
+
# as below example.
|
193
|
+
#
|
194
|
+
# @example
|
195
|
+
#
|
196
|
+
# element = @driver.find_element(:id, "some id")
|
197
|
+
# @driver.key_action.send_key('hiあ').perform # The 'send_key' is a part of 'KeyActions'
|
198
|
+
# # is equal to:
|
199
|
+
# # @driver.action(devices: [::Selenium::WebDriver::Interactions.key('keyboard')]).send_keys('hiあ').perform
|
200
|
+
#
|
201
|
+
def key_action(async: false)
|
202
|
+
@bridge.action(
|
203
|
+
async: async,
|
204
|
+
devices: [::Selenium::WebDriver::Interactions.key('keyboard')]
|
205
|
+
)
|
206
|
+
end
|
207
|
+
|
77
208
|
# Lock the device
|
78
209
|
# @return [String]
|
79
210
|
#
|
@@ -138,38 +269,6 @@ module Appium
|
|
138
269
|
end
|
139
270
|
alias is_keyboard_shown keyboard_shown?
|
140
271
|
|
141
|
-
# [DEPRECATION]
|
142
|
-
# Send keys for a current active element
|
143
|
-
# @param [String] key Input text
|
144
|
-
#
|
145
|
-
# @example
|
146
|
-
#
|
147
|
-
# @driver.send_keys 'happy testing!'
|
148
|
-
#
|
149
|
-
def send_keys(*key)
|
150
|
-
::Appium::Logger.warn(
|
151
|
-
'[DEPRECATION] Driver#send_keys is deprecated in W3C spec. Use driver.action.<command>.perform instead'
|
152
|
-
)
|
153
|
-
@bridge.send_keys_to_active_element(key)
|
154
|
-
end
|
155
|
-
alias type send_keys
|
156
|
-
|
157
|
-
class DriverSettings
|
158
|
-
# @private this class is private
|
159
|
-
def initialize(bridge)
|
160
|
-
@bridge = bridge
|
161
|
-
end
|
162
|
-
|
163
|
-
def get
|
164
|
-
@bridge.get_settings
|
165
|
-
end
|
166
|
-
|
167
|
-
def update(settings)
|
168
|
-
@bridge.update_settings(settings)
|
169
|
-
end
|
170
|
-
end
|
171
|
-
private_constant :DriverSettings
|
172
|
-
|
173
272
|
# Returns an instance of DriverSettings to call get/update.
|
174
273
|
#
|
175
274
|
# @example
|
@@ -178,7 +277,7 @@ module Appium
|
|
178
277
|
# @driver.settings.update('allowInvisibleElements': true)
|
179
278
|
#
|
180
279
|
def settings
|
181
|
-
@
|
280
|
+
@settings ||= DriverSettings.new(@bridge)
|
182
281
|
end
|
183
282
|
|
184
283
|
# Get appium Settings for current test session.
|
@@ -200,8 +299,8 @@ module Appium
|
|
200
299
|
#
|
201
300
|
# @example
|
202
301
|
#
|
203
|
-
# @driver.update_settings('allowInvisibleElements': true)
|
204
|
-
# @driver.settings.update('allowInvisibleElements': true)
|
302
|
+
# @driver.update_settings({ 'allowInvisibleElements': true })
|
303
|
+
# @driver.settings.update({ 'allowInvisibleElements': true })
|
205
304
|
# @driver.settings = { 'allowInvisibleElements': true }
|
206
305
|
#
|
207
306
|
def settings=(value)
|
@@ -209,36 +308,10 @@ module Appium
|
|
209
308
|
end
|
210
309
|
alias update_settings settings=
|
211
310
|
|
212
|
-
class DeviceIME
|
213
|
-
# @private this class is private
|
214
|
-
def initialize(bridge)
|
215
|
-
@bridge = bridge
|
216
|
-
end
|
217
|
-
|
218
|
-
def activate(ime_name)
|
219
|
-
@bridge.ime_activate(ime_name)
|
220
|
-
end
|
221
|
-
|
222
|
-
def available_engines
|
223
|
-
@bridge.ime_available_engines
|
224
|
-
end
|
225
|
-
|
226
|
-
def active_engine
|
227
|
-
@bridge.ime_active_engine
|
228
|
-
end
|
229
|
-
|
230
|
-
def activated?
|
231
|
-
@bridge.ime_activated
|
232
|
-
end
|
233
|
-
|
234
|
-
def deactivate
|
235
|
-
@bridge.ime_deactivate
|
236
|
-
end
|
237
|
-
end
|
238
|
-
private_constant :DeviceIME
|
239
|
-
|
240
311
|
# Returns an instance of DeviceIME
|
241
312
|
#
|
313
|
+
# @return [Appium::Core::Base::Driver::DeviceIME]
|
314
|
+
#
|
242
315
|
# @example
|
243
316
|
#
|
244
317
|
# @driver.ime.activate engine: 'com.android.inputmethod.latin/.LatinIME'
|
@@ -248,7 +321,7 @@ module Appium
|
|
248
321
|
# @driver.ime.deactivate #=> Deactivate current IME engine
|
249
322
|
#
|
250
323
|
def ime
|
251
|
-
@
|
324
|
+
@ime ||= DeviceIME.new(@bridge)
|
252
325
|
end
|
253
326
|
|
254
327
|
# Android only. Make an engine that is available active.
|
@@ -289,6 +362,8 @@ module Appium
|
|
289
362
|
# @!method ime_activated
|
290
363
|
# Android only. Indicates whether IME input is active at the moment (not if it is available).
|
291
364
|
#
|
365
|
+
# @return [Boolean]
|
366
|
+
#
|
292
367
|
# @example
|
293
368
|
#
|
294
369
|
# @driver.ime_activated #=> True if IME is activated
|
@@ -366,42 +441,10 @@ module Appium
|
|
366
441
|
end
|
367
442
|
alias set_context context=
|
368
443
|
|
369
|
-
# Set the value to element directly
|
370
|
-
#
|
371
|
-
# @example
|
372
|
-
#
|
373
|
-
# @driver.set_immediate_value element, 'hello'
|
374
|
-
#
|
375
|
-
def set_immediate_value(element, *value)
|
376
|
-
::Appium::Logger.warn '[DEPRECATION] driver#set_immediate_value(element, *value) is deprecated. ' \
|
377
|
-
'Use Element#immediate_value(*value) instead'
|
378
|
-
@bridge.set_immediate_value(element, *value)
|
379
|
-
end
|
380
|
-
|
381
|
-
# Replace the value to element directly
|
382
|
-
#
|
383
|
-
# @example
|
384
|
-
#
|
385
|
-
# @driver.replace_value element, 'hello'
|
386
|
-
#
|
387
|
-
def replace_value(element, *value)
|
388
|
-
::Appium::Logger.warn '[DEPRECATION] driver#replace_value(element, *value) is deprecated. ' \
|
389
|
-
'Use Element#replace_value(*value) instead'
|
390
|
-
@bridge.replace_value(element, *value)
|
391
|
-
end
|
392
|
-
|
393
444
|
# Place a file in a specific location on the device.
|
394
|
-
# On iOS, the server should have ifuse libraries installed and configured properly for this feature to work on
|
395
|
-
# real devices.
|
396
445
|
# On Android, the application under test should be built with debuggable flag enabled in order to get access to
|
397
446
|
# its container on the internal file system.
|
398
447
|
#
|
399
|
-
# {https://github.com/libimobiledevice/ifuse iFuse GitHub page6}
|
400
|
-
#
|
401
|
-
# {https://github.com/osxfuse/osxfuse/wiki/FAQ osxFuse FAQ}
|
402
|
-
#
|
403
|
-
# {https://developer.android.com/studio/debug 'Debug Your App' developer article}
|
404
|
-
#
|
405
448
|
# @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
|
406
449
|
# If the path starts with application id prefix, then the file will be pushed to the root of
|
407
450
|
# the corresponding application container.
|
@@ -418,18 +461,10 @@ module Appium
|
|
418
461
|
@bridge.push_file(path, filedata)
|
419
462
|
end
|
420
463
|
|
421
|
-
# Pull a file from the
|
422
|
-
# On iOS the server should have ifuse
|
423
|
-
# libraries installed and configured properly for this feature to work on real devices.
|
464
|
+
# Pull a file from the remote device.
|
424
465
|
# On Android the application under test should be built with debuggable flag enabled in order to get access
|
425
466
|
# to its container on the internal file system.
|
426
467
|
#
|
427
|
-
# {https://github.com/libimobiledevice/ifuse iFuse GitHub page6}
|
428
|
-
#
|
429
|
-
# {https://github.com/osxfuse/osxfuse/wiki/FAQ osxFuse FAQ}
|
430
|
-
#
|
431
|
-
# {https://developer.android.com/studio/debug 'Debug Your App' developer article}
|
432
|
-
#
|
433
468
|
# @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
|
434
469
|
# If the path starts with application id prefix, then the file will be pulled from the root
|
435
470
|
# of the corresponding application container.
|
@@ -438,7 +473,6 @@ module Appium
|
|
438
473
|
# Only pulling files from application containers is supported for iOS Simulator.
|
439
474
|
# Provide the remote path in format
|
440
475
|
# <code>@bundle.identifier:container_type/relative_path_in_container</code>
|
441
|
-
# (Make sure this in ifuse doc)
|
442
476
|
#
|
443
477
|
# @return [Base64-decoded] Base64 decoded data
|
444
478
|
#
|
@@ -455,18 +489,10 @@ module Appium
|
|
455
489
|
@bridge.pull_file(path)
|
456
490
|
end
|
457
491
|
|
458
|
-
# Pull a folder content from the
|
459
|
-
# On iOS the server should have ifuse libraries installed and configured properly for this feature to work
|
460
|
-
# on real devices.
|
492
|
+
# Pull a folder content from the remote device.
|
461
493
|
# On Android the application under test should be built with debuggable flag enabled in order to get access to
|
462
494
|
# its container on the internal file system.
|
463
495
|
#
|
464
|
-
# {https://github.com/libimobiledevice/ifuse iFuse GitHub page6}
|
465
|
-
#
|
466
|
-
# {https://github.com/osxfuse/osxfuse/wiki/FAQ osxFuse FAQ}
|
467
|
-
#
|
468
|
-
# {https://developer.android.com/studio/debug 'Debug Your App' developer article}
|
469
|
-
#
|
470
496
|
# @param [String] path Absolute path to the folder.
|
471
497
|
# If the path starts with <em>@applicationId/</em> prefix, then the folder will be pulled
|
472
498
|
# from the root of the corresponding application container.
|
@@ -475,7 +501,6 @@ module Appium
|
|
475
501
|
# Only pulling files from application containers is supported for iOS Simulator.
|
476
502
|
# Provide the remote path in format
|
477
503
|
# <code>@bundle.identifier:container_type/relative_path_in_container</code>
|
478
|
-
# (Make sure this in ifuse doc)
|
479
504
|
#
|
480
505
|
# @return [Base64-decoded] Base64 decoded data which is zip archived
|
481
506
|
#
|
@@ -489,19 +514,6 @@ module Appium
|
|
489
514
|
@bridge.pull_folder(path)
|
490
515
|
end
|
491
516
|
|
492
|
-
# Send keyevent on the device.(Only for Selendroid)
|
493
|
-
# http://developer.android.com/reference/android/view/KeyEvent.html
|
494
|
-
# @param [integer] key The key to press.
|
495
|
-
# @param [String] metastate The state the metakeys should be in when pressing the key.
|
496
|
-
#
|
497
|
-
# @example
|
498
|
-
#
|
499
|
-
# @driver.keyevent 82
|
500
|
-
#
|
501
|
-
def keyevent(key, metastate = nil)
|
502
|
-
@bridge.keyevent(key, metastate)
|
503
|
-
end
|
504
|
-
|
505
517
|
# Press keycode on the device.
|
506
518
|
# http://developer.android.com/reference/android/view/KeyEvent.html
|
507
519
|
# @param [Integer] key The key to press. The values which have +KEYCODE_+ prefix in http://developer.android.com/reference/android/view/KeyEvent.html
|
@@ -546,6 +558,7 @@ module Appium
|
|
546
558
|
@bridge.long_press_keycode(key, metastate: metastate, flags: flags)
|
547
559
|
end
|
548
560
|
|
561
|
+
# @deprecated Except for Windows
|
549
562
|
# Start the simulator and application configured with desired capabilities
|
550
563
|
#
|
551
564
|
# @example
|
@@ -553,9 +566,16 @@ module Appium
|
|
553
566
|
# @driver.launch_app
|
554
567
|
#
|
555
568
|
def launch_app
|
569
|
+
# TODO: Define only in Windows module when ruby_lib_core removes this method
|
570
|
+
if @automation_name != :windows
|
571
|
+
::Appium::Logger.warn(
|
572
|
+
'[DEPRECATION] launch_app is deprecated. Please use activate_app instead.'
|
573
|
+
)
|
574
|
+
end
|
556
575
|
@bridge.launch_app
|
557
576
|
end
|
558
577
|
|
578
|
+
# @deprecated Except for Windows
|
559
579
|
# Close an app on device
|
560
580
|
#
|
561
581
|
# @example
|
@@ -563,9 +583,16 @@ module Appium
|
|
563
583
|
# @driver.close_app
|
564
584
|
#
|
565
585
|
def close_app
|
586
|
+
# TODO: Define only in Windows module when ruby_lib_core removes this method
|
587
|
+
if @automation_name != :windows
|
588
|
+
::Appium::Logger.warn(
|
589
|
+
'[DEPRECATION] close_app is deprecated. Please use terminate_app instead.'
|
590
|
+
)
|
591
|
+
end
|
566
592
|
@bridge.close_app
|
567
593
|
end
|
568
594
|
|
595
|
+
# @deprecated
|
569
596
|
# Reset the device, relaunching the application.
|
570
597
|
#
|
571
598
|
# @example
|
@@ -573,6 +600,10 @@ module Appium
|
|
573
600
|
# @driver.reset
|
574
601
|
#
|
575
602
|
def reset
|
603
|
+
::Appium::Logger.warn(
|
604
|
+
'[DEPRECATION] reset is deprecated. Please use terminate_app and activate_app, ' \
|
605
|
+
'or quit and create a new session instead.'
|
606
|
+
)
|
576
607
|
@bridge.reset
|
577
608
|
end
|
578
609
|
|
@@ -602,7 +633,9 @@ module Appium
|
|
602
633
|
@bridge.background_app(duration)
|
603
634
|
end
|
604
635
|
|
605
|
-
# Install the given app onto the device
|
636
|
+
# Install the given app onto the device.
|
637
|
+
# Each options can be snake-case or camel-case. Snake-cases will be converted to camel-case
|
638
|
+
# as options value.
|
606
639
|
#
|
607
640
|
# @param [String] path The absolute local path or remote http URL to an .ipa or .apk file,
|
608
641
|
# or a .zip containing one of these.
|
@@ -616,26 +649,26 @@ module Appium
|
|
616
649
|
# @param [Boolean] grant_permissions Only for Android. whether to automatically grant application permissions
|
617
650
|
# on Android 6+ after the installation completes. +false+ by default
|
618
651
|
#
|
652
|
+
# Other parameters such as https://github.com/appium/appium-xcuitest-driver#mobile-installapp also can be set.
|
653
|
+
# Then, arguments in snake case will be camel case as its request parameters.
|
654
|
+
#
|
619
655
|
# @example
|
620
656
|
#
|
621
657
|
# @driver.install_app("/path/to/test.apk")
|
622
658
|
# @driver.install_app("/path/to/test.apk", replace: true, timeout: 20000, allow_test_packages: true,
|
623
659
|
# use_sdcard: false, grant_permissions: false)
|
660
|
+
# @driver.install_app("/path/to/test.ipa", timeoutMs: 20000)
|
624
661
|
#
|
625
|
-
def install_app(path,
|
626
|
-
|
627
|
-
|
628
|
-
allow_test_packages: nil,
|
629
|
-
use_sdcard: nil,
|
630
|
-
grant_permissions: nil)
|
631
|
-
@bridge.install_app(path,
|
632
|
-
replace: replace,
|
633
|
-
timeout: timeout,
|
634
|
-
allow_test_packages: allow_test_packages,
|
635
|
-
use_sdcard: use_sdcard,
|
636
|
-
grant_permissions: grant_permissions)
|
662
|
+
def install_app(path, **options)
|
663
|
+
options = options.transform_keys { |key| key.to_s.gsub(/_./) { |v| v[1].upcase } } unless options.nil?
|
664
|
+
@bridge.install_app(path, options)
|
637
665
|
end
|
638
666
|
|
667
|
+
# def capitalize(s)
|
668
|
+
# chars =
|
669
|
+
# chars[1:].map(&:capitalize).join
|
670
|
+
# end
|
671
|
+
|
639
672
|
# @param [Strong] app_id BundleId for iOS or package name for Android
|
640
673
|
# @param [Boolean] keep_data Only for Android. Whether to keep application data and caches after it is uninstalled.
|
641
674
|
# +false+ by default
|
@@ -790,7 +823,7 @@ module Appium
|
|
790
823
|
#
|
791
824
|
# @example: Zoom
|
792
825
|
#
|
793
|
-
# f1 =
|
826
|
+
# f1 = ::Selenium::WebDriver::Interactions.pointer(:touch, name: 'finger1')
|
794
827
|
# f1.create_pointer_move(duration: 1, x: 200, y: 500,
|
795
828
|
# origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
796
829
|
# f1.create_pointer_down(:left)
|
@@ -798,7 +831,7 @@ module Appium
|
|
798
831
|
# origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
799
832
|
# f1.create_pointer_up(:left)
|
800
833
|
#
|
801
|
-
# f2 =
|
834
|
+
# f2 = ::Selenium::WebDriver::Interactions.pointer(:touch, name: 'finger2')
|
802
835
|
# f2.create_pointer_move(duration: 1, x: 200, y: 500,
|
803
836
|
# origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
|
804
837
|
# f2.create_pointer_down(:left)
|
@@ -809,7 +842,11 @@ module Appium
|
|
809
842
|
# @driver.perform_actions [f1, f2] #=> 'nil' if the action succeed
|
810
843
|
#
|
811
844
|
def perform_actions(data)
|
812
|
-
raise ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
|
845
|
+
raise ::Appium::Core::Error::ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
|
846
|
+
|
847
|
+
# NOTE: 'add_input' in Selenium Ruby implementation has additional 'pause'.
|
848
|
+
# This implementation is to avoid the additional pause.
|
849
|
+
# https://github.com/SeleniumHQ/selenium/blob/64447d4b03f6986337d1ca8d8b6476653570bcc1/rb/lib/selenium/webdriver/common/action_builder.rb#L207
|
813
850
|
|
814
851
|
@bridge.send_actions data.map(&:encode).compact
|
815
852
|
data.each(&:clear_actions)
|
@@ -853,7 +890,7 @@ module Appium
|
|
853
890
|
end
|
854
891
|
|
855
892
|
# Get the device window's logs.
|
856
|
-
# @return [
|
893
|
+
# @return [Appium::Core::Logs]
|
857
894
|
#
|
858
895
|
# @example
|
859
896
|
#
|
@@ -879,16 +916,15 @@ module Appium
|
|
879
916
|
# Retrieve the capabilities of the specified session.
|
880
917
|
# It's almost same as +@driver.capabilities+ but you can get more details.
|
881
918
|
#
|
882
|
-
# @return [Selenium::WebDriver::Remote::Capabilities]
|
919
|
+
# @return [Selenium::WebDriver::Remote::Capabilities, Selenium::WebDriver::Remote::Capabilities]
|
883
920
|
#
|
884
921
|
# @example
|
885
922
|
# @driver.session_capabilities
|
886
923
|
#
|
887
924
|
# #=> uiautomator2
|
888
|
-
# # <Selenium::WebDriver::Remote::
|
925
|
+
# # <Selenium::WebDriver::Remote::Capabilities:0x007fa38dae1360
|
889
926
|
# # @capabilities=
|
890
|
-
# # {:
|
891
|
-
# # :browser_name=>nil,
|
927
|
+
# # {:browser_name=>nil,
|
892
928
|
# # :browser_version=>nil,
|
893
929
|
# # :platform_name=>"android",
|
894
930
|
# # :page_load_strategy=>nil,
|
@@ -935,10 +971,9 @@ module Appium
|
|
935
971
|
# # "viewportRect"=>{"left"=>0, "top"=>63, "width"=>1080, "height"=>1731}}>
|
936
972
|
# #
|
937
973
|
# #=> XCUITest
|
938
|
-
# # <Selenium::WebDriver::Remote::
|
974
|
+
# # <Selenium::WebDriver::Remote::Capabilities:0x007fb15dc01370
|
939
975
|
# # @capabilities=
|
940
|
-
# # {:
|
941
|
-
# # :browser_name=>"UICatalog",
|
976
|
+
# # {:browser_name=>"UICatalog",
|
942
977
|
# # :browser_version=>nil,
|
943
978
|
# # :platform_name=>"ios",
|
944
979
|
# # :page_load_strategy=>nil,
|
@@ -992,11 +1027,14 @@ module Appium
|
|
992
1027
|
visualize: visualize)
|
993
1028
|
end
|
994
1029
|
|
995
|
-
def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil
|
1030
|
+
def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil,
|
1031
|
+
multiple: nil, match_neighbour_threshold: nil)
|
996
1032
|
@bridge.find_image_occurrence(full_image: full_image,
|
997
1033
|
partial_image: partial_image,
|
998
1034
|
visualize: visualize,
|
999
|
-
threshold: threshold
|
1035
|
+
threshold: threshold,
|
1036
|
+
multiple: multiple,
|
1037
|
+
match_neighbour_threshold: match_neighbour_threshold)
|
1000
1038
|
end
|
1001
1039
|
|
1002
1040
|
def get_images_similarity(first_image:, second_image:, visualize: false)
|
@@ -1009,14 +1047,14 @@ module Appium
|
|
1009
1047
|
|
1010
1048
|
# @since Appium 1.8.2
|
1011
1049
|
# Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
|
1012
|
-
# {https://github.com/appium/appium/blob/
|
1050
|
+
# {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
|
1013
1051
|
#
|
1014
1052
|
# You can handle settings for the comparision following below.
|
1015
1053
|
# {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 device-settings}
|
1016
1054
|
#
|
1017
1055
|
# @param [String] img_path A path to a partial image you'd like to find
|
1018
1056
|
#
|
1019
|
-
# @return [::
|
1057
|
+
# @return [::Appium::Core::Element]
|
1020
1058
|
#
|
1021
1059
|
# @example
|
1022
1060
|
#
|
@@ -1031,14 +1069,14 @@ module Appium
|
|
1031
1069
|
|
1032
1070
|
# @since Appium 1.8.2
|
1033
1071
|
# Return elements if current view has a partial image. The logic depends on template matching by OpenCV.
|
1034
|
-
# {https://github.com/appium/appium/blob/
|
1072
|
+
# {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
|
1035
1073
|
#
|
1036
1074
|
# You can handle settings for the comparision following below.
|
1037
1075
|
# {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 device-settings}
|
1038
1076
|
#
|
1039
1077
|
# @param [String] img_path A path to a partial image you'd like to find
|
1040
1078
|
#
|
1041
|
-
# @return [
|
1079
|
+
# @return [Array<Selenium::WebDriver::Element>]
|
1042
1080
|
#
|
1043
1081
|
# @example
|
1044
1082
|
#
|
@@ -1086,14 +1124,14 @@ module Appium
|
|
1086
1124
|
@bridge.execute_driver(script: script, type: type, timeout_ms: timeout_ms)
|
1087
1125
|
end
|
1088
1126
|
|
1089
|
-
# Convert vanilla element response to ::
|
1127
|
+
# Convert vanilla element response to ::Appium::Core::Element
|
1090
1128
|
#
|
1091
1129
|
# @param [Hash] id The id which can get as a response from server
|
1092
|
-
# @return [::
|
1130
|
+
# @return [::Appium::Core::Element]
|
1093
1131
|
#
|
1094
1132
|
# @example
|
1095
1133
|
# response = {"element-6066-11e4-a52e-4f735466cecf"=>"xxxx", "ELEMENT"=>"xxxx"}
|
1096
|
-
# ele = @driver.convert_to_element(response) #=> ::
|
1134
|
+
# ele = @driver.convert_to_element(response) #=> ::Appium::Core::Element
|
1097
1135
|
# ele.rect #=> Can get the rect of the element
|
1098
1136
|
#
|
1099
1137
|
def convert_to_element(id)
|