appium_lib_core 4.1.0 → 5.0.0.rc6

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +8 -0
  3. data/.github/workflows/unittest.yml +8 -9
  4. data/.rubocop.yml +89 -1
  5. data/CHANGELOG.md +64 -277
  6. data/README.md +7 -6
  7. data/Rakefile +4 -0
  8. data/appium_lib_core.gemspec +4 -4
  9. data/ci-jobs/functional/run_appium.yml +3 -3
  10. data/ci-jobs/functional_test.yml +3 -3
  11. data/docs/mobile_command.md +2 -2
  12. data/lib/appium_lib_core/android/device/auth_finger_print.rb +2 -1
  13. data/lib/appium_lib_core/android/device.rb +4 -4
  14. data/lib/appium_lib_core/common/base/bridge.rb +297 -90
  15. data/lib/appium_lib_core/common/base/capabilities.rb +10 -3
  16. data/lib/appium_lib_core/common/base/device_ime.rb +49 -0
  17. data/lib/appium_lib_core/common/base/driver.rb +148 -128
  18. data/lib/appium_lib_core/common/base/driver_settings.rb +51 -0
  19. data/lib/appium_lib_core/common/base/has_location.rb +80 -0
  20. data/lib/appium_lib_core/common/base/has_network_connection.rb +56 -0
  21. data/lib/appium_lib_core/common/base/http_default.rb +1 -3
  22. data/lib/appium_lib_core/common/base/remote_status.rb +31 -0
  23. data/lib/appium_lib_core/common/base/rotable.rb +54 -0
  24. data/lib/appium_lib_core/common/base/screenshot.rb +6 -6
  25. data/lib/appium_lib_core/common/base/search_context.rb +11 -4
  26. data/lib/appium_lib_core/common/base.rb +1 -3
  27. data/lib/appium_lib_core/common/command.rb +259 -4
  28. data/lib/appium_lib_core/common/device/image_comparison.rb +12 -4
  29. data/lib/appium_lib_core/common/device/keyevent.rb +4 -4
  30. data/lib/appium_lib_core/common/{command/mjsonwp.rb → device/orientation.rb} +14 -11
  31. data/lib/appium_lib_core/common/device/value.rb +6 -6
  32. data/lib/appium_lib_core/common/error.rb +4 -1
  33. data/lib/appium_lib_core/common/log.rb +4 -1
  34. data/lib/appium_lib_core/common/touch_action/touch_actions.rb +1 -1
  35. data/lib/appium_lib_core/common/wait.rb +42 -10
  36. data/lib/appium_lib_core/device.rb +1 -5
  37. data/lib/appium_lib_core/driver.rb +27 -46
  38. data/lib/appium_lib_core/{patch.rb → element.rb} +66 -9
  39. data/lib/appium_lib_core/ios/uiautomation/patch.rb +1 -1
  40. data/lib/appium_lib_core/{common/base/command.rb → mac2/bridge.rb} +9 -8
  41. data/lib/appium_lib_core/mac2/device/screen.rb +48 -0
  42. data/lib/appium_lib_core/mac2/device.rb +92 -0
  43. data/lib/appium_lib_core/mac2.rb +17 -0
  44. data/lib/appium_lib_core/version.rb +2 -2
  45. data/lib/appium_lib_core.rb +2 -5
  46. data/release_notes.md +92 -0
  47. data/script/commands.rb +3 -37
  48. metadata +28 -28
  49. data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +0 -81
  50. data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -252
  51. data/lib/appium_lib_core/common/command/common.rb +0 -110
  52. data/lib/appium_lib_core/common/command/w3c.rb +0 -56
@@ -55,8 +55,6 @@ module Appium
55
55
  def update_sending_request_to(scheme:, host:, port:, path:)
56
56
  return @server_url unless validate_url_param(scheme, host, port, path)
57
57
 
58
- ::Appium::Logger.debug("[experimental] This feature, #{__method__}, is an experimental")
59
-
60
58
  # Add / if 'path' does not have it
61
59
  path = path.start_with?('/') ? path : "/#{path}"
62
60
  path = path.end_with?('/') ? path : "#{path}/"
