appium_lib_core 4.1.0 → 5.0.1

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/codeql-analysis.yml +70 -0
  4. data/.github/workflows/unittest.yml +8 -9
  5. data/.rubocop.yml +89 -1
  6. data/CHANGELOG.md +89 -276
  7. data/README.md +11 -6
  8. data/Rakefile +4 -0
  9. data/appium_lib_core.gemspec +4 -7
  10. data/bin/console +0 -4
  11. data/ci-jobs/functional/run_appium.yml +3 -3
  12. data/ci-jobs/functional_test.yml +3 -3
  13. data/docs/mobile_command.md +2 -2
  14. data/lib/appium_lib_core/android/device/auth_finger_print.rb +2 -1
  15. data/lib/appium_lib_core/android/device.rb +4 -4
  16. data/lib/appium_lib_core/common/base/bridge.rb +297 -90
  17. data/lib/appium_lib_core/common/base/capabilities.rb +10 -3
  18. data/lib/appium_lib_core/common/base/device_ime.rb +49 -0
  19. data/lib/appium_lib_core/common/base/driver.rb +183 -171
  20. data/lib/appium_lib_core/common/base/driver_settings.rb +51 -0
  21. data/lib/appium_lib_core/common/base/has_location.rb +80 -0
  22. data/lib/appium_lib_core/common/base/has_network_connection.rb +56 -0
  23. data/lib/appium_lib_core/common/base/http_default.rb +1 -3
  24. data/lib/appium_lib_core/common/base/remote_status.rb +31 -0
  25. data/lib/appium_lib_core/common/base/rotable.rb +54 -0
  26. data/lib/appium_lib_core/common/base/screenshot.rb +6 -6
  27. data/lib/appium_lib_core/common/base/search_context.rb +19 -4
  28. data/lib/appium_lib_core/common/base.rb +1 -3
  29. data/lib/appium_lib_core/common/command.rb +257 -4
  30. data/lib/appium_lib_core/common/device/image_comparison.rb +12 -4
  31. data/lib/appium_lib_core/common/device/keyevent.rb +4 -4
  32. data/lib/appium_lib_core/common/{command/mjsonwp.rb → device/orientation.rb} +14 -11
  33. data/lib/appium_lib_core/common/device/touch_actions.rb +2 -0
  34. data/lib/appium_lib_core/common/device/value.rb +6 -6
  35. data/lib/appium_lib_core/common/error.rb +4 -1
  36. data/lib/appium_lib_core/common/log.rb +4 -1
  37. data/lib/appium_lib_core/common/touch_action/multi_touch.rb +19 -0
  38. data/lib/appium_lib_core/common/touch_action/touch_actions.rb +16 -2
  39. data/lib/appium_lib_core/common/wait.rb +38 -6
  40. data/lib/appium_lib_core/device.rb +1 -5
  41. data/lib/appium_lib_core/driver.rb +30 -46
  42. data/lib/appium_lib_core/{patch.rb → element.rb} +66 -9
  43. data/lib/appium_lib_core/ios/uiautomation/patch.rb +1 -1
  44. data/lib/appium_lib_core/{common/base/command.rb → mac2/bridge.rb} +9 -8
  45. data/lib/appium_lib_core/mac2/device/screen.rb +48 -0
  46. data/lib/appium_lib_core/mac2/device.rb +92 -0
  47. data/lib/appium_lib_core/mac2.rb +17 -0
  48. data/lib/appium_lib_core/version.rb +2 -2
  49. data/lib/appium_lib_core.rb +2 -5
  50. data/release_notes.md +125 -0
  51. data/script/commands.rb +3 -37
  52. metadata +27 -68
  53. data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +0 -81
  54. data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -252
  55. data/lib/appium_lib_core/common/command/common.rb +0 -110
  56. data/lib/appium_lib_core/common/command/w3c.rb +0 -56
@@ -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::TakeScreenshot
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
43
+
44
+ private
31
45
 
