appium_lib_core 4.1.0 → 6.2.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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +207 -272
  3. data/README.md +41 -14
  4. data/Rakefile +4 -0
  5. data/appium_lib_core.gemspec +5 -8
  6. data/bin/console +0 -4
  7. data/lib/appium_lib_core/android/device/auth_finger_print.rb +2 -1
  8. data/lib/appium_lib_core/android/device.rb +4 -4
  9. data/lib/appium_lib_core/common/base/bridge.rb +311 -90
  10. data/lib/appium_lib_core/common/base/capabilities.rb +8 -9
  11. data/lib/appium_lib_core/common/base/device_ime.rb +49 -0
  12. data/lib/appium_lib_core/common/base/driver.rb +222 -187
  13. data/lib/appium_lib_core/common/base/driver_settings.rb +51 -0
  14. data/lib/appium_lib_core/common/base/has_location.rb +80 -0
  15. data/lib/appium_lib_core/common/base/has_network_connection.rb +56 -0
  16. data/lib/appium_lib_core/common/base/http_default.rb +1 -3
  17. data/lib/appium_lib_core/{ios/uiautomation/bridge.rb → common/base/remote_status.rb} +9 -8
  18. data/lib/appium_lib_core/common/base/rotable.rb +54 -0
  19. data/lib/appium_lib_core/common/base/screenshot.rb +6 -6
  20. data/lib/appium_lib_core/common/base/search_context.rb +20 -6
  21. data/lib/appium_lib_core/common/base.rb +1 -3
  22. data/lib/appium_lib_core/common/command.rb +259 -4
  23. data/lib/appium_lib_core/common/device/app_management.rb +8 -14
  24. data/lib/appium_lib_core/common/device/image_comparison.rb +12 -4
  25. data/lib/appium_lib_core/common/device/keyevent.rb +4 -4
  26. data/lib/appium_lib_core/common/{command/mjsonwp.rb → device/orientation.rb} +14 -11
  27. data/lib/appium_lib_core/common/device/touch_actions.rb +2 -0
  28. data/lib/appium_lib_core/common/device/value.rb +6 -8
  29. data/lib/appium_lib_core/common/error.rb +4 -5
  30. data/lib/appium_lib_core/common/log.rb +4 -1
  31. data/lib/appium_lib_core/common/touch_action/multi_touch.rb +19 -0
  32. data/lib/appium_lib_core/common/touch_action/touch_actions.rb +16 -2
  33. data/lib/appium_lib_core/common/wait.rb +38 -6
  34. data/lib/appium_lib_core/device.rb +1 -5
  35. data/lib/appium_lib_core/driver.rb +177 -102
  36. data/lib/appium_lib_core/{patch.rb → element.rb} +66 -9
  37. data/lib/appium_lib_core/{common/base/command.rb → mac2/bridge.rb} +9 -8
  38. data/lib/appium_lib_core/mac2/device/screen.rb +48 -0
  39. data/lib/appium_lib_core/mac2/device.rb +92 -0
  40. data/lib/appium_lib_core/{ios.rb → mac2.rb} +2 -5
  41. data/lib/appium_lib_core/version.rb +2 -2
  42. data/lib/appium_lib_core/windows/device/app_management.rb +38 -0
  43. data/lib/appium_lib_core/windows/device.rb +2 -0
  44. data/lib/appium_lib_core.rb +20 -10
  45. metadata +27 -83
  46. data/.github/ISSUE_TEMPLATE/issue-report.md +0 -29
  47. data/.github/contributing.md +0 -26
  48. data/.github/issue_template.md +0 -20
  49. data/.github/workflows/unittest.yml +0 -68
  50. data/.gitignore +0 -18
  51. data/.rubocop.yml +0 -58
  52. data/azure-pipelines.yml +0 -15
  53. data/ci-jobs/functional/android_setup.yml +0 -3
  54. data/ci-jobs/functional/ios_setup.yml +0 -7
  55. data/ci-jobs/functional/publish_test_result.yml +0 -18
  56. data/ci-jobs/functional/run_appium.yml +0 -25
  57. data/ci-jobs/functional/start-emulator.sh +0 -26
  58. data/ci-jobs/functional_test.yml +0 -298
  59. data/docs/mobile_command.md +0 -34
  60. data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +0 -81
  61. data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -252
  62. data/lib/appium_lib_core/common/command/common.rb +0 -110
  63. data/lib/appium_lib_core/common/command/w3c.rb +0 -56
  64. data/lib/appium_lib_core/ios/uiautomation/device.rb +0 -44
  65. data/lib/appium_lib_core/ios/uiautomation/patch.rb +0 -34
  66. data/release_notes.md +0 -816
  67. data/script/commands.rb +0 -200