@@ -71,7 +69,7 @@ module Appium
71
69
  return true unless [scheme, host, port, path].include?(nil)
72
70
 
73
71
  message = "Given parameters are scheme: '#{scheme}', host: '#{host}', port: '#{port}', path: '#{path}'"
74
- ::Appium::Logger.warn(message)
72
+ ::Appium::Logger.debug(message)
75
73
  false
76
74
  end
77
75
 
@@ -0,0 +1,31 @@
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
+
22
+ module HasRemoteStatus
23
+ # Selenium binding has this ability only in Remote Binding,
24
+ # so this library has this method by own for safe.
25
+ def remote_status
26
+ bridge.status
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
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
+
22
+ module Rotatable
23
+ ORIENTATIONS = %i[landscape portrait].freeze
24
+
25
+ #
26
+ # Change the screen orientation
27
+ #
28
+ # @param [:landscape, :portrait] orientation
29
+ #
30
+ #
31
+ def rotation=(orientation)
32
+ unless ORIENTATIONS.include?(orientation)
33
+ raise ::Appium::Core::Error::ArgumentError, "expected #{ORIENTATIONS.inspect}, got #{orientation.inspect}"
34
+ end
35
+
36
+ bridge.screen_orientation = orientation.to_s.upcase
37
+ end
38
+ alias rotate rotation=
39
+
40
+ #
41
+ # Get the current screen orientation
42
+ #
43
+ # @return [:landscape, :portrait] orientation
44
+ #
45
+ # @api public
46
+ #
47
+
48
+ def orientation
49
+ bridge.screen_orientation.to_sym.downcase
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -15,7 +15,7 @@
15
15
  module Appium
16
16
  module Core
17
17
  class Base
18
- module TakeScreenshot
18
+ module TakesScreenshot
19
19
  #
20
20
  # Save a PNG screenshot to the given path
21
21
  #
@@ -63,8 +63,8 @@ module Appium
63
63
  def save_element_screenshot(element, png_path)
64
64
  extension = File.extname(png_path).downcase
65
65
  if extension != '.png'
66
- ::Appium::Logger.warn 'name used for saved screenshot does not match file type. '\
67
- 'It should end with .png extension'
66
+ ::Appium::Logger.warn 'name used for saved screenshot does not match file type. ' \
67
+ 'It should end with .png extension'
68
68
  end
69
69
  File.open(png_path, 'wb') { |f| f << element_screenshot_as(element, :png) }
70
70
  end
@@ -84,9 +84,9 @@ module Appium
84
84
  def element_screenshot_as(element, format)
85
85
  case format
86
86
  when :base64
87
- bridge.take_element_screenshot(element)
87
+ bridge.element_screenshot element.id
88
88
  when :png
89
- bridge.take_element_screenshot(element).unpack('m')[0]
89
+ bridge.element_screenshot(element.id).unpack('m')[0]
90
90
  else
91
91
  raise Core::Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
92
92
  end
@@ -106,7 +106,7 @@ module Appium
106
106
  ::Appium::Logger.warn 'name used for saved screenshot does not match file type. '\
107
107
  'It should end with .png extension'
108
108
  end
109
- viewport_screenshot_encode64 = bridge.take_viewport_screenshot
109
+ viewport_screenshot_encode64 = bridge.viewport_screenshot
110
110
  File.open(png_path, 'wb') { |f| f << viewport_screenshot_encode64.unpack('m')[0] }
111
111
  end
112
112
  end
@@ -141,6 +141,8 @@ module Appium
141
141
  #
142
142
  # Find all elements matching the given arguments
143
143
  #
144
+ # @return [Array<Selenium::WebDriver::Element>]
145
+ #
144
146
  # @see SearchContext#find_elements
145
147
  #
146
148
  def find_elements(*args)
@@ -157,7 +159,10 @@ module Appium
157
159
 
158
160
  def _set_by_from_finders(how)
159
161
  by = FINDERS[how.to_sym]
160
- raise ArgumentError, "cannot find element by #{how.inspect}. Available finders are #{FINDERS.keys}." unless by
162
+ unless by
163
+ raise ::Appium::Core::Error::ArgumentError,
164
+ "cannot find element by #{how.inspect}. Available finders are #{FINDERS.keys}."
165
+ end
161
166
 