32
46
  # Private API.
33
47
  # Do not use this for general use. Used by flutter driver to get bridge for creating a new element
34
48
  attr_reader :bridge
35
49
 
36
- def initialize(opts = {})
37
- listener = opts.delete(:listener)
38
- @bridge = ::Appium::Core::Base::Bridge.handshake(**opts)
39
- if @bridge.dialect == :oss # MJSONWP
40
- extend ::Selenium::WebDriver::DriverExtensions::HasTouchScreen
41
- extend ::Selenium::WebDriver::DriverExtensions::HasLocation
42
- extend ::Selenium::WebDriver::DriverExtensions::HasNetworkConnection
43
- elsif @bridge.dialect == :w3c
44
- # TODO: Only for Appium. Ideally, we'd like to remove the below like selenium-webdriver
45
- extend ::Selenium::WebDriver::DriverExtensions::HasTouchScreen
46
- extend ::Selenium::WebDriver::DriverExtensions::HasLocation
47
- extend ::Selenium::WebDriver::DriverExtensions::HasNetworkConnection
48
- end
49
- super(@bridge, listener: listener)
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
- # Get the dialect value
53
- # @return [:oss|:w3c]
54
- def dialect
55
- @bridge.dialect
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,10 +88,95 @@ 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.update_sending_request_to(scheme: protocol,
70
- host: host,
71
- port: port,
72
- path: path)
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
@@ -138,38 +245,6 @@ module Appium
138
245
  end
139
246
  alias is_keyboard_shown keyboard_shown?
140
247
 
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
248
  # Returns an instance of DriverSettings to call get/update.
174
249
  #
175
250
  # @example
@@ -178,7 +253,7 @@ module Appium
178
253
  # @driver.settings.update('allowInvisibleElements': true)
179
254
  #
180
255
  def settings
181
- @driver_settings ||= DriverSettings.new(@bridge) # rubocop:disable Naming/MemoizedInstanceVariableName
256
+ @settings ||= DriverSettings.new(@bridge)
182
257
  end
183
258
 
184
259
  # Get appium Settings for current test session.
@@ -200,8 +275,8 @@ module Appium
200
275
  #
201
276
  # @example
202
277
  #
203
- # @driver.update_settings('allowInvisibleElements': true)
204
- # @driver.settings.update('allowInvisibleElements': true)
278
+ # @driver.update_settings({ 'allowInvisibleElements': true })
279
+ # @driver.settings.update({ 'allowInvisibleElements': true })
205
280
  # @driver.settings = { 'allowInvisibleElements': true }
206
281
  #
207
282
  def settings=(value)
@@ -209,36 +284,10 @@ module Appium
209
284
  end
210
285
  alias update_settings settings=
211
286
 
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
287
  # Returns an instance of DeviceIME
241
288
  #
289
+ # @return [Appium::Core::Base::Driver::DeviceIME]
290
+ #
242
291
  # @example
243
292
  #
244
293
  # @driver.ime.activate engine: 'com.android.inputmethod.latin/.LatinIME'
@@ -248,7 +297,7 @@ module Appium
248
297
  # @driver.ime.deactivate #=> Deactivate current IME engine
249
298
  #
250
299
  def ime
251
- @device_ime ||= DeviceIME.new(@bridge) # rubocop:disable Naming/MemoizedInstanceVariableName
300
+ @ime ||= DeviceIME.new(@bridge)
252
301
  end
253
302
 
254
303
  # Android only. Make an engine that is available active.
@@ -289,6 +338,8 @@ module Appium
289
338
  # @!method ime_activated
290
339
  # Android only. Indicates whether IME input is active at the moment (not if it is available).
291
340
  #
341
+ # @return [Boolean]
342
+ #
292
343
  # @example
293
344
  #
294
345
  # @driver.ime_activated #=> True if IME is activated
@@ -366,42 +417,10 @@ module Appium
366
417
  end
367
418
  alias set_context context=