@@ -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,65 @@ 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
- include ::Selenium::WebDriver::DriverExtensions::HasRemoteStatus
27
32
  include ::Selenium::WebDriver::DriverExtensions::HasWebStorage
28
33
 
34
+ include ::Appium::Core::Base::Rotatable
29
35
  include ::Appium::Core::Base::SearchContext
30
- include ::Appium::Core::Base::TakeScreenshot
36
+ include ::Appium::Core::Base::TakesScreenshot
37
+ include ::Appium::Core::Base::HasRemoteStatus
38
+ include ::Appium::Core::Base::HasLocation
39
+ include ::Appium::Core::Base::HasNetworkConnection
40
+
41
+ include ::Appium::Core::Waitable
31
42
 
32
43
  # Private API.
33
44
  # Do not use this for general use. Used by flutter driver to get bridge for creating a new element
34
45
  attr_reader :bridge
35
46
 
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)
47
+ private
48
+
49
+ def initialize(bridge: nil, listener: nil, **opts)
50
+ # For ::Appium::Core::Waitable
51
+ @wait_timeout = opts.delete(:wait_timeout)
52
+ @wait_interval = opts.delete(:wait_interval)
53
+
54
+ super
50
55
  end
51
56
 
52
- # Get the dialect value
53
- # @return [:oss|:w3c]
54
- def dialect
55
- @bridge.dialect
57
+ # Create a proper bridge instance.
58
+ #
59
+ # @return [::Appium::Core::Base::Bridge]
60
+ #
61
+ def create_bridge(**opts)
62
+ # for a new session request
63
+ capabilities = opts.delete(:capabilities)
64
+ bridge_opts = { http_client: opts.delete(:http_client), url: opts.delete(:url) }
65
+
66
+ # for attaching to an existing session
67
+ session_id = opts.delete(:existing_session_id)
68
+ automation_name = opts.delete(:automation_name)
69
+ platform_name = opts.delete(:platform_name)
70
+
71
+ raise ::Appium::Core::Error::ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
72
+
73
+ bridge = ::Appium::Core::Base::Bridge.new(**bridge_opts)
74
+
75
+ if session_id.nil?
76
+ bridge.create_session(capabilities)
77
+ else
78
+ # attach to the existing session id
79
+ bridge.attach_to(session_id, platform_name, automation_name)
80
+ end
81
+
82
+ bridge
56
83
  end
57
84
 
85
+ public
86
+
58
87
  # Update +server_url+ and HTTP clients following this arguments, protocol, host, port and path.
59
88
  # After this method, +@bridge.http+ will be a new instance following them instead of +server_url+ which is
60
89
  # set before creating session.
90
+ # If +@bridge.http+ did not have +update_sending_request_to+ method, this method returns immediately.
61
91
  #
62
92
  # @example
63
93
  #
@@ -66,14 +96,124 @@ module Appium
66
96
  # driver.manage.timeouts.implicit_wait = 10 # @bridge.http is for 'https://example2.com:9000/wd/hub/'
67
97
  #
68
98
  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)