162
167
  by
163
168
  end
@@ -169,16 +174,18 @@ module Appium
169
174
  when 1
170
175
  arg = args.first
171
176
 
172
- raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift" unless arg.respond_to?(:shift)
177
+ unless arg.respond_to?(:shift)
178
+ raise ::Appium::Core::Error::ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift"
179
+ end
173
180
 
174
181
  # this will be a single-entry hash, so use #shift over #first or #[]
175
182
  arr = arg.dup.shift
176
183
 
177
- raise ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
184
+ raise ::Appium::Core::Error::ArgumentError, "expected #{arr.inspect} to have 2 elements" unless arr.size == 2
178
185
 
179
186
  arr
180
187
  else
181
- raise ArgumentError, "wrong number of arguments (#{args.size} for 2)"
188
+ raise ::Appium::Core::Error::ArgumentError, "wrong number of arguments (#{args.size} for 2)"
182
189
  end
183
190
  end
184
191
  end # module SearchContext
@@ -29,14 +29,12 @@ require_relative 'device/clipboard_content_type'
29
29
  require_relative 'device/device'
30
30
  require_relative 'device/touch_actions'
31
31
  require_relative 'device/execute_driver'
32
+ require_relative 'device/orientation'
32
33
 
33
34
  # The following files have selenium-webdriver related stuff.
34
35
  require_relative 'base/driver'
35
36
  require_relative 'base/bridge'
36
- require_relative 'base/bridge/mjsonwp'
37
- require_relative 'base/bridge/w3c'
38
37
  require_relative 'base/capabilities'
39
38
  require_relative 'base/http_default'
40
39
  require_relative 'base/search_context'
41
- require_relative 'base/command'
42
40
  require_relative 'base/platform'