368
419
 
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
420
  # 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
421
  # On Android, the application under test should be built with debuggable flag enabled in order to get access to
397
422
  # its container on the internal file system.
398
423
  #
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
424
  # @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
406
425
  # If the path starts with application id prefix, then the file will be pushed to the root of
407
426
  # the corresponding application container.
@@ -418,18 +437,10 @@ module Appium
418
437
  @bridge.push_file(path, filedata)
419
438
  end
420
439
 
421
- # Pull a file from the simulator/device.
422
- # On iOS the server should have ifuse
423
- # libraries installed and configured properly for this feature to work on real devices.
440
+ # Pull a file from the remote device.
424
441
  # On Android the application under test should be built with debuggable flag enabled in order to get access
425
442
  # to its container on the internal file system.
426
443
  #
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
444
  # @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
434
445
  # If the path starts with application id prefix, then the file will be pulled from the root
435
446
  # of the corresponding application container.
@@ -438,7 +449,6 @@ module Appium
438
449
  # Only pulling files from application containers is supported for iOS Simulator.
439
450
  # Provide the remote path in format
440
451
  # <code>@bundle.identifier:container_type/relative_path_in_container</code>
441
- # (Make sure this in ifuse doc)
442
452
  #
443
453
  # @return [Base64-decoded] Base64 decoded data
444
454
  #
@@ -455,18 +465,10 @@ module Appium
455
465
  @bridge.pull_file(path)
456
466
  end
457
467
 
458
- # Pull a folder content from the simulator/device.
459
- # On iOS the server should have ifuse libraries installed and configured properly for this feature to work
460
- # on real devices.
468
+ # Pull a folder content from the remote device.
461
469
  # On Android the application under test should be built with debuggable flag enabled in order to get access to
462
470
  # its container on the internal file system.
463
471
  #
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
472
  # @param [String] path Absolute path to the folder.
471
473
  # If the path starts with <em>@applicationId/</em> prefix, then the folder will be pulled
472
474
  # from the root of the corresponding application container.
@@ -475,7 +477,6 @@ module Appium
475
477
  # Only pulling files from application containers is supported for iOS Simulator.
476
478
  # Provide the remote path in format
477
479
  # <code>@bundle.identifier:container_type/relative_path_in_container</code>
478
- # (Make sure this in ifuse doc)
479
480
  #
480
481
  # @return [Base64-decoded] Base64 decoded data which is zip archived
481
482
  #
@@ -489,19 +490,6 @@ module Appium
489
490
  @bridge.pull_folder(path)
490
491
  end
491
492
 
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
493
  # Press keycode on the device.
506
494
  # http://developer.android.com/reference/android/view/KeyEvent.html
507
495
  # @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 +534,7 @@ module Appium
546
534
  @bridge.long_press_keycode(key, metastate: metastate, flags: flags)
547
535
  end
548
536
 
537
+ # @deprecated Except for Windows
549
538
  # Start the simulator and application configured with desired capabilities
550
539
  #
551
540
  # @example
@@ -553,9 +542,16 @@ module Appium
553
542
  # @driver.launch_app
554
543
  #
555
544
  def launch_app
545
+ # TODO: Define only in Windows module when ruby_lib_core removes this method
546
+ if @automation_name != :windows
547
+ ::Appium::Logger.warn(
548
+ '[DEPRECATION] launch_app is deprecated. Please use activate_app instead.'
549
+ )
550
+ end
556
551
  @bridge.launch_app
557
552
  end
558
553
 
554
+ # @deprecated Except for Windows
559
555
  # Close an app on device
560
556
  #
561
557
  # @example
@@ -563,9 +559,16 @@ module Appium
563
559
  # @driver.close_app
564
560
  #
565
561
  def close_app
562
+ # TODO: Define only in Windows module when ruby_lib_core removes this method
563
+ if @automation_name != :windows
564
+ ::Appium::Logger.warn(
565
+ '[DEPRECATION] close_app is deprecated. Please use terminate_app instead.'
566
+ )
567
+ end
566
568
  @bridge.close_app