99
+ unless @bridge.http&.class&.method_defined? :update_sending_request_to
100
+ ::Appium::Logger.warn "#{@bridge.http&.class} has no 'update_sending_request_to'. " \
101
+ 'It keeps current connection target.'
102
+ return
103
+ end
104
+
105
+ @bridge.http&.update_sending_request_to(scheme: protocol,
106
+ host: host,
107
+ port: port,
108
+ path: path)
109
+ end
110
+
111
+ AVAILABLE_METHODS = [
112
+ :get, :head, :post, :put, :delete,
113
+ :connect, :options, :trace, :patch
114
+ ].freeze
115
+ # Define a new custom method to the driver so that you can define your own method for
116
+ # drivers/plugins in Appium 2.0. Appium 2.0 and its custom drivers/plugins allow you
117
+ # to define custom commands that are not part of W3C spec.
118
+ #
119
+ # @param [Symbol] method HTTP request method as https://www.w3.org/TR/webdriver/#endpoints
120
+ # @param [string] url The url to URL template as https://www.w3.org/TR/webdriver/#endpoints.
121
+ # +:session_id+ is the placeholder of 'session id'.
122
+ # Other place holders can be specified with +:+ prefix like +:id+.
123
+ # Then, the +:id+ will be replaced with a given value as the seconds argument of +execute+
124
+ # @param [Symbol] name The name of method that is called as the driver instance method.
125
+ # @param [Proc] block The block to involve as the method.
126
+ # Please define a method that has the same +name+ with arguments you want.
127
+ # The method must has +execute+ method. tHe +execute+ is calls the +url+
128
+ # with the given parameters.
129
+ # The first argument should be +name+ as symbol.
130
+ # The second argument should be hash. If keys in the hash matches +:+ prefix
131
+ # string in the given url, the matched string in the given url will be
132
+ # values in the hash.
133
+ # The third argument should be hash. The hash will be the request body.
134
+ # Please read examples below for more details.
135
+ # @raise [ArgumentError] If the given +method+ is invalid value.
136
+ #
137
+ # @example
138
+ #
139
+ # @driver.add_command(
140
+ # method: :get,
141
+ # url: 'session/:session_id/path/to/custom/url',
142
+ # name: :test_command
143
+ # )
144
+ # # Send a GET request to 'session/<session id>/path/to/custom/url'
145
+ # @driver.test_command
146
+ #
147
+ #
148
+ # @driver.add_command(
149
+ # method: :post,
150
+ # url: 'session/:session_id/path/to/custom/url',
151
+ # name: :test_command
152
+ # ) do
153
+ # def test_command(argument)
154
+ # execute(:test_command, {}, { dummy: argument })
155
+ # end
156
+ # end
157
+ # # Send a POST request to 'session/<session id>/path/to/custom/url'
158
+ # # with body "{ dummy: 1 }" as JSON object. "1" is the argument.
159
+ # # ':session_id' in the given 'url' is replaced with current 'session id'.
160
+ # @driver.test_command(1)
161
+ #
162
+ #
163
+ # @driver.add_command(
164
+ # method: :post,
165
+ # url: 'session/:session_id/element/:id/custom/action',
166
+ # name: :test_action_command
167
+ # ) do
168
+ # def test_action_command(element_id, action)
169
+ # execute(:test_action_command, {id: element_id}, { dummy_action: action })
170
+ # end
171
+ # end
172
+ # # Send a POST request to 'session/<session id>/element/<element id>/custom/action'
173
+ # # with body "{ dummy_action: #{action} }" as JSON object. "action" is the seconds argument.
174
+ # # ':session_id' in the given url is replaced with current 'session id'.
175
+ # # ':id' in the given url is replaced with the given 'element_id'.
176
+ # e = @driver.find_element :accessibility_id, 'an element'
177
+ # @driver.test_action_command(e.id, 'action')
178
+ #
179
+ def add_command(method:, url:, name:, &block)
180
+ unless AVAILABLE_METHODS.include? method
181
+ raise ::Appium::Core::Error::ArgumentError, "Available method is either #{AVAILABLE_METHODS}"
182
+ end
183
+
184
+ # TODO: Remove this logger before Appium 2.0 release
185
+ ::Appium::Logger.info '[Experimental] this method is experimental for Appium 2.0. This interface may change.'
186
+
187
+ @bridge.add_command method: method, url: url, name: name, &block
73
188
  end
74
189
 
75
190
  ### Methods for Appium
76
191
 