@@ -12,7 +12,262 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require_relative 'base/command'
16
- require_relative 'command/common'
17
- require_relative 'command/mjsonwp'
18
- require_relative 'command/w3c'
15
+ module Appium
16
+ module Core
17
+ # ref: https://github.com/appium/appium-base-driver/blob/master/lib/mjsonwp/routes.js
18
+ module Commands
19
+ # Some commands differ for each driver.
20
+ COMMAND = {
21
+ ###
22
+ # W3C
23
+ ###
24
+ status: [:get, 'status'],
25
+
26
+ #
27
+ # session handling
28
+ #
29
+
30
+ new_session: [:post, 'session'],
31
+ delete_session: [:delete, 'session/:session_id'],
32
+
33
+ #
34
+ # basic driver
35
+ #
36
+
37
+ get: [:post, 'session/:session_id/url'],
38
+ get_current_url: [:get, 'session/:session_id/url'],
39
+ back: [:post, 'session/:session_id/back'],
40
+ forward: [:post, 'session/:session_id/forward'],
41
+ refresh: [:post, 'session/:session_id/refresh'],
42
+ get_title: [:get, 'session/:session_id/title'],
43
+
44
+ #
45
+ # window and Frame handling
46
+ #
47
+
48
+ get_window_handle: [:get, 'session/:session_id/window'],
49
+ new_window: [:post, 'session/:session_id/window/new'],
50
+ close_window: [:delete, 'session/:session_id/window'],
51
+ switch_to_window: [:post, 'session/:session_id/window'],
52
+ get_window_handles: [:get, 'session/:session_id/window/handles'],
53
+ fullscreen_window: [:post, 'session/:session_id/window/fullscreen'],
54
+ minimize_window: [:post, 'session/:session_id/window/minimize'],
55
+ maximize_window: [:post, 'session/:session_id/window/maximize'],
56
+ set_window_size: [:post, 'session/:session_id/window/size'],
57
+ get_window_size: [:get, 'session/:session_id/window/size'],
58
+ set_window_position: [:post, 'session/:session_id/window/position'],
59
+ get_window_position: [:get, 'session/:session_id/window/position'],
60
+ set_window_rect: [:post, 'session/:session_id/window/rect'],
61
+ get_window_rect: [:get, 'session/:session_id/window/rect'],
62
+ switch_to_frame: [:post, 'session/:session_id/frame'],
63
+ switch_to_parent_frame: [:post, 'session/:session_id/frame/parent'],
64
+
65
+ #
66
+ # element
67
+ #
68
+
69
+ find_element: [:post, 'session/:session_id/element'],
70
+ find_elements: [:post, 'session/:session_id/elements'],
71
+ find_child_element: [:post, 'session/:session_id/element/:id/element'],
72
+ find_child_elements: [:post, 'session/:session_id/element/:id/elements'],
73
+ get_active_element: [:get, 'session/:session_id/element/active'],
74
+ is_element_selected: [:get, 'session/:session_id/element/:id/selected'],
75
+ get_element_attribute: [:get, 'session/:session_id/element/:id/attribute/:name'],
76
+ get_element_property: [:get, 'session/:session_id/element/:id/property/:name'],
77
+ get_element_css_value: [:get, 'session/:session_id/element/:id/css/:property_name'],
78
+ get_element_text: [:get, 'session/:session_id/element/:id/text'],
79
+ get_element_tag_name: [:get, 'session/:session_id/element/:id/name'],
80
+ get_element_rect: [:get, 'session/:session_id/element/:id/rect'],
81
+ is_element_enabled: [:get, 'session/:session_id/element/:id/enabled'],
82
+
83
+ #
84
+ # document handling
85
+ #
86
+
87
+ get_page_source: [:get, 'session/:session_id/source'],
88
+ execute_script: [:post, 'session/:session_id/execute/sync'],
89
+ execute_async_script: [:post, 'session/:session_id/execute/async'],
90
+
91
+ #
92
+ # cookies
93
+ #
94
+
95
+ get_all_cookies: [:get, 'session/:session_id/cookie'],
96
+ get_cookie: [:get, 'session/:session_id/cookie/:name'],
97
+ add_cookie: [:post, 'session/:session_id/cookie'],
98
+ delete_cookie: [:delete, 'session/:session_id/cookie/:name'],
99
+ delete_all_cookies: [:delete, 'session/:session_id/cookie'],
100
+
101
+ #
102
+ # timeouts
103
+ #
104
+
105
+ set_timeout: [:post, 'session/:session_id/timeouts'],
106
+
107
+ #
108
+ # actions
109
+ #
110
+
111
+ actions: [:post, 'session/:session_id/actions'],
112
+ release_actions: [:delete, 'session/:session_id/actions'],
113
+ print_page: [:post, 'session/:session_id/print'],
114
+
115
+ #
116
+ # Element Operations
117
+ #
118
+
119
+ element_click: [:post, 'session/:session_id/element/:id/click'],
120
+ element_tap: [:post, 'session/:session_id/element/:id/tap'],
121
+ element_clear: [:post, 'session/:session_id/element/:id/clear'],
122
+ element_send_keys: [:post, 'session/:session_id/element/:id/value'],
123
+
124
+ #
125
+ # alerts
126
+ #
127
+
128
+ dismiss_alert: [:post, 'session/:session_id/alert/dismiss'],
129
+ accept_alert: [:post, 'session/:session_id/alert/accept'],
130
+ get_alert_text: [:get, 'session/:session_id/alert/text'],
131
+ send_alert_text: [:post, 'session/:session_id/alert/text'],
132
+
133
+ #
134
+ # screenshot
135
+ #
136
+
137
+ take_screenshot: [:get, 'session/:session_id/screenshot'],
138
+ take_element_screenshot: [:get, 'session/:session_id/element/:id/screenshot'],
139
+
140
+ #
141
+ # server extensions
142
+ #
143
+
144
+ upload_file: [:post, 'session/:session_id/se/file'],
145
+
146
+ ###
147
+ # Used by Appium, but no in W3C
148
+ ###
149
+
150
+ # ::Appium::Core::Base::Commands::OSS has the following commands and Appium also use them.
151
+ # Delegated to ::Appium::Core::Base::Commands::OSS commands
152
+ is_element_displayed: [:get, 'session/:session_id/element/:id/displayed'], # hint: https://w3c.github.io/webdriver/#element-displayedness
153
+
154
+ get_timeouts: [:get, 'session/:session_id/timeouts'], # https://w3c.github.io/webdriver/#get-timeouts
155
+
156
+ # Add OSS commands to W3C commands. We can remove them if we would like to remove them from W3C module.
157
+ ### Session capability
158
+ get_capabilities: [:get, 'session/:session_id'],
159
+
160
+ ### rotatable
161
+ get_screen_orientation: [:get, 'session/:session_id/orientation'],
162
+ set_screen_orientation: [:post, 'session/:session_id/orientation'],
163
+
164
+ get_location: [:get, 'session/:session_id/location'],
165
+ set_location: [:post, 'session/:session_id/location'],
166
+
167
+ ### For IME
168
+ ime_get_available_engines: [:get, 'session/:session_id/ime/available_engines'],
169
+ ime_get_active_engine: [:get, 'session/:session_id/ime/active_engine'],
170
+ ime_is_activated: [:get, 'session/:session_id/ime/activated'],
171
+ ime_deactivate: [:post, 'session/:session_id/ime/deactivate'],
172
+ ime_activate_engine: [:post, 'session/:session_id/ime/activate'],
173
+
174
+ send_keys_to_active_element: [:post, 'session/:session_id/keys'],
175
+
176
+ ### Logs
177
+ get_available_log_types: [:get, 'session/:session_id/log/types'],
178
+ get_log: [:post, 'session/:session_id/log'],
179
+
180
+ ###
181
+ # Appium own
182
+ ###
183
+
184
+ # common
185
+ get_all_sessions: [:get, 'sessions'],
186
+ available_contexts: [:get, 'session/:session_id/contexts'],
187
+ set_context: [:post, 'session/:session_id/context'],
188
+ current_context: [:get, 'session/:session_id/context'],
189
+
190
+ touch_actions: [:post, 'session/:session_id/touch/perform'],
191
+ multi_touch: [:post, 'session/:session_id/touch/multi/perform'],
192
+
193
+ set_immediate_value: [:post, 'session/:session_id/appium/element/:id/value'],
194
+ replace_value: [:post, 'session/:session_id/appium/element/:id/replace_value'],
195
+
196
+ launch_app: [:post, 'session/:session_id/appium/app/launch'],
197
+ close_app: [:post, 'session/:session_id/appium/app/close'],
198
+ reset: [:post, 'session/:session_id/appium/app/reset'],
199
+ background_app: [:post, 'session/:session_id/appium/app/background'],
200
+ app_strings: [:post, 'session/:session_id/appium/app/strings'],
201
+
202
+ device_locked?: [:post, 'session/:session_id/appium/device/is_locked'],
203
+ unlock: [:post, 'session/:session_id/appium/device/unlock'],
204
+ lock: [:post, 'session/:session_id/appium/device/lock'],
205
+ device_time: [:get, 'session/:session_id/appium/device/system_time'],
206
+ install_app: [:post, 'session/:session_id/appium/device/install_app'],
207
+ remove_app: [:post, 'session/:session_id/appium/device/remove_app'],
208
+ app_installed?: [:post, 'session/:session_id/appium/device/app_installed'],
209
+ activate_app: [:post, 'session/:session_id/appium/device/activate_app'],
210
+ terminate_app: [:post, 'session/:session_id/appium/device/terminate_app'],
211
+ app_state: [:post, 'session/:session_id/appium/device/app_state'],
212
+ shake: [:post, 'session/:session_id/appium/device/shake'],
213
+ hide_keyboard: [:post, 'session/:session_id/appium/device/hide_keyboard'],
214
+ press_keycode: [:post, 'session/:session_id/appium/device/press_keycode'],
215
+ long_press_keycode: [:post, 'session/:session_id/appium/device/long_press_keycode'],
216
+ # keyevent is only for Selendroid
217
+ keyevent: [:post, 'session/:session_id/appium/device/keyevent'],
218
+ push_file: [:post, 'session/:session_id/appium/device/push_file'],
219
+ pull_file: [:post, 'session/:session_id/appium/device/pull_file'],
220
+ pull_folder: [:post, 'session/:session_id/appium/device/pull_folder'],
221
+ get_clipboard: [:post, 'session/:session_id/appium/device/get_clipboard'],
222
+ set_clipboard: [:post, 'session/:session_id/appium/device/set_clipboard'],
223
+ finger_print: [:post, 'session/:session_id/appium/device/finger_print'],
224
+ get_settings: [:get, 'session/:session_id/appium/settings'],
225
+ update_settings: [:post, 'session/:session_id/appium/settings'],
226
+ stop_recording_screen: [:post, 'session/:session_id/appium/stop_recording_screen'],
227
+ start_recording_screen: [:post, 'session/:session_id/appium/start_recording_screen'],
228
+ compare_images: [:post, 'session/:session_id/appium/compare_images'],
229
+ is_keyboard_shown: [:get, 'session/:session_id/appium/device/is_keyboard_shown'],
230
+ execute_driver: [:post, 'session/:session_id/appium/execute_driver'],
231
+ post_log_event: [:post, 'session/:session_id/appium/log_event'],
232
+ get_log_events: [:post, 'session/:session_id/appium/events']
233
+ }.freeze
234
+
235
+ COMMAND_ANDROID = {
236
+ open_notifications: [:post, 'session/:session_id/appium/device/open_notifications'],
237
+ toggle_airplane_mode: [:post, 'session/:session_id/appium/device/toggle_airplane_mode'],
238
+ start_activity: [:post, 'session/:session_id/appium/device/start_activity'],
239
+ current_activity: [:get, 'session/:session_id/appium/device/current_activity'],
240
+ current_package: [:get, 'session/:session_id/appium/device/current_package'],
241
+ get_system_bars: [:get, 'session/:session_id/appium/device/system_bars'],
242
+ get_display_density: [:get, 'session/:session_id/appium/device/display_density'],
243
+ toggle_wifi: [:post, 'session/:session_id/appium/device/toggle_wifi'],
244
+ toggle_data: [:post, 'session/:session_id/appium/device/toggle_data'],
245
+ toggle_location_services: [:post, 'session/:session_id/appium/device/toggle_location_services'],
246
+ end_coverage: [:post, 'session/:session_id/appium/app/end_test_coverage'],
247
+ get_performance_data_types: [:post, 'session/:session_id/appium/performanceData/types'],
248
+ get_performance_data: [:post, 'session/:session_id/appium/getPerformanceData'],
249
+ get_network_connection: [:get, 'session/:session_id/network_connection'], # defined also in OSS
250
+ set_network_connection: [:post, 'session/:session_id/network_connection'], # defined also in OSS
251
+
252
+ # only emulator
253
+ send_sms: [:post, 'session/:session_id/appium/device/send_sms'],
254
+ gsm_call: [:post, 'session/:session_id/appium/device/gsm_call'],
255
+ gsm_signal: [:post, 'session/:session_id/appium/device/gsm_signal'],
256
+ gsm_voice: [:post, 'session/:session_id/appium/device/gsm_voice'],
257
+ set_network_speed: [:post, 'session/:session_id/appium/device/network_speed'],
258
+ set_power_capacity: [:post, 'session/:session_id/appium/device/power_capacity'],
259
+ set_power_ac: [:post, 'session/:session_id/appium/device/power_ac'],
260
+
261
+ # For chromium: https://chromium.googlesource.com/chromium/src/+/master/chrome/test/chromedriver/server/http_handler.cc
262
+ chrome_send_command: [:post, 'session/:session_id/goog/cdp/execute']
263
+ }.freeze
264
+
265
+ COMMAND_IOS = {
266
+ touch_id: [:post, 'session/:session_id/appium/simulator/touch_id'],
267
+ toggle_touch_id_enrollment: [:post, 'session/:session_id/appium/simulator/toggle_touch_id_enrollment']
268
+ }.freeze
269
+
270
+ COMMANDS = {}.merge(COMMAND).merge(COMMAND_ANDROID).merge(COMMAND_IOS).freeze
271
+ end # module Commands
272
+ end # module Core
273
+ end # module Appium
@@ -47,7 +47,7 @@ module Appium
47
47
  # not available in the default OpenCV installation and have to be enabled manually
