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