192
+ # Perform 'key' actions for W3C module.
193
+ # Generate +key+ pointer action here and users can use this via +driver.key_action+
194
+ # - https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/W3CActionBuilder.html
195
+ # - https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/KeyActions.html
196
+ #
197
+ # The pointer type is 'key' by default in the Appium Ruby client.
198
+ # +driver.action+ in Appium Ruby client has 'pointer' action by default.
199
+ # This method is a shortcut to set 'key' type.
200
+ # Hense this method is equal to +driver.action(devices: [::Selenium::WebDriver::Interactions.key('keyboard')])+
201
+ # as below example.
202
+ #
203
+ # @example
204
+ #
205
+ # element = @driver.find_element(:id, "some id")
206
+ # @driver.key_action.send_key('hiあ').perform # The 'send_key' is a part of 'KeyActions'
207
+ # # is equal to:
208
+ # # @driver.action(devices: [::Selenium::WebDriver::Interactions.key('keyboard')]).send_keys('hiあ').perform
209
+ #
210
+ def key_action(async: false)
211
+ @bridge.action(
212
+ async: async,
213
+ devices: [::Selenium::WebDriver::Interactions.key('keyboard')]
214
+ )
215
+ end
216
+
77
217
  # Lock the device
78
218
  # @return [String]
79
219
  #
@@ -138,38 +278,6 @@ module Appium
138
278
  end
139
279
  alias is_keyboard_shown keyboard_shown?
140
280
 
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
281
  # Returns an instance of DriverSettings to call get/update.
174
282
  #
175
283
  # @example
@@ -178,7 +286,7 @@ module Appium
178
286
  # @driver.settings.update('allowInvisibleElements': true)
179
287
  #
180
288
  def settings
181
- @driver_settings ||= DriverSettings.new(@bridge) # rubocop:disable Naming/MemoizedInstanceVariableName
289
+ @settings ||= DriverSettings.new(@bridge)
182
290
  end
183
291
 
184
292
  # Get appium Settings for current test session.
@@ -200,8 +308,8 @@ module Appium
200
308
  #
201
309
  # @example
202
310
  #
203
- # @driver.update_settings('allowInvisibleElements': true)
204
- # @driver.settings.update('allowInvisibleElements': true)
311
+ # @driver.update_settings({ 'allowInvisibleElements': true })
312
+ # @driver.settings.update({ 'allowInvisibleElements': true })
205
313
  # @driver.settings = { 'allowInvisibleElements': true }
206
314
  #
207
315
  def settings=(value)
@@ -209,36 +317,10 @@ module Appium
209
317
  end
210
318
  alias update_settings settings=
211
319
 
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
320
  # Returns an instance of DeviceIME
241
321
  #
322
+ # @return [Appium::Core::Base::Driver::DeviceIME]
323
+ #
242
324
  # @example
243
325
  #
244
326
  # @driver.ime.activate engine: 'com.android.inputmethod.latin/.LatinIME'
@@ -248,7 +330,7 @@ module Appium
248
330
  # @driver.ime.deactivate #=> Deactivate current IME engine
249
331
  #
250
332
  def ime
251
- @device_ime ||= DeviceIME.new(@bridge) # rubocop:disable Naming/MemoizedInstanceVariableName
333
+ @ime ||= DeviceIME.new(@bridge)
252
334
  end
253
335
 
254
336
  # Android only. Make an engine that is available active.
@@ -289,6 +371,8 @@ module Appium
289
371
  # @!method ime_activated
290
372
  # Android only. Indicates whether IME input is active at the moment (not if it is available).
291
373
  #
374
+ # @return [Boolean]
375
+ #
292
376
  # @example
293
377
  #
294
378
  # @driver.ime_activated #=> True if IME is activated
@@ -366,42 +450,10 @@ module Appium
366
450
  end
367
451
  alias set_context context=
368
452
 
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
453
  # 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
454
  # On Android, the application under test should be built with debuggable flag enabled in order to get access to
397
455
  # its container on the internal file system.
398
456
  #
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
457
  # @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
406
458
  # If the path starts with application id prefix, then the file will be pushed to the root of
407
459
  # the corresponding application container.
@@ -418,18 +470,10 @@ module Appium
418
470
  @bridge.push_file(path, filedata)
419
471
  end
420
472
 
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.
473
+ # Pull a file from the remote device.
424
474
  # On Android the application under test should be built with debuggable flag enabled in order to get access
425
475
  # to its container on the internal file system.
426
476
  #
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
477
  # @param [String] path Either an absolute path OR, for iOS devices, a path relative to the app, as described.
434
478
  # If the path starts with application id prefix, then the file will be pulled from the root
435
479
  # of the corresponding application container.