48
48
  # before library compilation. The default detector name is 'ORB'.
49
49
  # @param [String] match_func The name of the matching function. The default one is 'BruteForce'.
50
- # @param [String] good_matches_factor The maximum count of "good" matches (e. g. with minimal distances).
50
+ # @param [String, nil] good_matches_factor The maximum count of "good" matches (e. g. with minimal distances).
51
51
  # The default one is nil.
52
52
  # @param [Bool] visualize Makes the endpoint to return an image, which contains the visualized result of
53
53
  # the corresponding picture matching operation. This option is disabled by default.
@@ -94,7 +94,12 @@ module Appium
94
94
  # are supported.
95
95
  # @param [Bool] visualize Makes the endpoint to return an image, which contains the visualized result of
96
96
  # the corresponding picture matching operation. This option is disabled by default.
97
- # @param [Float] threshold [0.5] At what normalized threshold to reject
97
+ # @param [Float, nil] threshold [0.5] At what normalized threshold to reject
98
+ # @param [bool, nil] multiple Whether to enable the support of multiple image occurrences @since Appium 1.21.0.
99
+ # @param [integer, nil] match_neighbour_threshold The pixel distance between matches we consider to be part of
100
+ # the same template match @since Appium 1.21.0.
101
+ # This option is only considered if multiple matches mode is enabled.
102
+ # 10 pixels by default.
98
103
  #
