appium_lib_core 4.1.0 → 5.0.1

Sign up to get free protection for your applications and to get access to all the features.
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