@@ -438,7 +482,6 @@ module Appium
438
482
  # Only pulling files from application containers is supported for iOS Simulator.
439
483
  # Provide the remote path in format
440
484
  # <code>@bundle.identifier:container_type/relative_path_in_container</code>
441
- # (Make sure this in ifuse doc)
442
485
  #
443
486
  # @return [Base64-decoded] Base64 decoded data
444
487
  #
@@ -455,18 +498,10 @@ module Appium
455
498
  @bridge.pull_file(path)
456
499
  end
457
500
 
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.
501
+ # Pull a folder content from the remote device.
461
502
  # On Android the application under test should be built with debuggable flag enabled in order to get access to
462
503
  # its container on the internal file system.
463
504
  #
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
505
  # @param [String] path Absolute path to the folder.
471
506
  # If the path starts with <em>@applicationId/</em> prefix, then the folder will be pulled
472
507
  # from the root of the corresponding application container.
@@ -475,7 +510,6 @@ module Appium
475
510
  # Only pulling files from application containers is supported for iOS Simulator.
476
511
  # Provide the remote path in format
477
512
  # <code>@bundle.identifier:container_type/relative_path_in_container</code>
478
- # (Make sure this in ifuse doc)
479
513
  #
480
514
  # @return [Base64-decoded] Base64 decoded data which is zip archived
481
515
  #
@@ -489,19 +523,6 @@ module Appium
489
523
  @bridge.pull_folder(path)
490
524
  end
491
525
 
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
526
  # Press keycode on the device.
506
527
  # http://developer.android.com/reference/android/view/KeyEvent.html
507
528
  # @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 +567,7 @@ module Appium
546
567
  @bridge.long_press_keycode(key, metastate: metastate, flags: flags)
547
568
  end
548
569
 
570
+ # @deprecated Except for Windows
549
571
  # Start the simulator and application configured with desired capabilities
550
572
  #
551
573
  # @example
@@ -556,6 +578,7 @@ module Appium
556
578
  @bridge.launch_app
557
579
  end
558
580
 
581
+ # @deprecated Except for Windows
559
582
  # Close an app on device
560
583
  #
561
584
  # @example
@@ -566,6 +589,7 @@ module Appium
566
589
  @bridge.close_app
567
590
  end
568
591
 
592
+ # @deprecated
569
593
  # Reset the device, relaunching the application.
570
594
  #
571
595
  # @example
@@ -573,6 +597,10 @@ module Appium
573
597
  # @driver.reset
574
598
  #
575
599
  def reset
600
+ ::Appium::Logger.warn(
601
+ '[DEPRECATION] reset is deprecated. Please use terminate_app and activate_app, ' \
602
+ 'or quit and create a new session instead.'
603
+ )
576
604
  @bridge.reset
577
605
  end
578
606
 
@@ -602,7 +630,9 @@ module Appium
602
630
  @bridge.background_app(duration)
603
631
  end
604
632
 
605
- # Install the given app onto the device
633
+ # Install the given app onto the device.
634
+ # Each options can be snake-case or camel-case. Snake-cases will be converted to camel-case
635
+ # as options value.
606
636
  #
607
637
  # @param [String] path The absolute local path or remote http URL to an .ipa or .apk file,
608
638
  # or a .zip containing one of these.
@@ -616,26 +646,26 @@ module Appium
616
646
  # @param [Boolean] grant_permissions Only for Android. whether to automatically grant application permissions
617
647
  # on Android 6+ after the installation completes. +false+ by default
618
648
  #
649
+ # Other parameters such as https://github.com/appium/appium-xcuitest-driver#mobile-installapp also can be set.
650
+ # Then, arguments in snake case will be camel case as its request parameters.
651
+ #
619
652
  # @example
620
653
  #
621
654
  # @driver.install_app("/path/to/test.apk")
622
655
  # @driver.install_app("/path/to/test.apk", replace: true, timeout: 20000, allow_test_packages: true,
623
656
  # use_sdcard: false, grant_permissions: false)
657
+ # @driver.install_app("/path/to/test.ipa", timeoutMs: 20000)
624
658
  #