99
104
  # @example
100
105
  # @driver.find_image_occurrence full_image: "image data 1", partial_image: "image data 2"
@@ -102,12 +107,15 @@ module Appium
102
107
  # visual = @@driver.find_image_occurrence full_image: image1, partial_image: image2, visualize: true
103
108
  # File.write 'find_result_visual.png', Base64.decode64(visual['visualization']) # if the image is PNG
104
109
  #
105
- def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil)
110
+ def find_image_occurrence(full_image:, partial_image:, visualize: false, threshold: nil,
111
+ multiple: nil, match_neighbour_threshold: nil)
106
112
  raise "visualize should be #{MATCH_TEMPLATE[:visualize]}" unless MATCH_TEMPLATE[:visualize].member?(visualize)
107
113
 
108
114
  options = {}
109
115
  options[:visualize] = visualize
110
116
  options[:threshold] = threshold unless threshold.nil?
117
+ options[:multiple] = multiple unless multiple.nil?
118
+ options[:matchNeighbourThreshold] = match_neighbour_threshold unless match_neighbour_threshold.nil?
111
119
 
112
120
  compare_images(mode: :matchTemplate, first_image: full_image, second_image: partial_image, options: options)
113
121
  end
@@ -144,7 +152,7 @@ module Appium
144
152
  # +:matchFeatures is by default.
