appium_lib_core 5.0.0 → 6.3.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 +140 -0
- data/README.md +55 -10
- data/appium_lib_core.gemspec +5 -5
- data/lib/appium_lib_core/common/base/bridge.rb +54 -40
- data/lib/appium_lib_core/common/base/capabilities.rb +8 -16
- data/lib/appium_lib_core/common/base/driver.rb +68 -40
- data/lib/appium_lib_core/common/base/has_location.rb +10 -10
- data/lib/appium_lib_core/common/base/http_default.rb +1 -1
- data/lib/appium_lib_core/common/base/rotable.rb +11 -3
- data/lib/appium_lib_core/common/base/search_context.rb +1 -2
- data/lib/appium_lib_core/common/command.rb +4 -2
- data/lib/appium_lib_core/common/device/app_management.rb +8 -14
- data/lib/appium_lib_core/common/device/value.rb +1 -3
- data/lib/appium_lib_core/common/error.rb +0 -4
- data/lib/appium_lib_core/driver.rb +170 -62
- 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/{ios/uiautomation/bridge.rb → windows/device/app_management.rb} +20 -12
- data/lib/appium_lib_core/windows/device.rb +2 -0
- data/lib/appium_lib_core.rb +19 -5
- metadata +21 -34
- data/.github/ISSUE_TEMPLATE/issue-report.md +0 -29
- data/.github/contributing.md +0 -26
- data/.github/dependabot.yml +0 -8
- data/.github/issue_template.md +0 -20
- data/.github/workflows/unittest.yml +0 -67
- data/.gitignore +0 -18
- data/.rubocop.yml +0 -146
- 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/ios/uiautomation/device.rb +0 -44
- data/lib/appium_lib_core/ios/uiautomation/patch.rb +0 -34
- data/lib/appium_lib_core/ios.rb +0 -20
- data/release_notes.md +0 -932
- data/script/commands.rb +0 -166
@@ -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,7 +26,6 @@ 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
|
|
@@ -76,6 +78,13 @@ module Appium
|
|
76
78
|
path: 'directConnectPath'
|
77
79
|
}.freeze
|
78
80
|
|
81
|
+
W3C_KEYS = {
|
82
|
+
protocol: 'appium:directConnectProtocol',
|
83
|
+
host: 'appium:directConnectHost',
|
84
|
+
port: 'appium:directConnectPort',
|
85
|
+
path: 'appium:directConnectPath'
|
86
|
+
}.freeze
|
87
|
+
|
79
88
|
# @return [string] Returns a protocol such as http/https
|
80
89
|
attr_reader :protocol
|
81
90
|
|
@@ -89,10 +98,10 @@ module Appium
|
|
89
98
|
attr_reader :path
|
90
99
|
|
91
100
|
def initialize(capabilities)
|
92
|
-
@protocol = capabilities[KEYS[:protocol]]
|
93
|
-
@host = capabilities[KEYS[:host]]
|
94
|
-
@port = capabilities[KEYS[:port]]
|
95
|
-
@path = capabilities[KEYS[:path]]
|
101
|
+
@protocol = capabilities[W3C_KEYS[:protocol]] || capabilities[KEYS[:protocol]]
|
102
|
+
@host = capabilities[W3C_KEYS[:host]] || capabilities[KEYS[:host]]
|
103
|
+
@port = capabilities[W3C_KEYS[:port]] || capabilities[KEYS[:port]]
|
104
|
+
@path = capabilities[W3C_KEYS[:path]] || capabilities[KEYS[:path]]
|
96
105
|
end
|
97
106
|
end
|
98
107
|
|
@@ -175,7 +184,8 @@ module Appium
|
|
175
184
|
# - <code>directConnectPort</code>
|
176
185
|
# - <code>directConnectPath</code>
|
177
186
|
#
|
178
|
-
#
|
187
|
+
# ignore them if this parameter is <code>false</code>. Defaults to true.
|
188
|
+
# These keys can have <code>appium:</code> prefix.
|
179
189
|
#
|
180
190
|
# @return [Bool]
|
181
191
|
attr_reader :direct_connect
|
@@ -266,8 +276,58 @@ module Appium
|
|
266
276
|
# @core = Appium::Core.for(opts) # create a core driver with 'opts' and extend methods into 'self'
|
267
277
|
# @core.start_driver # start driver with 'url'. Connect to 'http://custom-host:8080/wd/hub.com'
|
268
278
|
#
|
279
|
+
# # With a custom listener
|
280
|
+
# class CustomListener < ::Selenium::WebDriver::Support::AbstractEventListener
|
281
|
+
# // something
|
282
|
+
# end
|
283
|
+
# capabilities: {
|
284
|
+
# platformName: :ios,
|
285
|
+
# platformVersion: '11.0',
|
286
|
+
# deviceName: 'iPhone Simulator',
|
287
|
+
# automationName: 'XCUITest',
|
288
|
+
# app: '/path/to/MyiOS.app'
|
289
|
+
# },
|
290
|
+
# appium_lib: {
|
291
|
+
# listener: CustomListener.new,
|
292
|
+
# }
|
293
|
+
# @core = Appium::Core.for capabilities: capabilities, appium_lib: appium_lib
|
294
|
+
# @core.start_driver
|
295
|
+
#
|
269
296
|
def self.for(opts = {})
|
270
|
-
new(opts)
|
297
|
+
new.setup_for_new_session(opts)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Attach to an existing session. The main usage of this method is to attach to
|
301
|
+
# an existing session for debugging. The generated driver instance has the capabilities which
|
302
|
+
# has the given automationName and platformName only since the W3C WebDriver spec does not provide
|
303
|
+
# an endpoint to get running session's capabilities.
|
304
|
+
#
|
305
|
+
#
|
306
|
+
# @param [String] The session id to attach to.
|
307
|
+
# @param [String] url The WebDriver URL to attach to with the session_id.
|
308
|
+
# @param [String] automation_name The platform name to keep in the dummy capabilities
|
309
|
+
# @param [String] platform_name The automation name to keep in the dummy capabilities
|
310
|
+
# @return [Selenium::WebDriver] A new driver instance with the given session id.
|
311
|
+
#
|
312
|
+
# @example
|
313
|
+
#
|
314
|
+
# new_driver = ::Appium::Core::Driver.attach_to(
|
315
|
+
# driver.session_id, # The 'driver' has an existing session id
|
316
|
+
# url: 'http://127.0.0.1:4723/wd/hub', automation_name: 'UiAutomator2', platform_name: 'Android'
|
317
|
+
# )
|
318
|
+
# new_driver.page_source # for example
|
319
|
+
#
|
320
|
+
def self.attach_to(
|
321
|
+
session_id, url: nil, automation_name: nil, platform_name: nil,
|
322
|
+
http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 }
|
323
|
+
)
|
324
|
+
new.attach_to(
|
325
|
+
session_id,
|
326
|
+
automation_name: automation_name,
|
327
|
+
platform_name: platform_name,
|
328
|
+
url: url,
|
329
|
+
http_client_ops: http_client_ops
|
330
|
+
)
|
271
331
|
end
|
272
332
|
|
273
333
|
private
|
@@ -278,17 +338,25 @@ module Appium
|
|
278
338
|
@delegate_target
|
279
339
|
end
|
280
340
|
|
281
|
-
public
|
282
|
-
|
283
341
|
# @private
|
284
|
-
def initialize
|
342
|
+
def initialize
|
285
343
|
@delegate_target = self # for testing purpose
|
286
344
|
@automation_name = nil # initialise before 'set_automation_name'
|
345
|
+
end
|
346
|
+
|
347
|
+
public
|
287
348
|
|
288
|
-
|
289
|
-
|
349
|
+
# @private
|
350
|
+
# Set up for a new session
|
351
|
+
def setup_for_new_session(opts = {})
|
352
|
+
@custom_url = opts.delete :url # to set the custom url as :url
|
353
|
+
|
354
|
+
# TODO: Remove when we implement Options
|
355
|
+
# The symbolize_keys is to keep compatiility for the legacy code, which allows capabilities to give 'string' as the key.
|
356
|
+
# The toplevel `caps`, `capabilities` and `appium_lib` are expected to be symbol.
|
357
|
+
# FIXME: First, please try to remove `nested: true` to `nested: false`.
|
358
|
+
opts = Appium.symbolize_keys(opts, nested: true)
|
290
359
|
|
291
|
-
@custom_url = opts.delete :url
|
292
360
|
@caps = get_caps(opts)
|
293
361
|
|
294
362
|
set_appium_lib_specific_values(get_appium_lib_opts(opts))
|
@@ -297,8 +365,7 @@ module Appium
|
|
297
365
|
set_automation_name
|
298
366
|
|
299
367
|
extend_for(device: @device, automation_name: @automation_name)
|
300
|
-
|
301
|
-
self # rubocop:disable Lint/Void
|
368
|
+
self
|
302
369
|
end
|
303
370
|
|
304
371
|
# Creates a new global driver and quits the old one if it exists.
|
@@ -309,7 +376,7 @@ module Appium
|
|
309
376
|
# @option http_client_ops [Hash] :http_client Custom HTTP Client
|
310
377
|
# @option http_client_ops [Hash] :open_timeout Custom open timeout for http client.
|
311
378
|
# @option http_client_ops [Hash] :read_timeout Custom read timeout for http client.
|
312
|
-
# @return [Selenium::WebDriver]
|
379
|
+
# @return [Selenium::WebDriver] A new driver instance
|
313
380
|
#
|
314
381
|
# @example
|
315
382
|
#
|
@@ -363,11 +430,10 @@ module Appium
|
|
363
430
|
begin
|
364
431
|
@driver = ::Appium::Core::Base::Driver.new(listener: @listener,
|
365
432
|
http_client: @http_client,
|
366
|
-
capabilities: @caps, # ::
|
433
|
+
capabilities: @caps, # ::Appium::Core::Base::Capabilities
|
367
434
|
url: @custom_url,
|
368
435
|
wait_timeout: @wait_timeout,
|
369
|
-
wait_interval: @wait_interval
|
370
|
-
automation_name: @automation_name)
|
436
|
+
wait_interval: @wait_interval)
|
371
437
|
|
372
438
|
if @direct_connect
|
373
439
|
d_c = DirectConnections.new(@driver.capabilities)
|
@@ -385,6 +451,8 @@ module Appium
|
|
385
451
|
@http_client.additional_headers.delete Appium::Core::Base::Http::RequestHeaders::KEYS[:idempotency]
|
386
452
|
end
|
387
453
|
|
454
|
+
# TODO: this method can be removed after releasing Appium 2.0, and after a while
|
455
|
+
# since Appium 2.0 reuqires 'automationName'. This method won't help anymore then.
|
388
456
|
# If "automationName" is set only server side, this method set "automationName" attribute into @automation_name.
|
389
457
|
# Since @automation_name is set only client side before start_driver is called.
|
390
458
|
set_automation_name_if_nil
|
@@ -394,7 +462,47 @@ module Appium
|
|
394
462
|
@driver
|
395
463
|
end
|
396
464
|
|
397
|
-
private
|
465
|
+
# @private
|
466
|
+
# Attach to an existing session
|
467
|
+
def attach_to(session_id, url: nil, automation_name: nil, platform_name: nil,
|
468
|
+
http_client_ops: { http_client: nil, open_timeout: 999_999, read_timeout: 999_999 })
|
469
|
+
|
470
|
+
raise ::Appium::Core::Error::ArgumentError, 'The :url must not be nil' if url.nil?
|
471
|
+
raise ::Appium::Core::Error::ArgumentError, 'The :automation_name must not be nil' if automation_name.nil?
|
472
|
+
raise ::Appium::Core::Error::ArgumentError, 'The :platform_name must not be nil' if platform_name.nil?
|
473
|
+
|
474
|
+
@custom_url = url
|
475
|
+
|
476
|
+
# use lowercase internally
|
477
|
+
@automation_name = convert_downcase(automation_name)
|
478
|
+
@device = convert_downcase(platform_name)
|
479
|
+
|
480
|
+
extend_for(device: @device, automation_name: @automation_name)
|
481
|
+
|
482
|
+
@http_client = get_http_client http_client: http_client_ops.delete(:http_client),
|
483
|
+
open_timeout: http_client_ops.delete(:open_timeout),
|
484
|
+
read_timeout: http_client_ops.delete(:read_timeout)
|
485
|
+
|
486
|
+
# Note that 'enable_idempotency_header' works only a new session reqeust. The attach_to method skips
|
487
|
+
# the new session request, this it does not needed.
|
488
|
+
|
489
|
+
begin
|
490
|
+
# included https://github.com/SeleniumHQ/selenium/blob/43f8b3f66e7e01124eff6a5805269ee441f65707/rb/lib/selenium/webdriver/remote/driver.rb#L29
|
491
|
+
@driver = ::Appium::Core::Base::Driver.new(http_client: @http_client,
|
492
|
+
url: @custom_url,
|
493
|
+
listener: @listener,
|
494
|
+
existing_session_id: session_id,
|
495
|
+
automation_name: automation_name,
|
496
|
+
platform_name: platform_name)
|
497
|
+
|
498
|
+
# export session
|
499
|
+
write_session_id(@driver.session_id, @export_session_path) if @export_session
|
500
|
+
rescue Errno::ECONNREFUSED
|
501
|
+
raise "ERROR: Unable to connect to Appium. Is the server running on #{@custom_url}?"
|
502
|
+
end
|
503
|
+
|
504
|
+
@driver
|
505
|
+
end
|
398
506
|
|
399
507
|
def get_http_client(http_client: nil, open_timeout: nil, read_timeout: nil)
|
400
508
|
client = http_client || Appium::Core::Base::Http::Default.new
|
@@ -420,9 +528,7 @@ module Appium
|
|
420
528
|
{}
|
421
529
|
end
|
422
530
|
|
423
|
-
|
424
|
-
|
425
|
-
# Quits the driver
|
531
|
+
# [Deprecated] Quits the driver. This method is the same as @driver.quit
|
426
532
|
# @return [void]
|
427
533
|
#
|
428
534
|
# @example
|
@@ -430,6 +536,7 @@ module Appium
|
|
430
536
|
# @core.quit_driver
|
431
537
|
#
|
432
538
|
def quit_driver
|
539
|
+
::Appium::Logger.warn('[DEPRECATION] quit_driver will be removed. Please use @driver.quit instead.')
|
433
540
|
@driver.quit
|
434
541
|
rescue # rubocop:disable Style/RescueStandardError
|
435
542
|
nil
|
@@ -475,20 +582,35 @@ module Appium
|
|
475
582
|
# @core.platform_version #=> [10,1,1]
|
476
583
|
#
|
477
584
|
def platform_version
|
585
|
+
::Appium::Logger.warn(
|
586
|
+
'[DEPRECATION] platform_version method will be. ' \
|
587
|
+
'Please check the platformVersion via @driver.capabilities["platformVersion"] instead.'
|
588
|
+
)
|
589
|
+
|
478
590
|
p_version = @driver.capabilities['platformVersion'] || @driver.session_capabilities['platformVersion']
|
479
591
|
p_version.split('.').map(&:to_i)
|
480
592
|
end
|
481
593
|
|
482
594
|
private
|
483
595
|
|
596
|
+
def convert_to_symbol(value)
|
597
|
+
if value.nil?
|
598
|
+
value
|
599
|
+
else
|
600
|
+
value.to_sym
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
484
604
|
# @private
|
485
605
|
def extend_for(device:, automation_name:) # rubocop:disable Metrics/CyclomaticComplexity
|
486
606
|
extend Appium::Core
|
487
607
|
extend Appium::Core::Device
|
488
608
|
|
489
|
-
|
609
|
+
sym_automation_name = convert_to_symbol(automation_name)
|
610
|
+
|
611
|
+
case convert_to_symbol(device)
|
490
612
|
when :android
|
491
|
-
case
|
613
|
+
case sym_automation_name
|
492
614
|
when :espresso
|
493
615
|
::Appium::Core::Android::Espresso::Bridge.for self
|
494
616
|
when :uiautomator2
|
@@ -499,16 +621,14 @@ module Appium
|
|
499
621
|
::Appium::Core::Android::Uiautomator1::Bridge.for self
|
500
622
|
end
|
501
623
|
when :ios, :tvos
|
502
|
-
case
|
624
|
+
case sym_automation_name
|
503
625
|
when :safari
|
504
626
|
::Appium::Logger.debug('SafariDriver for iOS')
|
505
|
-
|
627
|
+
else # XCUITest
|
506
628
|
::Appium::Core::Ios::Xcuitest::Bridge.for self
|
507
|
-
else # default and UIAutomation
|
508
|
-
::Appium::Core::Ios::Uiautomation::Bridge.for self
|
509
629
|
end
|
510
630
|
when :mac
|
511
|
-
case
|
631
|
+
case sym_automation_name
|
512
632
|
when :safari
|
513
633
|
::Appium::Logger.debug('SafariDriver for macOS')
|
514
634
|
when :gecko
|
@@ -520,7 +640,7 @@ module Appium
|
|
520
640
|
::Appium::Logger.debug('macOS Native')
|
521
641
|
end
|
522
642
|
when :windows
|
523
|
-
case
|
643
|
+
case sym_automation_name
|
524
644
|
when :gecko
|
525
645
|
::Appium::Logger.debug('Gecko Driver for Windows')
|
526
646
|
else
|
@@ -530,7 +650,7 @@ module Appium
|
|
530
650
|
# https://github.com/Samsung/appium-tizen-driver
|
531
651
|
::Appium::Logger.debug('tizen')
|
532
652
|
else
|
533
|
-
case
|
653
|
+
case sym_automation_name
|
534
654
|
when :youiengine
|
535
655
|
# https://github.com/YOU-i-Labs/appium-youiengine-driver
|
536
656
|
::Appium::Logger.debug('YouiEngine')
|
@@ -547,32 +667,9 @@ module Appium
|
|
547
667
|
self
|
548
668
|
end
|
549
669
|
|
550
|
-
# @private
|
551
|
-
def validate_keys(opts)
|
552
|
-
flatten_ops = flatten_hash_keys(opts)
|
553
|
-
|
554
|
-
raise Error::NoCapabilityError unless opts.member?(:caps) || opts.member?(:capabilities)
|
555
|
-
|
556
|
-
if !opts.member?(:appium_lib) && flatten_ops.member?(:appium_lib)
|
557
|
-
raise Error::CapabilityStructureError, 'Please check the value of appium_lib in the capability'
|
558
|
-
end
|
559
|
-
|
560
|
-
true
|
561
|
-
end
|
562
|
-
|
563
|
-
# @private
|
564
|
-
def flatten_hash_keys(hash, flatten_keys_result = [])
|
565
|
-
hash.each do |key, value|
|
566
|
-
flatten_keys_result << key
|
567
|
-
flatten_hash_keys(value, flatten_keys_result) if value.is_a?(Hash)
|
568
|
-
end
|
569
|
-
|
570
|
-
flatten_keys_result
|
571
|
-
end
|
572
|
-
|
573
670
|
# @private
|
574
671
|
def get_caps(opts)
|
575
|
-
Core::Base::Capabilities.
|
672
|
+
Core::Base::Capabilities.new(opts[:caps] || opts[:capabilities] || {})
|
576
673
|
end
|
577
674
|
|
578
675
|
# @private
|
@@ -585,6 +682,7 @@ module Appium
|
|
585
682
|
# The path can be local, HTTP/S, Windows Share and other path like 'sauce-storage:'.
|
586
683
|
# Use @caps[:app] without modifications if the path isn't HTTP/S or local path.
|
587
684
|
def set_app_path
|
685
|
+
# FIXME: maybe `:app` should check `app` as well.
|
588
686
|
return unless @caps && @caps[:app] && !@caps[:app].empty?
|
589
687
|
return if @caps[:app] =~ URI::DEFAULT_PARSER.make_regexp
|
590
688
|
|
@@ -623,18 +721,24 @@ module Appium
|
|
623
721
|
# @private
|
624
722
|
def set_appium_device
|
625
723
|
# https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile
|
626
|
-
|
724
|
+
# TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
|
725
|
+
@device = @caps[:platformName] || @caps['platformName']
|
627
726
|
return @device unless @device
|
628
727
|
|
629
|
-
@device =
|
728
|
+
@device = convert_downcase @device
|
630
729
|
end
|
631
730
|
|
632
731
|
# @private
|
633
732
|
def set_automation_name
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
733
|
+
# TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
|
734
|
+
candidate = @caps[:automationName] || @caps['automationName']
|
735
|
+
@automation_name = candidate if candidate
|
736
|
+
@automation_name = convert_downcase @automation_name if @automation_name
|
737
|
+
end
|
738
|
+
|
739
|
+
# @private
|
740
|
+
def convert_downcase(value)
|
741
|
+
value.is_a?(Symbol) ? value.downcase : value.downcase.strip.intern
|
638
742
|
end
|
639
743
|
|
640
744
|
# @private
|
@@ -648,6 +752,10 @@ module Appium
|
|
648
752
|
|
649
753
|
# @private
|
650
754
|
def write_session_id(session_id, export_path = '/tmp/appium_lib_session')
|
755
|
+
::Appium::Logger.warn(
|
756
|
+
'[DEPRECATION] export_session option will be removed. ' \
|
757
|
+
'Please save the session id by yourself with #session_id method like @driver.session_id.'
|
758
|
+
)
|
651
759
|
export_path = export_path.tr('/', '\\') if ::Appium::Core::Base.platform.windows?
|
652
760
|
File.write(export_path, session_id)
|
653
761
|
rescue IOError => e
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module Appium
|
16
|
+
module Support
|
17
|
+
class EventFiringBridge < ::Selenium::WebDriver::Support::EventFiringBridge
|
18
|
+
# This module inherits ::Selenium::WebDriver::Support::EventFiringBridge
|
19
|
+
# to provide customer listener availability.
|
20
|
+
# https://github.com/SeleniumHQ/selenium/blob/trunk/rb/lib/selenium/webdriver/support/event_firing_bridge.rb#L79
|
21
|
+
|
22
|
+
def initialize(delegate, listener, **opts)
|
23
|
+
@appium_options = opts
|
24
|
+
super delegate, listener
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_element_by(how, what, parent = nil)
|
28
|
+
e = dispatch(:find, how, what, driver) do
|
29
|
+
@delegate.find_element_by how, what, parent
|
30
|
+
end
|
31
|
+
|
32
|
+
::Appium::Core::Element.new self, e.ref.last
|
33
|
+
end
|
34
|
+
|
35
|
+
def find_elements_by(how, what, parent = nil)
|
36
|
+
es = dispatch(:find, how, what, driver) do
|
37
|
+
@delegate.find_elements_by(how, what, parent)
|
38
|
+
end
|
39
|
+
|
40
|
+
es.map { |e| ::Appium::Core::Element.new self, e.ref.last }
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def create_element(ref)
|
46
|
+
::Appium::Core::Element.new @delegate, ref
|
47
|
+
end
|
48
|
+
|
49
|
+
def driver
|
50
|
+
# To not gives the listener
|
51
|
+
@appium_options.delete(:listener)
|
52
|
+
|
53
|
+
@driver ||= ::Appium::Core::Base::Driver.new(bridge: self, listener: nil, **@appium_options)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
module Appium
|
16
16
|
module Core
|
17
|
-
VERSION = '
|
18
|
-
DATE = '
|
17
|
+
VERSION = '6.3.0' unless defined? ::Appium::Core::VERSION
|
18
|
+
DATE = '2023-03-14' unless defined? ::Appium::Core::DATE
|
19
19
|
end
|
20
20
|
end
|
@@ -14,17 +14,25 @@
|
|
14
14
|
|
15
15
|
module Appium
|
16
16
|
module Core
|
17
|
-
module
|
18
|
-
module
|
19
|
-
module
|
20
|
-
|
21
|
-
|
17
|
+
module Windows
|
18
|
+
module Device
|
19
|
+
module AppManagement
|
20
|
+
# override
|
21
|
+
def self.add_methods
|
22
|
+
::Appium::Core::Device.add_endpoint_method(:launch_app) do
|
23
|
+
def launch_app
|
24
|
+
execute :launch_app
|
25
|
+
end
|
26
|
+
end
|
22
27
|
|
23
|
-
Core::
|
24
|
-
|
28
|
+
::Appium::Core::Device.add_endpoint_method(:close_app) do
|
29
|
+
def close_app
|
30
|
+
execute :close_app
|
31
|
+
end
|
32
|
+
end
|
25
33
|
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
34
|
+
end # module AppManagement
|
35
|
+
end # module Device
|
36
|
+
end # module Windows
|
37
|
+
end # module Core
|
38
|
+
end # module Appium
|
@@ -13,6 +13,7 @@
|
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
15
|
require_relative 'device/screen'
|
16
|
+
require_relative 'device/app_management'
|
16
17
|
|
17
18
|
module Appium
|
18
19
|
module Core
|
@@ -78,6 +79,7 @@ module Appium
|
|
78
79
|
class << self
|
79
80
|
def extended(_mod)
|
80
81
|
Screen.add_methods
|
82
|
+
AppManagement.add_methods
|
81
83
|
end
|
82
84
|
end # class << self
|
83
85
|
end # module Device
|
data/lib/appium_lib_core.rb
CHANGED
@@ -19,18 +19,28 @@ require_relative 'appium_lib_core/common'
|
|
19
19
|
require_relative 'appium_lib_core/driver'
|
20
20
|
require_relative 'appium_lib_core/device'
|
21
21
|
require_relative 'appium_lib_core/element'
|
22
|
+
require_relative 'appium_lib_core/support/event_firing_bridge'
|
22
23
|
|
23
24
|
module Appium
|
24
|
-
#
|
25
|
+
# @private
|
26
|
+
#
|
27
|
+
# convert the top level keys to symbols.
|
25
28
|
#
|
26
|
-
# based on deep_symbolize_keys & deep_transform_keys from rails
|
27
|
-
# https://github.com/rails/docrails/blob/a3b1105ada3da64acfa3843b164b14b734456a50/activesupport/lib/active_support/core_ext/hash/keys.rb#L84
|
28
29
|
# @param [Hash] hash Hash value to make symbolise
|
29
|
-
def self.symbolize_keys(hash)
|
30
|
+
def self.symbolize_keys(hash, nested: false, enable_deprecation_msg: true)
|
31
|
+
# FIXME: As https://github.com/appium/ruby_lib/issues/945, we must remove this implicit string to symbol.
|
32
|
+
# But appium_lib_core's some capability handling expect to be symbol, so we should test to remove
|
33
|
+
# the mehotds which expect the symbol first.
|
30
34
|
raise ::Appium::Core::Error::ArgumentError, 'symbolize_keys requires a hash' unless hash.is_a? Hash
|
31
35
|
|
32
36
|
hash.each_with_object({}) do |pair, acc|
|
33
37
|
key = begin
|
38
|
+
if enable_deprecation_msg && !(pair[0].is_a? Symbol)
|
39
|
+
::Appium::Logger.warn("[Deprecation] The key '#{pair[0]}' must be a symbol while currently it " \
|
40
|
+
"is #{pair[0].class.name}. Please define the key as a Symbol. " \
|
41
|
+
'Converting it to Symbol for now.')
|
42
|
+
end
|
43
|
+
|
34
44
|
pair[0].to_sym
|
35
45
|
rescue StandardError => e
|
36
46
|
::Appium::Logger.warn(e.message)
|
@@ -38,7 +48,11 @@ module Appium
|
|
38
48
|
end
|
39
49
|
|
40
50
|
value = pair[1]
|
41
|
-
acc[key] =
|
51
|
+
acc[key] = if nested
|
52
|
+
value.is_a?(Hash) ? symbolize_keys(value, nested: false, enable_deprecation_msg: false) : value
|
53
|
+
else
|
54
|
+
value
|
55
|
+
end
|
42
56
|
end
|
43
57
|
end
|
44
58
|
|