567
569
  end
568
570
 
571
+ # @deprecated
569
572
  # Reset the device, relaunching the application.
570
573
  #
571
574
  # @example
@@ -573,6 +576,10 @@ module Appium
573
576
  # @driver.reset
574
577
  #
575
578
  def reset
579
+ ::Appium::Logger.warn(
580
+ '[DEPRECATION] reset is deprecated. Please use terminate_app and activate_app, ' \
581
+ 'or quit and create a new session instead.'
582
+ )
576
583
  @bridge.reset
577
584
  end
578
585
 
@@ -790,7 +797,7 @@ module Appium
790
797
  #
791
798
  # @example: Zoom
792
799
  #
793
- # f1 = @driver.action.add_pointer_input(:touch, 'finger1')
800
+ # f1 = ::Selenium::WebDriver::Interactions.pointer(:touch, name: 'finger1')
794
801
  # f1.create_pointer_move(duration: 1, x: 200, y: 500,
795
802
  # origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
796
803
  # f1.create_pointer_down(:left)
@@ -798,7 +805,7 @@ module Appium
798
805
  # origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
799
806
  # f1.create_pointer_up(:left)
800
807
  #
801
- # f2 = @driver.action.add_pointer_input(:touch, 'finger2')
808
+ # f2 = ::Selenium::WebDriver::Interactions.pointer(:touch, name: 'finger2')
802
809
  # f2.create_pointer_move(duration: 1, x: 200, y: 500,
803
810
  # origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
804
811
  # f2.create_pointer_down(:left)
@@ -809,7 +816,11 @@ module Appium
809
816
  # @driver.perform_actions [f1, f2] #=> 'nil' if the action succeed
810
817
  #
811
818
  def perform_actions(data)
812
- raise ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
819
+ raise ::Appium::Core::Error::ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
820
+
821
+ # NOTE: 'add_input' in Selenium Ruby implementation has additional 'pause'.
822
+ # This implementation is to avoid the additional pause.
823
+ # https://github.com/SeleniumHQ/selenium/blob/64447d4b03f6986337d1ca8d8b6476653570bcc1/rb/lib/selenium/webdriver/common/action_builder.rb#L207
813
824
 
814
825
  @bridge.send_actions data.map(&:encode).compact
815
826
  data.each(&:clear_actions)
@@ -853,7 +864,7 @@ module Appium
853
864
  end
854
865
 
855
866
  # Get the device window's logs.
856
- # @return [String]
867
+ # @return [Appium::Core::Logs]
857
868
  #
858
869
  # @example
859
870
  #
@@ -879,16 +890,15 @@ module Appium
879
890
  # Retrieve the capabilities of the specified session.
880
891
  # It's almost same as +@driver.capabilities+ but you can get more details.
881
892
  #
882
- # @return [Selenium::WebDriver::Remote::Capabilities]
893
+ # @return [Selenium::WebDriver::Remote::Capabilities, Selenium::WebDriver::Remote::Capabilities]
883
894
  #
884
895
  # @example
885
896
  # @driver.session_capabilities
886
897
  #
887
898
  # #=> uiautomator2
888
- # # <Selenium::WebDriver::Remote::W3C::Capabilities:0x007fa38dae1360
899
+ # # <Selenium::WebDriver::Remote::Capabilities:0x007fa38dae1360
889
900
  # # @capabilities=
890
- # # {:proxy=>nil,
891
- # # :browser_name=>nil,
901
+ # # {:browser_name=>nil,
892
902
  # # :browser_version=>nil,
893
903
  # # :platform_name=>"android",
894
904
  # # :page_load_strategy=>nil,
@@ -935,10 +945,9 @@ module Appium
935
945
  # # "viewportRect"=>{"left"=>0, "top"=>63, "width"=>1080, "height"=>1731}}>
936
946
  # #