625
- def install_app(path,
626
- replace: nil,
627
- timeout: nil,
628
- allow_test_packages: nil,
629
- use_sdcard: nil,
630
- grant_permissions: nil)
631
- @bridge.install_app(path,
632
- replace: replace,
633
- timeout: timeout,
634
- allow_test_packages: allow_test_packages,
635
- use_sdcard: use_sdcard,
636
- grant_permissions: grant_permissions)
659
+ def install_app(path, **options)
660
+ options = options.transform_keys { |key| key.to_s.gsub(/_./) { |v| v[1].upcase } } unless options.nil?
661
+ @bridge.install_app(path, options)
637
662
  end
638
663
 
664
+ # def capitalize(s)
665
+ # chars =
666
+ # chars[1:].map(&:capitalize).join
667
+ # end
668
+
639
669
  # @param [Strong] app_id BundleId for iOS or package name for Android
640
670
  # @param [Boolean] keep_data Only for Android. Whether to keep application data and caches after it is uninstalled.
641
671
  # +false+ by default
@@ -790,7 +820,7 @@ module Appium
790
820
  #
791
821
  # @example: Zoom
792
822
  #
793
- # f1 = @driver.action.add_pointer_input(:touch, 'finger1')
823
+ # f1 = ::Selenium::WebDriver::Interactions.pointer(:touch, name: 'finger1')
794
824
  # f1.create_pointer_move(duration: 1, x: 200, y: 500,
795
825
  # origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
796
826
  # f1.create_pointer_down(:left)
@@ -798,7 +828,7 @@ module Appium
798
828
  # origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
799
829
  # f1.create_pointer_up(:left)
800
830
  #
801
- # f2 = @driver.action.add_pointer_input(:touch, 'finger2')
831
+ # f2 = ::Selenium::WebDriver::Interactions.pointer(:touch, name: 'finger2')
802
832
  # f2.create_pointer_move(duration: 1, x: 200, y: 500,
803
833
  # origin: ::Selenium::WebDriver::Interactions::PointerMove::VIEWPORT)
804
834
  # f2.create_pointer_down(:left)
@@ -809,7 +839,11 @@ module Appium
809
839
  # @driver.perform_actions [f1, f2] #=> 'nil' if the action succeed
810
840
  #
811
841
  def perform_actions(data)
812
- raise ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
842
+ raise ::Appium::Core::Error::ArgumentError, "'#{data}' must be Array" unless data.is_a? Array
843
+
844
+ # NOTE: 'add_input' in Selenium Ruby implementation has additional 'pause'.
845
+ # This implementation is to avoid the additional pause.
846
+ # https://github.com/SeleniumHQ/selenium/blob/64447d4b03f6986337d1ca8d8b6476653570bcc1/rb/lib/selenium/webdriver/common/action_builder.rb#L207
813
847
 
814
848
  @bridge.send_actions data.map(&:encode).compact
815
849
  data.each(&:clear_actions)
@@ -853,7 +887,7 @@ module Appium
853
887
  end
854
888
 
855
889
  # Get the device window's logs.
856
- # @return [String]
890
+ # @return [Appium::Core::Logs]
857
891
  #
858
892
  # @example
859
893
  #
@@ -879,16 +913,15 @@ module Appium
879
913
  # Retrieve the capabilities of the specified session.
880
914
  # It's almost same as +@driver.capabilities+ but you can get more details.
881
915
  #
882
- # @return [Selenium::WebDriver::Remote::Capabilities]
916
+ # @return [Selenium::WebDriver::Remote::Capabilities, Selenium::WebDriver::Remote::Capabilities]
883
917
  #
884
918
  # @example
885
919
  # @driver.session_capabilities
886
920
  #
887
921
  # #=> uiautomator2
888
- # # <Selenium::WebDriver::Remote::W3C::Capabilities:0x007fa38dae1360
922
+ # # <Selenium::WebDriver::Remote::Capabilities:0x007fa38dae1360
889
923
  # # @capabilities=
890
- # # {:proxy=>nil,
891
- # # :browser_name=>nil,
924
+ # # {:browser_name=>nil,
892
925
  # # :browser_version=>nil,
893
926
  # # :platform_name=>"android",
894
927
  # # :page_load_strategy=>nil,
