appium_lib_core 4.1.0 → 8.0.2
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 +316 -270
- data/README.md +65 -15
- data/Rakefile +5 -22
- data/appium_lib_core.gemspec +6 -9
- data/bin/console +0 -4
- data/lib/appium_lib_core/android/device/auth_finger_print.rb +4 -1
- data/lib/appium_lib_core/android/device/network.rb +10 -0
- data/lib/appium_lib_core/android/device/performance.rb +3 -0
- data/lib/appium_lib_core/android/device/screen.rb +2 -0
- data/lib/appium_lib_core/android/device.rb +80 -17
- data/lib/appium_lib_core/common/base/bridge.rb +309 -93
- data/lib/appium_lib_core/common/base/capabilities.rb +8 -9
- data/lib/appium_lib_core/common/{command/mjsonwp.rb → base/device_ime.rb} +33 -12
- data/lib/appium_lib_core/common/base/driver.rb +258 -331
- 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 +15 -38
- data/lib/appium_lib_core/{ios/uiautomation/bridge.rb → common/base/remote_status.rb} +9 -8
- data/lib/appium_lib_core/common/base/rotable.rb +62 -0
- data/lib/appium_lib_core/common/base/screenshot.rb +8 -8
- data/lib/appium_lib_core/common/base/search_context.rb +13 -17
- data/lib/appium_lib_core/common/base.rb +1 -5
- data/lib/appium_lib_core/common/command.rb +244 -4
- data/lib/appium_lib_core/common/device/app_management.rb +2 -26
- data/lib/appium_lib_core/common/device/context.rb +1 -5
- 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/device/{touch_actions.rb → orientation.rb} +6 -10
- data/lib/appium_lib_core/common/error.rb +4 -5
- data/lib/appium_lib_core/common/log.rb +5 -4
- data/lib/appium_lib_core/common/wait.rb +38 -6
- data/lib/appium_lib_core/device.rb +3 -9
- data/lib/appium_lib_core/driver.rb +182 -148
- data/lib/appium_lib_core/{patch.rb → element.rb} +62 -25
- data/lib/appium_lib_core/ios/xcuitest/device.rb +2 -0
- 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/{ios.rb → mac2.rb} +2 -5
- data/lib/appium_lib_core/support/event_firing_bridge.rb +57 -0
- data/lib/appium_lib_core/version.rb +2 -2
- data/lib/appium_lib_core.rb +21 -10
- metadata +28 -94
- 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/lib/appium_lib_core/common/device/value.rb +0 -52
- data/lib/appium_lib_core/common/touch_action/multi_touch.rb +0 -56
- data/lib/appium_lib_core/common/touch_action/touch_actions.rb +0 -203
- data/lib/appium_lib_core/ios/uiautomation/device.rb +0 -44
- data/lib/appium_lib_core/ios/uiautomation/patch.rb +0 -34
- data/release_notes.md +0 -816
- data/script/commands.rb +0 -200
@@ -15,6 +15,9 @@
|
|
15
15
|
require 'uri'
|
16
16
|
|
17
17
|
module Appium
|
18
|
+
# The struct for 'location'
|
19
|
+
Location = Struct.new(:latitude, :longitude, :altitude)
|
20
|
+
|
18
21
|
module Core
|
19
22
|
module Android
|
20
23
|
autoload :Uiautomator1, 'appium_lib_core/android'
|
@@ -23,33 +26,30 @@ module Appium
|
|
23
26
|
end
|
24
27
|
|
25
28
|
module Ios
|
26
|
-
autoload :Uiautomation, 'appium_lib_core/ios'
|
27
29
|
autoload :Xcuitest, 'appium_lib_core/ios_xcuitest'
|
28
30
|
end
|
29
31
|
|
32
|
+
autoload :Mac2, 'appium_lib_core/mac2'
|
33
|
+
|
30
34
|
autoload :Windows, 'appium_lib_core/windows'
|
31
35
|
|
32
36
|
# This options affects only client side as <code>:appium_lib</code> key.<br>
|
33
37
|
# Read {::Appium::Core::Driver} about each attribute
|
34
38
|
class Options
|
35
|
-
attr_reader :custom_url, :default_wait,
|
39
|
+
attr_reader :custom_url, :default_wait,
|
36
40
|
:port, :wait_timeout, :wait_interval, :listener,
|
37
41
|
:direct_connect, :enable_idempotency_header
|
38
42
|
|
39
43
|
def initialize(appium_lib_opts)
|
40
44
|
@custom_url = appium_lib_opts.fetch :server_url, nil
|
41
|
-
@default_wait = appium_lib_opts.fetch :wait,
|
45
|
+
@default_wait = appium_lib_opts.fetch :wait, nil
|
42
46
|
@enable_idempotency_header = appium_lib_opts.fetch :enable_idempotency_header, true
|
43
47
|
|
44
|
-
|
45
|
-
@export_session = appium_lib_opts.fetch :export_session, false
|
46
|
-
@export_session_path = appium_lib_opts.fetch :export_session_path, default_tmp_appium_lib_session
|
47
|
-
|
48
|
-
@direct_connect = appium_lib_opts.fetch :direct_connect, false
|
48
|
+
@direct_connect = appium_lib_opts.fetch :direct_connect, true
|
49
49
|
|
50
50
|
@port = appium_lib_opts.fetch :port, Driver::DEFAULT_APPIUM_PORT
|
51
51
|
|
52
|
-
# timeout and interval used in ::Appium::
|
52
|
+
# timeout and interval used in ::Appium::Commn.wait/wait_true
|
53
53
|
@wait_timeout = appium_lib_opts.fetch :wait_timeout, ::Appium::Core::Wait::DEFAULT_TIMEOUT
|
54
54
|
@wait_interval = appium_lib_opts.fetch :wait_interval, ::Appium::Core::Wait::DEFAULT_INTERVAL
|
55
55
|
|
@@ -74,6 +74,13 @@ module Appium
|
|
74
74
|
path: 'directConnectPath'
|
75
75
|
}.freeze
|
76
76
|
|
77
|
+
W3C_KEYS = {
|
78
|
+
protocol: 'appium:directConnectProtocol',
|
79
|
+
host: 'appium:directConnectHost',
|
80
|
+
port: 'appium:directConnectPort',
|
81
|
+
path: 'appium:directConnectPath'
|
82
|
+
}.freeze
|
83
|
+
|
77
84
|
# @return [string] Returns a protocol such as http/https
|
78
85
|
attr_reader :protocol
|
79
86
|
|
@@ -87,10 +94,10 @@ module Appium
|
|
87
94
|
attr_reader :path
|
88
95
|
|
89
96
|
def initialize(capabilities)
|
90
|
-
@protocol = capabilities[KEYS[:protocol]]
|
91
|
-
@host = capabilities[KEYS[:host]]
|
92
|
-
@port = capabilities[KEYS[:port]]
|
93
|
-
@path = capabilities[KEYS[:path]]
|
97
|
+
@protocol = capabilities[W3C_KEYS[:protocol]] || capabilities[KEYS[:protocol]]
|
98
|
+
@host = capabilities[W3C_KEYS[:host]] || capabilities[KEYS[:host]]
|
99
|
+
@port = capabilities[W3C_KEYS[:port]] || capabilities[KEYS[:port]]
|
100
|
+
@path = capabilities[W3C_KEYS[:path]] || capabilities[KEYS[:path]]
|
94
101
|
end
|
95
102
|
end
|
96
103
|
|
@@ -126,18 +133,10 @@ module Appium
|
|
126
133
|
# @return [String]
|
127
134
|
attr_reader :custom_url
|
128
135
|
|
129
|
-
# Export session id to textfile in /tmp for 3rd party tools. False by default.
|
130
|
-
# @return [Boolean]
|
131
|
-
attr_reader :export_session
|
132
|
-
# @return [String] By default, session id is exported in '/tmp/appium_lib_session'
|
133
|
-
attr_reader :export_session_path
|
134
|
-
|
135
136
|
# Default wait time for elements to appear in Appium server side.
|
136
|
-
# Defaults to {::Appium::Core::Driver::DEFAULT_IMPLICIT_WAIT}.<br>
|
137
137
|
# Provide <code>{ appium_lib: { wait: 30 } }</code> to {::Appium::Core.for}
|
138
138
|
# @return [Integer]
|
139
139
|
attr_reader :default_wait
|
140
|
-
DEFAULT_IMPLICIT_WAIT = 0
|
141
140
|
|
142
141
|
# Appium's server port. 4723 is by default. Defaults to {::Appium::Core::Driver::DEFAULT_APPIUM_PORT}.<br>
|
143
142
|
# Provide <code>{ appium_lib: { port: 8080 } }</code> to {::Appium::Core.for}.
|
@@ -175,7 +174,8 @@ module Appium
|
|
175
174
|
# - <code>directConnectPort</code>
|
176
175
|
# - <code>directConnectPath</code>
|
177
176
|
#
|
178
|
-
#
|
177
|
+
# ignore them if this parameter is <code>false</code>. Defaults to true.
|
178
|
+
# These keys can have <code>appium:</code> prefix.
|
179
179
|
#
|
180
180
|
# @return [Bool]
|
181
181
|
attr_reader :direct_connect
|
@@ -185,8 +185,6 @@ module Appium
|
|
185
185
|
# @option opts [Hash] :caps Appium capabilities.
|
186
186
|
# @option opts [Hash] :capabilities The same as :caps.
|
187
187
|
# This param is for compatibility with Selenium WebDriver format
|
188
|
-
# @option opts [Hash] :desired_capabilities The same as :caps.
|
189
|
-
# This param is for compatibility with Selenium WebDriver format
|
190
188
|
# @option opts [Appium::Core::Options] :appium_lib Capabilities affect only ruby client
|
191
189
|
# @option opts [String] :url The same as :custom_url in :appium_lib.
|
192
190
|
# This param is for compatibility with Selenium WebDriver format
|
@@ -197,10 +195,8 @@ module Appium
|
|
197
195
|
#
|
198
196
|
# # format 1
|
199
197
|
# @core = Appium::Core.for caps: {...}, appium_lib: {...}
|
200
|
-
# # format 2. 'capabilities:'
|
198
|
+
# # format 2. 'capabilities:' is also available instead of 'caps:'.
|
201
199
|
# @core = Appium::Core.for url: "http://127.0.0.1:8080/wd/hub", capabilities: {...}, appium_lib: {...}
|
202
|
-
# # format 3. 'appium_lib: {...}' can be blank
|
203
|
-
# @core = Appium::Core.for url: "http://127.0.0.1:8080/wd/hub", desired_capabilities: {...}
|
204
200
|
#
|
205
201
|
#
|
206
202
|
# require 'rubygems'
|
@@ -216,7 +212,6 @@ module Appium
|
|
216
212
|
# app: '/path/to/MyiOS.app'
|
217
213
|
# },
|
218
214
|
# appium_lib: {
|
219
|
-
# export_session: false,
|
220
215
|
# port: 8080,
|
221
216
|
# wait: 0,
|
222
217
|
# wait_timeout: 20,
|
@@ -228,7 +223,7 @@ module Appium
|
|
228
223
|
# @core.start_driver # Connect to 'http://127.0.0.1:8080/wd/hub' because of 'port: 8080'
|
229
224
|
#
|
230
225
|
# # Start iOS driver with .zip file over HTTP
|
231
|
-
# #
|
226
|
+
# # 'capabilities:' is also available instead of 'caps:'. Either is fine.
|
232
227
|
# opts = {
|
233
228
|
# capabilities: {
|
234
229
|
# platformName: :ios,
|
@@ -239,7 +234,6 @@ module Appium
|
|
239
234
|
# },
|
240
235
|
# appium_lib: {
|
241
236
|
# server_url: 'http://custom-host:8080/wd/hub.com',
|
242
|
-
# export_session: false,
|
243
237
|
# wait: 0,
|
244
238
|
# wait_timeout: 20,
|
245
239
|
# wait_interval: 0.3,
|
@@ -252,7 +246,7 @@ module Appium
|
|
252
246
|
# # Start iOS driver as another format. 'url' is available like below
|
253
247
|
# opts = {
|
254
248
|
# url: "http://custom-host:8080/wd/hub.com",
|
255
|
-
#
|
249
|
+
# capabilities: {
|
256
250
|
# platformName: :ios,
|
257
251
|
# platformVersion: '11.0',
|
258
252
|
# deviceName: 'iPhone Simulator',
|
@@ -260,7 +254,6 @@ module Appium
|
|
260
254
|
# app: '/path/to/MyiOS.app'
|
261
255
|
# },
|
262
256
|
# appium_lib: {
|
263
|
-
# export_session: false,
|
264
257
|
# wait: 0,
|
265
258
|
# wait_timeout: 20,
|
266
259
|
# wait_interval: 0.3,
|
@@ -270,8 +263,58 @@ module Appium
|
|
270
263
|
# @core = Appium::Core.for(opts) # create a core driver with 'opts' and extend methods into 'self'
|
271
264
|
# @core.start_driver # start driver with 'url'. Connect to 'http://custom-host:8080/wd/hub.com'
|
272
265
|
#
|
266
|
+
# # With a custom listener
|
267
|
+
# class CustomListener < ::Selenium::WebDriver::Support::AbstractEventListener
|
268
|
+
# // something
|
269
|
+
# end
|
270
|
+
# capabilities: {
|
271
|
+
# platformName: :ios,
|
272
|
+
# platformVersion: '11.0',
|
273
|
+
# deviceName: 'iPhone Simulator',
|
274
|
+
# automationName: 'XCUITest',
|
275
|
+
# app: '/path/to/MyiOS.app'
|
276
|
+
# },
|
277
|
+
# appium_lib: {
|
278
|
+
# listener: CustomListener.new,
|
279
|
+
# }
|
280
|
+
# @core = Appium::Core.for capabilities: capabilities, appium_lib: appium_lib
|
281
|
+
# @core.start_driver
|
282
|
+
#
|
273
283
|
def self.for(opts = {})
|
274
|
-
new(opts)
|
284
|
+
new.setup_for_new_session(opts)
|
285
|
+
end
|
286
|
+
|
287
|
+
# Attach to an existing session. The main usage of this method is to attach to
|
288
|
+
# an existing session for debugging. The generated driver instance has the capabilities which
|
289
|
+
# has the given automationName and platformName only since the W3C WebDriver spec does not provide
|
290
|
+
# an endpoint to get running session's capabilities.
|
291
|
+
#
|
292
|
+
#
|
293
|
+
# @param [String] The session id to attach to.
|
294
|
+
# @param [String] url The WebDriver URL to attach to with the session_id.
|
295
|
+
# @param [String] automation_name The platform name to keep in the dummy capabilities
|
296
|
+
# @param [String] platform_name The automation name to keep in the dummy capabilities
|
297
|
+
# @return [Selenium::WebDriver] A new driver instance with the given session id.
|
298
|
+
#
|
299
|
+
# @example
|
300
|
+
#
|
301
|
+
# new_driver = ::Appium::Core::Driver.attach_to(
|
302
|
+
# driver.session_id, # The 'driver' has an existing session id
|
303
|
+
# url: 'http://127.0.0.1:4723/wd/hub', automation_name: 'UiAutomator2', platform_name: 'Android'
|
304
|
+
# )
|
305
|
+
# new_driver.page_source # for example
|
306
|
+
#
|
307
|
+
def self.attach_to(
|
308
|
+
session_id, url: nil, automation_name: nil, platform_name: nil,
|
309
|
+
http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 }
|
310
|
+
)
|
311
|
+
new.attach_to(
|
312
|
+
session_id,
|
313
|
+
automation_name: automation_name,
|
314
|
+
platform_name: platform_name,
|
315
|
+
url: url,
|
316
|
+
http_client_ops: http_client_ops
|
317
|
+
)
|
275
318
|
end
|
276
319
|
|
277
320
|
private
|
@@ -282,17 +325,25 @@ module Appium
|
|
282
325
|
@delegate_target
|
283
326
|
end
|
284
327
|
|
285
|
-
public
|
286
|
-
|
287
328
|
# @private
|
288
|
-
def initialize
|
329
|
+
def initialize
|
289
330
|
@delegate_target = self # for testing purpose
|
290
331
|
@automation_name = nil # initialise before 'set_automation_name'
|
332
|
+
end
|
291
333
|
|
292
|
-
|
293
|
-
|
334
|
+
public
|
335
|
+
|
336
|
+
# @private
|
337
|
+
# Set up for a new session
|
338
|
+
def setup_for_new_session(opts = {})
|
339
|
+
@custom_url = opts.delete :url # to set the custom url as :url
|
340
|
+
|
341
|
+
# TODO: Remove when we implement Options
|
342
|
+
# The symbolize_keys is to keep compatiility for the legacy code, which allows capabilities to give 'string' as the key.
|
343
|
+
# The toplevel `caps`, `capabilities` and `appium_lib` are expected to be symbol.
|
344
|
+
# FIXME: First, please try to remove `nested: true` to `nested: false`.
|
345
|
+
opts = Appium.symbolize_keys(opts, nested: true)
|
294
346
|
|
295
|
-
@custom_url = opts.delete :url
|
296
347
|
@caps = get_caps(opts)
|
297
348
|
|
298
349
|
set_appium_lib_specific_values(get_appium_lib_opts(opts))
|
@@ -301,8 +352,7 @@ module Appium
|
|
301
352
|
set_automation_name
|
302
353
|
|
303
354
|
extend_for(device: @device, automation_name: @automation_name)
|
304
|
-
|
305
|
-
self # rubocop:disable Lint/Void
|
355
|
+
self
|
306
356
|
end
|
307
357
|
|
308
358
|
# Creates a new global driver and quits the old one if it exists.
|
@@ -313,7 +363,7 @@ module Appium
|
|
313
363
|
# @option http_client_ops [Hash] :http_client Custom HTTP Client
|
314
364
|
# @option http_client_ops [Hash] :open_timeout Custom open timeout for http client.
|
315
365
|
# @option http_client_ops [Hash] :read_timeout Custom read timeout for http client.
|
316
|
-
# @return [Selenium::WebDriver]
|
366
|
+
# @return [Selenium::WebDriver] A new driver instance
|
317
367
|
#
|
318
368
|
# @example
|
319
369
|
#
|
@@ -324,7 +374,7 @@ module Appium
|
|
324
374
|
#
|
325
375
|
# # Start iOS driver
|
326
376
|
# opts = {
|
327
|
-
#
|
377
|
+
# capabilities: {
|
328
378
|
# platformName: :ios,
|
329
379
|
# platformVersion: '11.0',
|
330
380
|
# deviceName: 'iPhone Simulator',
|
@@ -365,19 +415,17 @@ module Appium
|
|
365
415
|
end
|
366
416
|
|
367
417
|
begin
|
368
|
-
|
369
|
-
|
370
|
-
|
418
|
+
@driver = ::Appium::Core::Base::Driver.new(listener: @listener,
|
419
|
+
http_client: @http_client,
|
420
|
+
capabilities: @caps, # ::Appium::Core::Base::Capabilities
|
371
421
|
url: @custom_url,
|
372
|
-
|
422
|
+
wait_timeout: @wait_timeout,
|
423
|
+
wait_interval: @wait_interval)
|
373
424
|
|
374
425
|
if @direct_connect
|
375
426
|
d_c = DirectConnections.new(@driver.capabilities)
|
376
427
|
@driver.update_sending_request_to(protocol: d_c.protocol, host: d_c.host, port: d_c.port, path: d_c.path)
|
377
428
|
end
|
378
|
-
|
379
|
-
# export session
|
380
|
-
write_session_id(@driver.session_id, @export_session_path) if @export_session
|
381
429
|
rescue Errno::ECONNREFUSED
|
382
430
|
raise "ERROR: Unable to connect to Appium. Is the server running on #{@custom_url}?"
|
383
431
|
end
|
@@ -387,6 +435,8 @@ module Appium
|
|
387
435
|
@http_client.additional_headers.delete Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
|
388
436
|
end
|
389
437
|
|
438
|
+
# TODO: this method can be removed after releasing Appium 2.0, and after a while
|
439
|
+
# since Appium 2.0 reuqires 'automationName'. This method won't help anymore then.
|
390
440
|
# If "automationName" is set only server side, this method set "automationName" attribute into @automation_name.
|
391
441
|
# Since @automation_name is set only client side before start_driver is called.
|
392
442
|
set_automation_name_if_nil
|
@@ -396,20 +446,53 @@ module Appium
|
|
396
446
|
@driver
|
397
447
|
end
|
398
448
|
|
399
|
-
private
|
449
|
+
# @private
|
450
|
+
# Attach to an existing session
|
451
|
+
def attach_to(session_id, url: nil, automation_name: nil, platform_name: nil,
|
452
|
+
http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 })
|
400
453
|
|
401
|
-
|
402
|
-
|
454
|
+
raise ::Appium::Core::Error::ArgumentError, 'The :url must not be nil' if url.nil?
|
455
|
+
raise ::Appium::Core::Error::ArgumentError, 'The :automation_name must not be nil' if automation_name.nil?
|
456
|
+
raise ::Appium::Core::Error::ArgumentError, 'The :platform_name must not be nil' if platform_name.nil?
|
457
|
+
|
458
|
+
@custom_url = url
|
459
|
+
|
460
|
+
# use lowercase internally
|
461
|
+
@automation_name = convert_downcase(automation_name)
|
462
|
+
@device = convert_downcase(platform_name)
|
463
|
+
|
464
|
+
extend_for(device: @device, automation_name: @automation_name)
|
403
465
|
|
404
|
-
|
405
|
-
|
406
|
-
|
466
|
+
@http_client = get_http_client http_client: http_client_ops.delete(:http_client),
|
467
|
+
open_timeout: http_client_ops.delete(:open_timeout),
|
468
|
+
read_timeout: http_client_ops.delete(:read_timeout)
|
469
|
+
|
470
|
+
# Note that 'enable_idempotency_header' works only a new session reqeust. The attach_to method skips
|
471
|
+
# the new session request, this it does not needed.
|
472
|
+
|
473
|
+
begin
|
474
|
+
# included https://github.com/SeleniumHQ/selenium/blob/43f8b3f66e7e01124eff6a5805269ee441f65707/rb/lib/selenium/webdriver/remote/driver.rb#L29
|
475
|
+
@driver = ::Appium::Core::Base::Driver.new(http_client: @http_client,
|
476
|
+
url: @custom_url,
|
477
|
+
listener: @listener,
|
478
|
+
existing_session_id: session_id,
|
479
|
+
automation_name: automation_name,
|
480
|
+
platform_name: platform_name)
|
481
|
+
rescue Errno::ECONNREFUSED
|
482
|
+
raise "ERROR: Unable to connect to Appium. Is the server running on #{@custom_url}?"
|
483
|
+
end
|
407
484
|
|
408
|
-
|
485
|
+
@driver
|
486
|
+
end
|
487
|
+
|
488
|
+
def get_http_client(http_client: nil, open_timeout: nil, read_timeout: nil)
|
489
|
+
http_client || Appium::Core::Base::Http::Default.new(open_timeout: open_timeout, read_timeout: read_timeout)
|
409
490
|
end
|
410
491
|
|
411
492
|
# Ignore setting default wait if the target driver has no implementation
|
412
493
|
def set_implicit_wait_by_default(wait)
|
494
|
+
return if @default_wait.nil?
|
495
|
+
|
413
496
|
@driver.manage.timeouts.implicit_wait = wait
|
414
497
|
rescue ::Selenium::WebDriver::Error::UnknownError => e
|
415
498
|
unless e.message.include?('The operation requested is not yet implemented')
|
@@ -420,9 +503,7 @@ module Appium
|
|
420
503
|
{}
|
421
504
|
end
|
422
505
|
|
423
|
-
|
424
|
-
|
425
|
-
# Quits the driver
|
506
|
+
# [Deprecated] Quits the driver. This method is the same as @driver.quit
|
426
507
|
# @return [void]
|
427
508
|
#
|
428
509
|
# @example
|
@@ -430,12 +511,14 @@ module Appium
|
|
430
511
|
# @core.quit_driver
|
431
512
|
#
|
432
513
|
def quit_driver
|
514
|
+
::Appium::Logger.warn('[DEPRECATION] quit_driver will be removed. Please use @driver.quit instead.')
|
433
515
|
@driver.quit
|
434
516
|
rescue # rubocop:disable Style/RescueStandardError
|
435
517
|
nil
|
436
518
|
end
|
437
519
|
|
438
|
-
# Returns the server's version info
|
520
|
+
# Returns the server's version info. This method calls +driver.remote_status+ internally
|
521
|
+
#
|
439
522
|
# @return [Hash]
|
440
523
|
#
|
441
524
|
# @example
|
@@ -449,58 +532,43 @@ module Appium
|
|
449
532
|
# }
|
450
533
|
# }
|
451
534
|
#
|
452
|
-
# Returns blank hash
|
535
|
+
# Returns blank hash in a case +driver.remote_status+ got an error
|
536
|
+
# such as Selenium Grid. It returns 500 error against 'remote_status'.
|
453
537
|
#
|
454
538
|
# @example
|
455
539
|
#
|
456
540
|
# @core.appium_server_version #=> {}
|
457
541
|
#
|
458
542
|
def appium_server_version
|
459
|
-
@driver.
|
460
|
-
rescue Selenium::WebDriver::Error::ServerError => e
|
461
|
-
raise ::Appium::Core::Error::ServerError unless e.message.include?('status code 500')
|
543
|
+
return {} if @driver.nil?
|
462
544
|
|
463
|
-
|
545
|
+
@driver.remote_status
|
546
|
+
rescue StandardError
|
547
|
+
# Ignore error case in a case the target appium server
|
548
|
+
# does not support `/status` API.
|
464
549
|
{}
|
465
550
|
end
|
466
551
|
|
467
|
-
|
468
|
-
# @return [Array<Integer>]
|
469
|
-
#
|
470
|
-
# @example
|
471
|
-
#
|
472
|
-
# @core.platform_version #=> [10,1,1]
|
473
|
-
#
|
474
|
-
def platform_version
|
475
|
-
p_version = @driver.capabilities['platformVersion'] || @driver.session_capabilities['platformVersion']
|
476
|
-
p_version.split('.').map(&:to_i)
|
477
|
-
end
|
552
|
+
private
|
478
553
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
#
|
486
|
-
# @core.screenshot '/tmp/hi.png' #=> nil
|
487
|
-
# # same as '@driver.save_screenshot png_save_path'
|
488
|
-
#
|
489
|
-
def screenshot(png_save_path)
|
490
|
-
::Appium::Logger.warn '[DEPRECATION] screenshot will be removed. Please use driver.save_screenshot instead.'
|
491
|
-
@driver.save_screenshot png_save_path
|
554
|
+
def convert_to_symbol(value)
|
555
|
+
if value.nil?
|
556
|
+
value
|
557
|
+
else
|
558
|
+
value.to_sym
|
559
|
+
end
|
492
560
|
end
|
493
561
|
|
494
|
-
private
|
495
|
-
|
496
562
|
# @private
|
497
563
|
def extend_for(device:, automation_name:) # rubocop:disable Metrics/CyclomaticComplexity
|
498
564
|
extend Appium::Core
|
499
565
|
extend Appium::Core::Device
|
500
566
|
|
501
|
-
|
567
|
+
sym_automation_name = convert_to_symbol(automation_name)
|
568
|
+
|
569
|
+
case convert_to_symbol(device)
|
502
570
|
when :android
|
503
|
-
case
|
571
|
+
case sym_automation_name
|
504
572
|
when :espresso
|
505
573
|
::Appium::Core::Android::Espresso::Bridge.for self
|
506
574
|
when :uiautomator2
|
@@ -511,28 +579,26 @@ module Appium
|
|
511
579
|
::Appium::Core::Android::Uiautomator1::Bridge.for self
|
512
580
|
end
|
513
581
|
when :ios, :tvos
|
514
|
-
case
|
582
|
+
case sym_automation_name
|
515
583
|
when :safari
|
516
584
|
::Appium::Logger.debug('SafariDriver for iOS')
|
517
|
-
|
585
|
+
else # XCUITest
|
518
586
|
::Appium::Core::Ios::Xcuitest::Bridge.for self
|
519
|
-
else # default and UIAutomation
|
520
|
-
::Appium::Core::Ios::Uiautomation::Bridge.for self
|
521
587
|
end
|
522
588
|
when :mac
|
523
|
-
case
|
589
|
+
case sym_automation_name
|
524
590
|
when :safari
|
525
591
|
::Appium::Logger.debug('SafariDriver for macOS')
|
526
592
|
when :gecko
|
527
593
|
::Appium::Logger.debug('Gecko Driver for macOS')
|
528
594
|
when :mac2
|
529
|
-
::Appium::
|
595
|
+
::Appium::Core::Mac2::Bridge.for self
|
530
596
|
else
|
531
597
|
# no Mac specific extentions
|
532
598
|
::Appium::Logger.debug('macOS Native')
|
533
599
|
end
|
534
600
|
when :windows
|
535
|
-
case
|
601
|
+
case sym_automation_name
|
536
602
|
when :gecko
|
537
603
|
::Appium::Logger.debug('Gecko Driver for Windows')
|
538
604
|
else
|
@@ -542,7 +608,7 @@ module Appium
|
|
542
608
|
# https://github.com/Samsung/appium-tizen-driver
|
543
609
|
::Appium::Logger.debug('tizen')
|
544
610
|
else
|
545
|
-
case
|
611
|
+
case sym_automation_name
|
546
612
|
when :youiengine
|
547
613
|
# https://github.com/YOU-i-Labs/appium-youiengine-driver
|
548
614
|
::Appium::Logger.debug('YouiEngine')
|
@@ -559,36 +625,9 @@ module Appium
|
|
559
625
|
self
|
560
626
|
end
|
561
627
|
|
562
|
-
# @private
|
563
|
-
def validate_keys(opts)
|
564
|
-
flatten_ops = flatten_hash_keys(opts)
|
565
|
-
|
566
|
-
# FIXME: Remove 'desired_capabilities' in the next major Selenium update
|
567
|
-
unless opts.member?(:caps) || opts.member?(:capabilities) || opts.member?(:desired_capabilities)
|
568
|
-
raise Error::NoCapabilityError
|
569
|
-
end
|
570
|
-
|
571
|
-
if !opts.member?(:appium_lib) && flatten_ops.member?(:appium_lib)
|
572
|
-
raise Error::CapabilityStructureError, 'Please check the value of appium_lib in the capability'
|
573
|
-
end
|
574
|
-
|
575
|
-
true
|
576
|
-
end
|
577
|
-
|
578
|
-
# @private
|
579
|
-
def flatten_hash_keys(hash, flatten_keys_result = [])
|
580
|
-
hash.each do |key, value|
|
581
|
-
flatten_keys_result << key
|
582
|
-
flatten_hash_keys(value, flatten_keys_result) if value.is_a?(Hash)
|
583
|
-
end
|
584
|
-
|
585
|
-
flatten_keys_result
|
586
|
-
end
|
587
|
-
|
588
628
|
# @private
|
589
629
|
def get_caps(opts)
|
590
|
-
|
591
|
-
Core::Base::Capabilities.create_capabilities(opts[:caps] || opts[:capabilities] || opts[:desired_capabilities] || {})
|
630
|
+
Core::Base::Capabilities.new(opts[:caps] || opts[:capabilities] || {})
|
592
631
|
end
|
593
632
|
|
594
633
|
# @private
|
@@ -601,6 +640,7 @@ module Appium
|
|
601
640
|
# The path can be local, HTTP/S, Windows Share and other path like 'sauce-storage:'.
|
602
641
|
# Use @caps[:app] without modifications if the path isn't HTTP/S or local path.
|
603
642
|
def set_app_path
|
643
|
+
# FIXME: maybe `:app` should check `app` as well.
|
604
644
|
return unless @caps && @caps[:app] && !@caps[:app].empty?
|
605
645
|
return if @caps[:app] =~ URI::DEFAULT_PARSER.make_regexp
|
606
646
|
|
@@ -623,9 +663,6 @@ module Appium
|
|
623
663
|
|
624
664
|
@default_wait = opts.default_wait
|
625
665
|
|
626
|
-
@export_session = opts.export_session
|
627
|
-
@export_session_path = opts.export_session_path
|
628
|
-
|
629
666
|
@port = opts.port
|
630
667
|
|
631
668
|
@wait_timeout = opts.wait_timeout
|
@@ -639,18 +676,24 @@ module Appium
|
|
639
676
|
# @private
|
640
677
|
def set_appium_device
|
641
678
|
# https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile
|
642
|
-
|
679
|
+
# TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
|
680
|
+
@device = @caps[:platformName] || @caps['platformName']
|
643
681
|
return @device unless @device
|
644
682
|
|
645
|
-
@device =
|
683
|
+
@device = convert_downcase @device
|
646
684
|
end
|
647
685
|
|
648
686
|
# @private
|
649
687
|
def set_automation_name
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
688
|
+
# TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
|
689
|
+
candidate = @caps[:automationName] || @caps['automationName']
|
690
|
+
@automation_name = candidate if candidate
|
691
|
+
@automation_name = convert_downcase @automation_name if @automation_name
|
692
|
+
end
|
693
|
+
|
694
|
+
# @private
|
695
|
+
def convert_downcase(value)
|
696
|
+
value.is_a?(Symbol) ? value.downcase : value.downcase.strip.intern
|
654
697
|
end
|
655
698
|
|
656
699
|
# @private
|
@@ -661,15 +704,6 @@ module Appium
|
|
661
704
|
@driver.capabilities['automationName'].downcase.strip.intern
|
662
705
|
end
|
663
706
|
end
|
664
|
-
|
665
|
-
# @private
|
666
|
-
def write_session_id(session_id, export_path = '/tmp/appium_lib_session')
|
667
|
-
export_path = export_path.tr('/', '\\') if ::Appium::Core::Base.platform.windows?
|
668
|
-
File.write(export_path, session_id)
|
669
|
-
rescue IOError => e
|
670
|
-
::Appium::Logger.warn e
|
671
|
-
nil
|
672
|
-
end
|
673
707
|
end # class Driver
|
674
708
|
end # module Core
|
675
709
|
end # module Appium
|