937
947
  # #=> XCUITest
938
- # # <Selenium::WebDriver::Remote::W3C::Capabilities:0x007fb15dc01370
948
+ # # <Selenium::WebDriver::Remote::Capabilities:0x007fb15dc01370
939
949
  # # @capabilities=
940
- # # {:proxy=>nil,
941
- # # :browser_name=>"UICatalog",
950
+ # # {:browser_name=>"UICatalog",
942
951
  # # :browser_version=>nil,
943
952
  # # :platform_name=>"ios",
944
953
  # # :page_load_strategy=>nil,
@@ -992,11 +1001,14 @@ module Appium
992
1001
  visualize: visualize)
993
1002
  end
994
1003
 
995
- def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil)
1004
+ def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil,
1005
+ multiple: nil, match_neighbour_threshold: nil)
996
1006
  @bridge.find_image_occurrence(full_image: full_image,
997
1007
  partial_image: partial_image,
998
1008
  visualize: visualize,
999
- threshold: threshold)
1009
+ threshold: threshold,
1010
+ multiple: multiple,
1011
+ match_neighbour_threshold: match_neighbour_threshold)
1000
1012
  end
1001
1013
 
1002
1014
  def get_images_similarity(first_image:, second_image:, visualize: false)
@@ -1016,7 +1028,7 @@ module Appium
1016
1028
  #
1017
1029
  # @param [String] img_path A path to a partial image you'd like to find
1018
1030
  #
1019
- # @return [::Selenium::WebDriver::Element]
1031
+ # @return [::Appium::Core::Element]
1020
1032
  #
1021
1033
  # @example
1022
1034
  #
@@ -1038,7 +1050,7 @@ module Appium
1038
1050
  #
1039
1051
  # @param [String] img_path A path to a partial image you'd like to find
1040
1052
  #
1041
- # @return [::Selenium::WebDriver::Element]
1053
+ # @return [Array<Selenium::WebDriver::Element>]
1042
1054
  #
1043
1055
  # @example
1044
1056
  #
@@ -1086,14 +1098,14 @@ module Appium
1086
1098
  @bridge.execute_driver(script: script, type: type, timeout_ms: timeout_ms)
1087
1099
  end
1088
1100
 
1089
- # Convert vanilla element response to ::Selenium::WebDriver::Element
1101
+ # Convert vanilla element response to ::Appium::Core::Element
1090
1102
  #
1091
1103
  # @param [Hash] id The id which can get as a response from server
1092
- # @return [::Selenium::WebDriver::Element]
1104
+ # @return [::Appium::Core::Element]
1093
1105
  #
1094
1106
  # @example
1095
1107
  # response = {"element-6066-11e4-a52e-4f735466cecf"=>"xxxx", "ELEMENT"=>"xxxx"}
1096
- # ele = @driver.convert_to_element(response) #=> ::Selenium::WebDriver::Element
1108
+ # ele = @driver.convert_to_element(response) #=> ::Appium::Core::Element
1097
1109
  # ele.rect #=> Can get the rect of the element
1098
1110
  #
1099
1111
  def convert_to_element(id)
@@ -0,0 +1,51 @@
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
+ class Base
18
+ #
19
+ # @api private
20
+ #
21
+ class DriverSettings
22
+ # @private this class is private
23
+ def initialize(bridge)
24
+ @bridge = bridge
25
+ end
26
+
27
+ # Get appium Settings for current test session.
28
+ #
29
+ # @example
30
+ #
31
+ # @driver.settings.get
32
+ #
33
+ def get
34
+ @bridge.get_settings
35
+ end
36
+
37
+ # Update Appium Settings for current test session
38
+ #
39
+ # @param [Hash] settings Settings to update, keys are settings, values to value to set each setting to
40
+ #
41
+ # @example
42
+ #
43
+ # @driver.settings.update({'allowInvisibleElements': true})
44
+ #
45
+ def update(settings)
46
+ @bridge.update_settings(settings)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end