appium_lib_core 4.1.0 → 5.6.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 +176 -273
- data/README.md +22 -11
- 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 -5
- 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 +68 -82
- 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 +20 -10
- 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
@@ -79,11 +79,7 @@ module Appium
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def create_bridge_command(method, &block)
|
82
|
-
::Appium::Core::Base::Bridge
|
83
|
-
undef_method method if method_defined? method
|
84
|
-
block_given? ? class_eval(&block) : define_method(method) { execute method }
|
85
|
-
end
|
86
|
-
::Appium::Core::Base::Bridge::W3C.class_eval do
|
82
|
+
::Appium::Core::Base::Bridge.class_eval do
|
87
83
|
undef_method method if method_defined? method
|
88
84
|
block_given? ? class_eval(&block) : define_method(method) { execute method }
|
89
85
|
end
|
@@ -27,6 +27,8 @@ module Appium
|
|
27
27
|
autoload :Xcuitest, 'appium_lib_core/ios_xcuitest'
|
28
28
|
end
|
29
29
|
|
30
|
+
autoload :Mac2, 'appium_lib_core/mac2'
|
31
|
+
|
30
32
|
autoload :Windows, 'appium_lib_core/windows'
|
31
33
|
|
32
34
|
# This options affects only client side as <code>:appium_lib</code> key.<br>
|
@@ -38,18 +40,18 @@ module Appium
|
|
38
40
|
|
39
41
|
def initialize(appium_lib_opts)
|
40
42
|
@custom_url = appium_lib_opts.fetch :server_url, nil
|
41
|
-
@default_wait = appium_lib_opts.fetch :wait,
|
43
|
+
@default_wait = appium_lib_opts.fetch :wait, nil
|
42
44
|
@enable_idempotency_header = appium_lib_opts.fetch :enable_idempotency_header, true
|
43
45
|
|
44
46
|
# bump current session id into a particular file
|
45
47
|
@export_session = appium_lib_opts.fetch :export_session, false
|
46
48
|
@export_session_path = appium_lib_opts.fetch :export_session_path, default_tmp_appium_lib_session
|
47
49
|
|
48
|
-
@direct_connect = appium_lib_opts.fetch :direct_connect,
|
50
|
+
@direct_connect = appium_lib_opts.fetch :direct_connect, true
|
49
51
|
|
50
52
|
@port = appium_lib_opts.fetch :port, Driver::DEFAULT_APPIUM_PORT
|
51
53
|
|
52
|
-
# timeout and interval used in ::Appium::
|
54
|
+
# timeout and interval used in ::Appium::Commn.wait/wait_true
|
53
55
|
@wait_timeout = appium_lib_opts.fetch :wait_timeout, ::Appium::Core::Wait::DEFAULT_TIMEOUT
|
54
56
|
@wait_interval = appium_lib_opts.fetch :wait_interval, ::Appium::Core::Wait::DEFAULT_INTERVAL
|
55
57
|
|
@@ -74,6 +76,13 @@ module Appium
|
|
74
76
|
path: 'directConnectPath'
|
75
77
|
}.freeze
|
76
78
|
|
79
|
+
W3C_KEYS = {
|
80
|
+
protocol: 'appium:directConnectProtocol',
|
81
|
+
host: 'appium:directConnectHost',
|
82
|
+
port: 'appium:directConnectPort',
|
83
|
+
path: 'appium:directConnectPath'
|
84
|
+
}.freeze
|
85
|
+
|
77
86
|
# @return [string] Returns a protocol such as http/https
|
78
87
|
attr_reader :protocol
|
79
88
|
|
@@ -87,10 +96,10 @@ module Appium
|
|
87
96
|
attr_reader :path
|
88
97
|
|
89
98
|
def initialize(capabilities)
|
90
|
-
@protocol = capabilities[KEYS[:protocol]]
|
91
|
-
@host = capabilities[KEYS[:host]]
|
92
|
-
@port = capabilities[KEYS[:port]]
|
93
|
-
@path = capabilities[KEYS[:path]]
|
99
|
+
@protocol = capabilities[W3C_KEYS[:protocol]] || capabilities[KEYS[:protocol]]
|
100
|
+
@host = capabilities[W3C_KEYS[:host]] || capabilities[KEYS[:host]]
|
101
|
+
@port = capabilities[W3C_KEYS[:port]] || capabilities[KEYS[:port]]
|
102
|
+
@path = capabilities[W3C_KEYS[:path]] || capabilities[KEYS[:path]]
|
94
103
|
end
|
95
104
|
end
|
96
105
|
|
@@ -133,11 +142,9 @@ module Appium
|
|
133
142
|
attr_reader :export_session_path
|
134
143
|
|
135
144
|
# Default wait time for elements to appear in Appium server side.
|
136
|
-
# Defaults to {::Appium::Core::Driver::DEFAULT_IMPLICIT_WAIT}.<br>
|
137
145
|
# Provide <code>{ appium_lib: { wait: 30 } }</code> to {::Appium::Core.for}
|
138
146
|
# @return [Integer]
|
139
147
|
attr_reader :default_wait
|
140
|
-
DEFAULT_IMPLICIT_WAIT = 0
|
141
148
|
|
142
149
|
# Appium's server port. 4723 is by default. Defaults to {::Appium::Core::Driver::DEFAULT_APPIUM_PORT}.<br>
|
143
150
|
# Provide <code>{ appium_lib: { port: 8080 } }</code> to {::Appium::Core.for}.
|
@@ -175,7 +182,8 @@ module Appium
|
|
175
182
|
# - <code>directConnectPort</code>
|
176
183
|
# - <code>directConnectPath</code>
|
177
184
|
#
|
178
|
-
#
|
185
|
+
# ignore them if this parameter is <code>false</code>. Defaults to true.
|
186
|
+
# These keys can have <code>appium:</code> prefix.
|
179
187
|
#
|
180
188
|
# @return [Bool]
|
181
189
|
attr_reader :direct_connect
|
@@ -185,8 +193,6 @@ module Appium
|
|
185
193
|
# @option opts [Hash] :caps Appium capabilities.
|
186
194
|
# @option opts [Hash] :capabilities The same as :caps.
|
187
195
|
# 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
196
|
# @option opts [Appium::Core::Options] :appium_lib Capabilities affect only ruby client
|
191
197
|
# @option opts [String] :url The same as :custom_url in :appium_lib.
|
192
198
|
# This param is for compatibility with Selenium WebDriver format
|
@@ -197,10 +203,8 @@ module Appium
|
|
197
203
|
#
|
198
204
|
# # format 1
|
199
205
|
# @core = Appium::Core.for caps: {...}, appium_lib: {...}
|
200
|
-
# # format 2. 'capabilities:'
|
206
|
+
# # format 2. 'capabilities:' is also available instead of 'caps:'.
|
201
207
|
# @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
208
|
#
|
205
209
|
#
|
206
210
|
# require 'rubygems'
|
@@ -228,7 +232,7 @@ module Appium
|
|
228
232
|
# @core.start_driver # Connect to 'http://127.0.0.1:8080/wd/hub' because of 'port: 8080'
|
229
233
|
#
|
230
234
|
# # Start iOS driver with .zip file over HTTP
|
231
|
-
# #
|
235
|
+
# # 'capabilities:' is also available instead of 'caps:'. Either is fine.
|
232
236
|
# opts = {
|
233
237
|
# capabilities: {
|
234
238
|
# platformName: :ios,
|
@@ -252,7 +256,7 @@ module Appium
|
|
252
256
|
# # Start iOS driver as another format. 'url' is available like below
|
253
257
|
# opts = {
|
254
258
|
# url: "http://custom-host:8080/wd/hub.com",
|
255
|
-
#
|
259
|
+
# capabilities: {
|
256
260
|
# platformName: :ios,
|
257
261
|
# platformVersion: '11.0',
|
258
262
|
# deviceName: 'iPhone Simulator',
|
@@ -289,8 +293,11 @@ module Appium
|
|
289
293
|
@delegate_target = self # for testing purpose
|
290
294
|
@automation_name = nil # initialise before 'set_automation_name'
|
291
295
|
|
292
|
-
|
293
|
-
|
296
|
+
# TODO: Remove when we implement Options
|
297
|
+
# The symbolize_keys is to keep compatiility for the legacy code, which allows capabilities to give 'string' as the key.
|
298
|
+
# The toplevel `caps`, `capabilities` and `appium_lib` are expected to be symbol.
|
299
|
+
# FIXME: First, please try to remove `nested: true` to `nested: false`.
|
300
|
+
opts = Appium.symbolize_keys(opts, nested: true)
|
294
301
|
|
295
302
|
@custom_url = opts.delete :url
|
296
303
|
@caps = get_caps(opts)
|
@@ -324,7 +331,7 @@ module Appium
|
|
324
331
|
#
|
325
332
|
# # Start iOS driver
|
326
333
|
# opts = {
|
327
|
-
#
|
334
|
+
# capabilities: {
|
328
335
|
# platformName: :ios,
|
329
336
|
# platformVersion: '11.0',
|
330
337
|
# deviceName: 'iPhone Simulator',
|
@@ -365,11 +372,13 @@ module Appium
|
|
365
372
|
end
|
366
373
|
|
367
374
|
begin
|
368
|
-
|
369
|
-
|
370
|
-
|
375
|
+
@driver = ::Appium::Core::Base::Driver.new(listener: @listener,
|
376
|
+
http_client: @http_client,
|
377
|
+
capabilities: @caps, # ::Appium::Core::Base::Capabilities
|
371
378
|
url: @custom_url,
|
372
|
-
|
379
|
+
wait_timeout: @wait_timeout,
|
380
|
+
wait_interval: @wait_interval,
|
381
|
+
automation_name: @automation_name)
|
373
382
|
|
374
383
|
if @direct_connect
|
375
384
|
d_c = DirectConnections.new(@driver.capabilities)
|
@@ -410,6 +419,8 @@ module Appium
|
|
410
419
|
|
411
420
|
# Ignore setting default wait if the target driver has no implementation
|
412
421
|
def set_implicit_wait_by_default(wait)
|
422
|
+
return if @default_wait.nil?
|
423
|
+
|
413
424
|
@driver.manage.timeouts.implicit_wait = wait
|
414
425
|
rescue ::Selenium::WebDriver::Error::UnknownError => e
|
415
426
|
unless e.message.include?('The operation requested is not yet implemented')
|
@@ -435,7 +446,8 @@ module Appium
|
|
435
446
|
nil
|
436
447
|
end
|
437
448
|
|
438
|
-
# Returns the server's version info
|
449
|
+
# Returns the server's version info. This method calls +driver.remote_status+ internally
|
450
|
+
#
|
439
451
|
# @return [Hash]
|
440
452
|
#
|
441
453
|
# @example
|
@@ -449,18 +461,20 @@ module Appium
|
|
449
461
|
# }
|
450
462
|
# }
|
451
463
|
#
|
452
|
-
# Returns blank hash
|
464
|
+
# Returns blank hash in a case +driver.remote_status+ got an error
|
465
|
+
# such as Selenium Grid. It returns 500 error against 'remote_status'.
|
453
466
|
#
|
454
467
|
# @example
|
455
468
|
#
|
456
469
|
# @core.appium_server_version #=> {}
|
457
470
|
#
|
458
471
|
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')
|
472
|
+
return {} if @driver.nil?
|
462
473
|
|
463
|
-
|
474
|
+
@driver.remote_status
|
475
|
+
rescue StandardError
|
476
|
+
# Ignore error case in a case the target appium server
|
477
|
+
# does not support `/status` API.
|
464
478
|
{}
|
465
479
|
end
|
466
480
|
|
@@ -476,31 +490,26 @@ module Appium
|
|
476
490
|
p_version.split('.').map(&:to_i)
|
477
491
|
end
|
478
492
|
|
479
|
-
# Takes a png screenshot and saves to the target path.
|
480
|
-
#
|
481
|
-
# @param png_save_path [String] the full path to save the png
|
482
|
-
# @return [File]
|
483
|
-
#
|
484
|
-
# @example
|
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
|
492
|
-
end
|
493
|
-
|
494
493
|
private
|
495
494
|
|
495
|
+
def convert_to_symbol(value)
|
496
|
+
if value.nil?
|
497
|
+
value
|
498
|
+
else
|
499
|
+
value.to_sym
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
496
503
|
# @private
|
497
504
|
def extend_for(device:, automation_name:) # rubocop:disable Metrics/CyclomaticComplexity
|
498
505
|
extend Appium::Core
|
499
506
|
extend Appium::Core::Device
|
500
507
|
|
501
|
-
|
508
|
+
sym_automation_name = convert_to_symbol(automation_name)
|
509
|
+
|
510
|
+
case convert_to_symbol(device)
|
502
511
|
when :android
|
503
|
-
case
|
512
|
+
case sym_automation_name
|
504
513
|
when :espresso
|
505
514
|
::Appium::Core::Android::Espresso::Bridge.for self
|
506
515
|
when :uiautomator2
|
@@ -511,7 +520,7 @@ module Appium
|
|
511
520
|
::Appium::Core::Android::Uiautomator1::Bridge.for self
|
512
521
|
end
|
513
522
|
when :ios, :tvos
|
514
|
-
case
|
523
|
+
case sym_automation_name
|
515
524
|
when :safari
|
516
525
|
::Appium::Logger.debug('SafariDriver for iOS')
|
517
526
|
when :xcuitest
|
@@ -520,19 +529,19 @@ module Appium
|
|
520
529
|
::Appium::Core::Ios::Uiautomation::Bridge.for self
|
521
530
|
end
|
522
531
|
when :mac
|
523
|
-
case
|
532
|
+
case sym_automation_name
|
524
533
|
when :safari
|
525
534
|
::Appium::Logger.debug('SafariDriver for macOS')
|
526
535
|
when :gecko
|
527
536
|
::Appium::Logger.debug('Gecko Driver for macOS')
|
528
537
|
when :mac2
|
529
|
-
::Appium::
|
538
|
+
::Appium::Core::Mac2::Bridge.for self
|
530
539
|
else
|
531
540
|
# no Mac specific extentions
|
532
541
|
::Appium::Logger.debug('macOS Native')
|
533
542
|
end
|
534
543
|
when :windows
|
535
|
-
case
|
544
|
+
case sym_automation_name
|
536
545
|
when :gecko
|
537
546
|
::Appium::Logger.debug('Gecko Driver for Windows')
|
538
547
|
else
|
@@ -542,7 +551,7 @@ module Appium
|
|
542
551
|
# https://github.com/Samsung/appium-tizen-driver
|
543
552
|
::Appium::Logger.debug('tizen')
|
544
553
|
else
|
545
|
-
case
|
554
|
+
case sym_automation_name
|
546
555
|
when :youiengine
|
547
556
|
# https://github.com/YOU-i-Labs/appium-youiengine-driver
|
548
557
|
::Appium::Logger.debug('YouiEngine')
|
@@ -559,36 +568,9 @@ module Appium
|
|
559
568
|
self
|
560
569
|
end
|
561
570
|
|
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
571
|
# @private
|
589
572
|
def get_caps(opts)
|
590
|
-
|
591
|
-
Core::Base::Capabilities.create_capabilities(opts[:caps] || opts[:capabilities] || opts[:desired_capabilities] || {})
|
573
|
+
Core::Base::Capabilities.new(opts[:caps] || opts[:capabilities] || {})
|
592
574
|
end
|
593
575
|
|
594
576
|
# @private
|
@@ -601,6 +583,7 @@ module Appium
|
|
601
583
|
# The path can be local, HTTP/S, Windows Share and other path like 'sauce-storage:'.
|
602
584
|
# Use @caps[:app] without modifications if the path isn't HTTP/S or local path.
|
603
585
|
def set_app_path
|
586
|
+
# FIXME: maybe `:app` should check `app` as well.
|
604
587
|
return unless @caps && @caps[:app] && !@caps[:app].empty?
|
605
588
|
return if @caps[:app] =~ URI::DEFAULT_PARSER.make_regexp
|
606
589
|
|
@@ -639,7 +622,8 @@ module Appium
|
|
639
622
|
# @private
|
640
623
|
def set_appium_device
|
641
624
|
# https://code.google.com/p/selenium/source/browse/spec-draft.md?repo=mobile
|
642
|
-
|
625
|
+
# TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
|
626
|
+
@device = @caps[:platformName] || @caps['platformName']
|
643
627
|
return @device unless @device
|
644
628
|
|
645
629
|
@device = @device.is_a?(Symbol) ? @device.downcase : @device.downcase.strip.intern
|
@@ -647,7 +631,9 @@ module Appium
|
|
647
631
|
|
648
632
|
# @private
|
649
633
|
def set_automation_name
|
650
|
-
|
634
|
+
# TODO: check if the Appium.symbolize_keys(opts, nested: false) enoug with this
|
635
|
+
candidate = @caps[:automationName] || @caps['automationName']
|
636
|
+
@automation_name = candidate if candidate
|
651
637
|
@automation_name = if @automation_name
|
652
638
|
@automation_name.is_a?(Symbol) ? @automation_name.downcase : @automation_name.downcase.strip.intern
|
653
639
|
end
|
@@ -12,14 +12,22 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
# rubocop:disable Style/ClassAndModuleChildren
|
16
15
|
module Appium
|
17
16
|
module Core
|
18
17
|
# Implement useful features for element.
|
19
18
|
# Patch for Selenium Webdriver.
|
20
|
-
class Selenium::WebDriver::Element
|
21
|
-
# To extend Appium related SearchContext into ::Selenium::WebDriver::Element
|
19
|
+
class Element < ::Selenium::WebDriver::Element
|
22
20
|
include ::Appium::Core::Base::SearchContext
|
21
|
+
include ::Appium::Core::Base::TakesScreenshot
|
22
|
+
|
23
|
+
# Retuns the element id.
|
24
|
+
#
|
25
|
+
# @return [String]
|
26
|
+
# @example
|
27
|
+
# e = @driver.find_element :accessibility_id, 'something'
|
28
|
+
# e.id
|
29
|
+
#
|
30
|
+
attr_reader :id
|
23
31
|
|
24
32
|
# Returns the value of attributes like below. Read each platform to know more details.
|
25
33
|
#
|
@@ -60,20 +68,20 @@ module Appium
|
|
60
68
|
#
|
61
69
|
# @example
|
62
70
|
#
|
63
|
-
#
|
71
|
+
# element.immediate_value 'hello'
|
64
72
|
#
|
65
73
|
def immediate_value(*value)
|
66
|
-
@bridge.set_immediate_value
|
74
|
+
@bridge.set_immediate_value @id, *value
|
67
75
|
end
|
68
76
|
|
69
77
|
# Replace the value to element directly
|
70
78
|
#
|
71
79
|
# @example
|
72
80
|
#
|
73
|
-
#
|
81
|
+
# element.replace_value 'hello'
|
74
82
|
#
|
75
83
|
def replace_value(*value)
|
76
|
-
@bridge.replace_value
|
84
|
+
@bridge.replace_value @id, *value
|
77
85
|
end
|
78
86
|
|
79
87
|
# For use with location_rel.
|
@@ -99,7 +107,56 @@ module Appium
|
|
99
107
|
w = driver.window_size
|
100
108
|
::Selenium::WebDriver::Point.new "#{center_x} / #{w.width.to_f}", "#{center_y} / #{w.height.to_f}"
|
101
109
|
end
|
102
|
-
|
110
|
+
|
111
|
+
# Return an element screenshot as base64
|
112
|
+
#
|
113
|
+
# @return String Base 64 encoded string
|
114
|
+
#
|
115
|
+
# @example
|
116
|
+
#
|
117
|
+
# element.screenshot #=> "iVBORw0KGgoAAAANSUhEUgAABDgAAAB+CAIAAABOPDa6AAAAAX"
|
118
|
+
#
|
119
|
+
def screenshot
|
120
|
+
bridge.element_screenshot @id
|
121
|
+
end
|
122
|
+
|
123
|
+
# Return an element screenshot in the given format
|
124
|
+
#
|
125
|
+
# @param [:base64, :png] format
|
126
|
+
# @return String screenshot
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
#
|
130
|
+
# element.screenshot_as :base64 #=> "iVBORw0KGgoAAAANSUhEUgAABDgAAAB+CAIAAABOPDa6AAAAAX"
|
131
|
+
#
|
132
|
+
def screenshot_as(format)
|
133
|
+
case format
|
134
|
+
when :base64
|
135
|
+
bridge.element_screenshot @id
|
136
|
+
when :png
|
137
|
+
bridge.element_screenshot(@id).unpack('m')[0]
|
138
|
+
else
|
139
|
+
raise Core::Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Save an element screenshot to the given path
|
144
|
+
#
|
145
|
+
# @param [String] png_path A path to save the screenshot
|
146
|
+
# @return [File] Path to the element screenshot.
|
147
|
+
#
|
148
|
+
# @example
|
149
|
+
#
|
150
|
+
# element.save_screenshot("fine_name.png")
|
151
|
+
#
|
152
|
+
def save_screenshot(png_path)
|
153
|
+
extension = File.extname(png_path).downcase
|
154
|
+
if extension != '.png'
|
155
|
+
::Appium::Logger.warn 'name used for saved screenshot does not match file type. '\
|
156
|
+
'It should end with .png extension'
|
157
|
+
end
|
158
|
+
File.open(png_path, 'wb') { |f| f << screenshot_as(:png) }
|
159
|
+
end
|
160
|
+
end # class Element
|
103
161
|
end # module Core
|
104
162
|
end # module Appium
|
105
|
-
# rubocop:enable Style/ClassAndModuleChildren
|
@@ -21,7 +21,7 @@ module Appium
|
|
21
21
|
# will trigger as soon as the file is required. in contrast a method
|
22
22
|
# will trigger only when invoked.
|
23
23
|
def self.patch_webdriver_element
|
24
|
-
::
|
24
|
+
::Appium::Core::Element.class_eval do
|
25
25
|
# Cross platform way of entering text into a textfield
|
26
26
|
def type(text, driver)
|
27
27
|
driver.execute_script %(au.getElement('#{ref}').setValue('#{text}');)
|
@@ -14,11 +14,12 @@
|
|
14
14
|
|
15
15
|
module Appium
|
16
16
|
module Core
|
17
|
-
|
18
|
-
module
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
17
|
+
module Mac2
|
18
|
+
module Bridge
|
19
|
+
def self.for(target)
|
20
|
+
target.extend Appium::Core::Mac2::Device
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,48 @@
|
|
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 Core
|
17
|
+
module Mac2
|
18
|
+
module Device
|
19
|
+
module Screen
|
20
|
+
def self.add_methods
|
21
|
+
::Appium::Core::Device.add_endpoint_method(:start_recording_screen) do
|
22
|
+
def start_recording_screen(remote_path: nil, user: nil, pass: nil, method: 'PUT',
|
23
|
+
file_field_name: nil, form_fields: nil, headers: nil, force_restart: nil,
|
24
|
+
fps: nil, preset: nil, video_filter: nil, time_limit: nil,
|
25
|
+
enable_capture_clicks: nil, enable_cursor_capture: nil, device_id: nil)
|
26
|
+
option = ::Appium::Core::Base::Device::ScreenRecord.new(
|
27
|
+
remote_path: remote_path, user: user, pass: pass, method: method,
|
28
|
+
file_field_name: file_field_name, form_fields: form_fields, headers: headers,
|
29
|
+
force_restart: force_restart
|
30
|
+
).upload_option
|
31
|
+
|
32
|
+
option[:fps] = fps unless fps.nil?
|
33
|
+
option[:preset] = preset unless preset.nil?
|
34
|
+
option[:videoFilter] = video_filter unless video_filter.nil?
|
35
|
+
option[:captureClicks] = enable_capture_clicks unless enable_capture_clicks.nil?
|
36
|
+
option[:captureCursor] = enable_cursor_capture unless enable_cursor_capture.nil?
|
37
|
+
option[:deviceId] = device_id unless device_id.nil?
|
38
|
+
option[:timeLimit] = time_limit unless time_limit.nil?
|
39
|
+
|
40
|
+
execute(:start_recording_screen, {}, { options: option })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end # module Screen
|
45
|
+
end # module Device
|
46
|
+
end # module Mac2
|
47
|
+
end # module Core
|
48
|
+
end # module Appium
|
@@ -0,0 +1,92 @@
|
|
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
|
+
require_relative 'device/screen'
|
16
|
+
|
17
|
+
module Appium
|
18
|
+
module Core
|
19
|
+
module Mac2
|
20
|
+
module Device
|
21
|
+
extend Forwardable
|
22
|
+
|
23
|
+
# rubocop:disable Layout/LineLength
|
24
|
+
|
25
|
+
# @since Appium 1.20.0
|
26
|
+
# @!method start_recording_screen(remote_path: nil, user: nil, pass: nil, method: 'PUT', file_field_name: nil, form_fields: nil, headers: nil, force_restart: nil, fps: nil, preset: nil, video_filter: nil, enable_capture_clicks: nil, enable_cursor_capture: nil, device_id: nil)
|
27
|
+
#
|
28
|
+
# Record the display of devices running iOS Simulator since Xcode 9 or real devices since iOS 11
|
29
|
+
# (ffmpeg utility is required: 'brew install ffmpeg').
|
30
|
+
# We would recommend to play the video by VLC or Mplayer if you can not play the video with other video players.
|
31
|
+
#
|
32
|
+
# @param [String] remote_path The path to the remote location, where the resulting video should be uploaded.
|
33
|
+
# The following protocols are supported: http/https, ftp.
|
34
|
+
# Null or empty string value (the default setting) means the content of resulting
|
35
|
+
# file should be encoded as Base64 and passed as the endpount response value.
|
36
|
+
# An exception will be thrown if the generated media file is too big to
|
37
|
+
# fit into the available process memory.
|
38
|
+
# This option only has an effect if there is screen recording process in progreess
|
39
|
+
# and +forceRestart+ parameter is not set to +true+.
|
40
|
+
# @param [String] user The name of the user for the remote authentication.
|
41
|
+
# @param [String] pass The password for the remote authentication.
|
42
|
+
# @param [String] method The http multipart upload method name. The 'PUT' one is used by default.
|
43
|
+
# @param [String] file_field_name The name of the form field containing the binary payload in multipart/form-data
|
44
|
+
# requests since Appium 1.18.0. Defaults to 'file'.
|
45
|
+
# @param [Array<Hash, Array<String>>] form_fields The form fields mapping in multipart/form-data requests since Appium 1.18.0.
|
46
|
+
# If any entry has the same key in this mapping, then it is going to be ignored.
|
47
|
+
# @param [Hash] headers The additional headers in multipart/form-data requests since Appium 1.18.0.
|
48
|
+
# @param [Boolean] force_restart Whether to try to catch and upload/return the currently running screen recording
|
49
|
+
# (+false+, the default setting on server) or ignore the result of it
|
50
|
+
# and start a new recording immediately (+true+).
|
51
|
+
# @param [integer] fps The count of frames per second in the resulting video.
|
52
|
+
# Increasing fps value also increases the size of the resulting video file and the CPU usage.
|
53
|
+
# The default value is 15.
|
54
|
+
# @param [String] preset A preset is a collection of options that will provide a certain encoding speed to compression ratio.
|
55
|
+
# A slower preset will provide better compression (compression is quality per filesize).
|
56
|
+
# This means that, for example, if you target a certain file size or constant bit rate, you will
|
57
|
+
# achieve better quality with a slower preset. Read https://trac.ffmpeg.org/wiki/Encode/H.264
|
58
|
+
# for more details.
|
59
|
+
# @param [Boolean] enable_cursor_capture Whether to capture the click gestures while recording the screen. Disabled by default.
|
60
|
+
# @param [Boolean] enable_capture_clicks Recording time. 180 seconds is by default.
|
61
|
+
# @param [String] video_filter The video filter spec to apply for ffmpeg.
|
62
|
+
# See https://trac.ffmpeg.org/wiki/FilteringGuide for more details on the possible values.
|
63
|
+
# Example: Set it to +scale=ifnot(gte(iw\,1024)\,iw\,1024):-2+ in order to limit the video width
|
64
|
+
# to 1024px. The height will be adjusted automatically to match the actual screen aspect ratio.
|
65
|
+
# @param [integer] device_id Screen device index to use for the recording.
|
66
|
+
# The list of available devices could be retrieved using
|
67
|
+
# +ffmpeg -f avfoundation -list_devices true -i ""+ command.
|
68
|
+
# This option is mandatory and must be always provided.
|
69
|
+
# @param [String] time_limit The maximum recording time. The default value is 600 seconds (10 minutes).
|
70
|
+
# The minimum time resolution unit is one second.
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
#
|
74
|
+
# @driver.start_recording_screen
|
75
|
+
# @driver.start_recording_screen fps: 30, enable_cursor_capture: true
|
76
|
+
#
|
77
|
+
|
78
|
+
# rubocop:enable Layout/LineLength
|
79
|
+
|
80
|
+
####
|
81
|
+
## class << self
|
82
|
+
####
|
83
|
+
|
84
|
+
class << self
|
85
|
+
def extended(_mod)
|
86
|
+
Screen.add_methods
|
87
|
+
end
|
88
|
+
end # class << self
|
89
|
+
end # module Device
|
90
|
+
end # module Mac2
|
91
|
+
end # module Core
|
92
|
+
end # module Appium
|
@@ -0,0 +1,17 @@
|
|
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
|
+
# loaded in common/driver.rb
|
16
|
+
require_relative 'mac2/device'
|
17
|
+
require_relative 'mac2/bridge'
|