145
153
  # @param [String] first_image An image data. All image formats, that OpenCV library itself accepts, are supported.
146
154
  # @param [String] second_image An image data. All image formats, that OpenCV library itself accepts, are supported.
147
- # @param [Hash] options The content of this dictionary depends on the actual +mode+ value.
155
+ # @param [Hash, nil] options The content of this dictionary depends on the actual +mode+ value.
148
156
  # See the documentation on +appium-support+ module for more details.
149
157
  # @return [Hash] The content of the resulting dictionary depends on the actual +mode+ and +options+ values.
150
158
  # See the documentation on +appium-support+ module for more details.
@@ -25,8 +25,8 @@ module Appium
25
25
  end
26
26
 
27
27
  def press_keycode(key, metastate: [], flags: [])
28
- raise ArgumentError, 'flags should be Array' unless flags.is_a? Array
29
- raise ArgumentError, 'metastates should be Array' unless metastate.is_a? Array
28
+ raise ::Appium::Core::Error::ArgumentError, 'flags should be Array' unless flags.is_a? Array
29
+ raise ::Appium::Core::Error::ArgumentError, 'metastates should be Array' unless metastate.is_a? Array
30
30
 
31
31
  args = { keycode: key }
32
32
  args[:metastate] = metastate.reduce(0) { |acc, meta| acc | meta } unless metastate.empty?
@@ -36,8 +36,8 @@ module Appium
36
36
  end
37
37
 