@@ -935,10 +968,9 @@ module Appium
935
968
  # # "viewportRect"=>{"left"=>0, "top"=>63, "width"=>1080, "height"=>1731}}>
936
969
  # #
937
970
  # #=> XCUITest
938
- # # <Selenium::WebDriver::Remote::W3C::Capabilities:0x007fb15dc01370
971
+ # # <Selenium::WebDriver::Remote::Capabilities:0x007fb15dc01370
939
972
  # # @capabilities=
940
- # # {:proxy=>nil,
941
- # # :browser_name=>"UICatalog",
973
+ # # {:browser_name=>"UICatalog",
942
974
  # # :browser_version=>nil,
943
975
  # # :platform_name=>"ios",
944
976
  # # :page_load_strategy=>nil,
@@ -992,11 +1024,14 @@ module Appium
992
1024
  visualize: visualize)
993
1025
  end
994
1026
 
995
- def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil)
1027
+ def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil,
1028
+ multiple: nil, match_neighbour_threshold: nil)
996
1029
  @bridge.find_image_occurrence(full_image: full_image,
997
1030
  partial_image: partial_image,
998
1031
  visualize: visualize,
999
- threshold: threshold)
1032
+ threshold: threshold,
1033
+ multiple: multiple,
1034
+ match_neighbour_threshold: match_neighbour_threshold)
1000
1035
  end
1001
1036
 
1002
1037
  def get_images_similarity(first_image:, second_image:, visualize: false)
@@ -1009,14 +1044,14 @@ module Appium
1009
1044
 
1010
1045
  # @since Appium 1.8.2
1011
1046
  # Return an element if current view has a partial image. The logic depends on template matching by OpenCV.
1012
- # {https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/image-comparison.md image-comparison}
1047
+ # {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
1013
1048
  #
1014
1049
  # You can handle settings for the comparision following below.
1015
1050
  # {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 device-settings}
1016
1051
  #
1017
1052
  # @param [String] img_path A path to a partial image you'd like to find
1018
1053
  #
1019
- # @return [::Selenium::WebDriver::Element]
1054
+ # @return [::Appium::Core::Element]
1020
1055
  #
1021
1056
  # @example
1022
1057
  #
@@ -1031,14 +1066,14 @@ module Appium
1031
1066
 
1032
1067
  # @since Appium 1.8.2
1033
1068
  # Return elements if current view has a partial image. The logic depends on template matching by OpenCV.
1034
- # {https://github.com/appium/appium/blob/master/docs/en/writing-running-appium/image-comparison.md image-comparison}
1069
+ # {https://github.com/appium/appium/blob/1.x/docs/en/writing-running-appium/image-comparison.md image-comparison}
1035
1070
  #
1036
1071
  # You can handle settings for the comparision following below.
1037
1072
  # {https://github.com/appium/appium-base-driver/blob/master/lib/basedriver/device-settings.js#L6 device-settings}
1038
1073
  #
1039
1074
  # @param [String] img_path A path to a partial image you'd like to find
1040
1075
  #
1041
- # @return [::Selenium::WebDriver::Element]
1076
+ # @return [Array<Selenium::WebDriver::Element>]
1042
1077
  #
1043
1078
  # @example
1044
1079
  #
@@ -1086,14 +1121,14 @@ module Appium
1086
1121
  @bridge.execute_driver(script: script, type: type, timeout_ms: timeout_ms)
1087
1122
  end
1088
1123
 
1089
- # Convert vanilla element response to ::Selenium::WebDriver::Element
1124
+ # Convert vanilla element response to ::Appium::Core::Element
1090
1125
  #
1091
1126
  # @param [Hash] id The id which can get as a response from server
1092
- # @return [::Selenium::WebDriver::Element]
1127
+ # @return [::Appium::Core::Element]
1093
1128
  #
1094
1129
  # @example
1095
1130
  # response = {"element-6066-11e4-a52e-4f735466cecf"=>"xxxx", "ELEMENT"=>"xxxx"}
1096
- # ele = @driver.convert_to_element(response) #=> ::Selenium::WebDriver::Element
1131
+ # ele = @driver.convert_to_element(response) #=> ::Appium::Core::Element
1097
1132
  # ele.rect #=> Can get the rect of the element
1098
1133
  #
1099
1134
  def convert_to_element(id)