38
38
  def long_press_keycode(key, metastate: [], flags: [])
39
- raise ArgumentError, 'flags should be Array' unless flags.is_a? Array
40
- raise ArgumentError, 'metastates should be Array' unless metastate.is_a? Array
39
+ raise ::Appium::Core::Error::ArgumentError, 'flags should be Array' unless flags.is_a? Array
40
+ raise ::Appium::Core::Error::ArgumentError, 'metastates should be Array' unless metastate.is_a? Array
41
41
 
42
42
  args = { keycode: key }
43
43
  args[:metastate] = metastate.reduce(0) { |acc, meta| acc | meta } unless metastate.empty?
@@ -14,15 +14,18 @@
14
14
 
15
15
  module Appium
16
16
  module Core
17
- module Commands
18
- module MJSONWP
19
- COMMANDS = ::Appium::Core::Commands::COMMANDS.merge(::Appium::Core::Base::Commands::OSS).merge(
20
- {
21
- # W3C already has.
22
- take_element_screenshot: [:get, 'session/:session_id/element/:id/screenshot']
23
- }
24
- ).freeze
25
- end # module MJSONWP
26
- end # module Commands
17
+ class Base
18
+ module Device
19
+ module Orientation
20
+ def screen_orientation=(orientation)
21
+ execute :set_screen_orientation, {}, { orientation: orientation }
22
+ end
23
+
24
+ def screen_orientation
25
+ execute :get_screen_orientation
26
+ end
27
+ end # module Orientation
28
+ end # module Device
29
+ end # class Base
27
30
  end # module Core
28
- end # Appium
31
+ end # module Appium
@@ -17,12 +17,12 @@ module Appium
17
17
  class Base
18
18
  module Device
19
19
  module Value
20
- def set_immediate_value(element, *value)
21
- execute :set_immediate_value, { id: element.ref }, generate_value_and_text(value)
20
+ def set_immediate_value(element_id, *value)
21
+ execute :set_immediate_value, { id: element_id }, generate_value_and_text(value)
22
22
  end
23
23
 
24
- def replace_value(element, *value)
25
- execute :replace_value, { id: element.ref }, generate_value_and_text(value)
24
+ def replace_value(element_id, *value)
25
+ execute :replace_value, { id: element_id }, generate_value_and_text(value)
26
26
  end
27
27
 
28
28
  private
@@ -39,11 +39,11 @@ module Appium
39
39
  end
40
40
 
41
41
  # Keep .split(//) for backward compatibility for now
42
- text = keys.join('')
42
+ text = keys.join
43
43
 
44
44
  # FIXME: further work for W3C. Over appium 1.15.0 or later
45
45
  # { value: text.split(//), text: text }
46
- { value: text.split(//) }
46
+ { value: text.chars }
47
47
  end
48
48
  end # module Value
49
49
  end # module Device
@@ -27,8 +27,11 @@ module Appium
27
27
 
28
28
  class UnsupportedOperationError < CoreError; end
29
29
 
30
- # Server side error
30
+ # Server side errors
31
31
  class ServerError < CoreError; end
32
+
33
+ # ruby_lib_core library specific errors
34
+ class ArgumentError < CoreError; end
32
35
  end
33
36
  end
34
37
  end
@@ -65,7 +65,10 @@ module Appium
65
65
  end
66
66
 
67
67
  def event=(log_event)
68
- raise ArgumentError('log_event should be Hash like { vendor: "appium", event: "funEvent"}') unless log_event.is_a?(Hash)
68
+ unless log_event.is_a?(Hash)
69
+ raise ::Appium::Core::Error::ArgumentError,
70
+ 'log_event should be Hash like { vendor: "appium", event: "funEvent"}'
71
+ end
69
72
 
70
73
  event vendor: log_event[:vendor], event: log_event[:event]
71
74
  end
@@ -195,7 +195,7 @@ module Appium
195
195
  end
196
196
 
197
197
  def args_with_ele_ref(args)
198
- args[:element] = args[:element].ref if args.key? :element
198
+ args[:element] = args[:element].id if args.key? :element
199
199
  args
200
200
  end
201
201
  end # class TouchAction