appium_lib_core 4.1.0 → 7.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +286 -271
  3. data/README.md +65 -15
  4. data/Rakefile +5 -22
  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 +4 -1
  8. data/lib/appium_lib_core/android/device/network.rb +10 -0
  9. data/lib/appium_lib_core/android/device/performance.rb +3 -0
  10. data/lib/appium_lib_core/android/device/screen.rb +2 -0
  11. data/lib/appium_lib_core/android/device.rb +82 -4
  12. data/lib/appium_lib_core/common/base/bridge.rb +321 -90
  13. data/lib/appium_lib_core/common/base/capabilities.rb +8 -9
  14. data/lib/appium_lib_core/common/base/device_ime.rb +49 -0
  15. data/lib/appium_lib_core/common/base/driver.rb +272 -192
  16. data/lib/appium_lib_core/common/base/driver_settings.rb +51 -0
  17. data/lib/appium_lib_core/common/base/has_location.rb +80 -0
  18. data/lib/appium_lib_core/common/base/has_network_connection.rb +56 -0
  19. data/lib/appium_lib_core/common/base/http_default.rb +15 -38
  20. data/lib/appium_lib_core/{ios/uiautomation/bridge.rb → common/base/remote_status.rb} +9 -8
  21. data/lib/appium_lib_core/common/base/rotable.rb +62 -0
  22. data/lib/appium_lib_core/common/base/screenshot.rb +8 -8
  23. data/lib/appium_lib_core/common/base/search_context.rb +20 -6
  24. data/lib/appium_lib_core/common/base.rb +1 -3
  25. data/lib/appium_lib_core/common/command.rb +260 -4
  26. data/lib/appium_lib_core/common/device/app_management.rb +8 -14
  27. data/lib/appium_lib_core/common/device/context.rb +1 -1
  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/touch_actions.rb +2 -0
  32. data/lib/appium_lib_core/common/device/value.rb +6 -8
  33. data/lib/appium_lib_core/common/error.rb +4 -5
  34. data/lib/appium_lib_core/common/log.rb +4 -1
  35. data/lib/appium_lib_core/common/touch_action/multi_touch.rb +19 -0
  36. data/lib/appium_lib_core/common/touch_action/touch_actions.rb +16 -2
  37. data/lib/appium_lib_core/common/wait.rb +38 -6
  38. data/lib/appium_lib_core/device.rb +1 -5
  39. data/lib/appium_lib_core/driver.rb +182 -148
  40. data/lib/appium_lib_core/{patch.rb → element.rb} +75 -9
  41. data/lib/appium_lib_core/ios/xcuitest/device.rb +2 -0
  42. data/lib/appium_lib_core/{common/base/command.rb → mac2/bridge.rb} +9 -8
  43. data/lib/appium_lib_core/mac2/device/screen.rb +48 -0
  44. data/lib/appium_lib_core/mac2/device.rb +92 -0
  45. data/lib/appium_lib_core/{ios.rb → mac2.rb} +2 -5
  46. data/lib/appium_lib_core/support/event_firing_bridge.rb +57 -0
  47. data/lib/appium_lib_core/version.rb +2 -2
  48. data/lib/appium_lib_core/windows/device/app_management.rb +38 -0
  49. data/lib/appium_lib_core/windows/device.rb +2 -0
  50. data/lib/appium_lib_core.rb +21 -10
  51. metadata +31 -86
  52. data/.github/ISSUE_TEMPLATE/issue-report.md +0 -29
  53. data/.github/contributing.md +0 -26
  54. data/.github/issue_template.md +0 -20
  55. data/.github/workflows/unittest.yml +0 -68
  56. data/.gitignore +0 -18
  57. data/.rubocop.yml +0 -58
  58. data/azure-pipelines.yml +0 -15
  59. data/ci-jobs/functional/android_setup.yml +0 -3
  60. data/ci-jobs/functional/ios_setup.yml +0 -7
  61. data/ci-jobs/functional/publish_test_result.yml +0 -18
  62. data/ci-jobs/functional/run_appium.yml +0 -25
  63. data/ci-jobs/functional/start-emulator.sh +0 -26
  64. data/ci-jobs/functional_test.yml +0 -298
  65. data/docs/mobile_command.md +0 -34
  66. data/lib/appium_lib_core/common/base/bridge/mjsonwp.rb +0 -81
  67. data/lib/appium_lib_core/common/base/bridge/w3c.rb +0 -252
  68. data/lib/appium_lib_core/common/command/common.rb +0 -110
  69. data/lib/appium_lib_core/common/command/w3c.rb +0 -56
  70. data/lib/appium_lib_core/ios/uiautomation/device.rb +0 -44
  71. data/lib/appium_lib_core/ios/uiautomation/patch.rb +0 -34
  72. data/release_notes.md +0 -816
  73. data/script/commands.rb +0 -200
@@ -16,52 +16,71 @@ module Appium
16
16
  module Core
17
17
  class Base
18
18
  class Bridge < ::Selenium::WebDriver::Remote::Bridge
19
+ include Device::DeviceLock
20
+ include Device::Keyboard
21
+ include Device::ImeActions
22
+ include Device::Setting
23
+ include Device::Context
24
+ include Device::Value
25
+ include Device::FileManagement
26
+ include Device::KeyEvent
27
+ include Device::ImageComparison
28
+ include Device::AppManagement
29
+ include Device::AppState
30
+ include Device::ScreenRecord::Command
31
+ include Device::Device
32
+ include Device::TouchActions
33
+ include Device::ExecuteDriver
34
+ include Device::Orientation
35
+
19
36
  # Prefix for extra capability defined by W3C
20
37
  APPIUM_PREFIX = 'appium:'
21
38
 
22
- # TODO: Remove the forceMjsonwp after Appium server won't need it
23
- FORCE_MJSONWP = :forceMjsonwp
39
+ # No 'browserName' means the session is native appium connection
40
+ APPIUM_NATIVE_BROWSER_NAME = 'appium'
41
+
42
+ attr_reader :available_commands
43
+
44
+ def browser
45
+ @browser ||= begin
46
+ name = @capabilities&.browser_name
47
+ name ? name.tr(' ', '_').downcase.to_sym : 'unknown'
48
+ rescue KeyError
49
+ APPIUM_NATIVE_BROWSER_NAME
50
+ end
51
+ end
24
52
 
25
- # Almost same as self.handshake in ::Selenium::WebDriver::Remote::Bridge
53
+ # Appium only.
54
+ # Attach to an existing session.
26
55
  #
27
- # Implements protocol handshake which:
56
+ # @param [String] The session id to attach to.
57
+ # @param [String] platform_name The platform name to keep in the dummy capabilities
58
+ # @param [String] platform_name The automation name to keep in the dummy capabilities
59
+ # @return [::Appium::Core::Base::Capabilities]
28
60
  #
29
- # 1. Creates session with driver.
30
- # 2. Sniffs response.
31
- # 3. Based on the response, understands which dialect we should use.
61
+ # @example
32
62
  #
33
- # @return [Bridge::MJSONWP, Bridge::W3C]
63
+ # new_driver = ::Appium::Core::Driver.attach_to(
64
+ # driver.session_id,
65
+ # url: 'http://127.0.0.1:4723/wd/hub', automation_name: 'UiAutomator2', platform_name: 'Android'
66
+ # )
34
67
  #
35
- def self.handshake(**opts)
36
- desired_capabilities = opts.delete(:desired_capabilities) { ::Selenium::WebDriver::Remote::Capabilities.new }
37
-
38
- if desired_capabilities.is_a?(Symbol)
39
- unless ::Selenium::WebDriver::Remote::Capabilities.respond_to?(desired_capabilities)
40
- raise ::Selenium::WebDriver::Error::WebDriverError, "invalid desired capability: #{desired_capabilities.inspect}"
41
- end
42
-
43
- desired_capabilities = ::Selenium::WebDriver::Remote::Capabilities.__send__(desired_capabilities)
44
- end
45
-
46
- bridge = new(opts)
47
- capabilities = bridge.create_session(desired_capabilities)
48
-
49
- case bridge.dialect
50
- when :oss # for MJSONWP
51
- Bridge::MJSONWP.new(capabilities, bridge.session_id, **opts)
52
- when :w3c
53
- Bridge::W3C.new(capabilities, bridge.session_id, **opts)
54
- else
55
- raise CoreError, 'cannot understand dialect'
56
- end
68
+ def attach_to(session_id, platform_name, automation_name)
69
+ @available_commands = ::Appium::Core::Commands::COMMANDS.dup
70
+ @session_id = session_id
71
+
72
+ # generate a dummy capabilities instance which only has the given platformName and automationName
73
+ @capabilities = ::Appium::Core::Base::Capabilities.new(
74
+ 'platformName' => platform_name,
75
+ 'automationName' => automation_name
76
+ )
57
77
  end
58
78
 
59
79
  # Override
60
- # Creates session handling both OSS and W3C dialects.
61
- # Copy from Selenium::WebDriver::Remote::Bridge to keep using +merged_capabilities+ for Appium
80
+ # Creates session handling.
62
81
  #
63
- # @param [::Selenium::WebDriver::Remote::W3C::Capabilities, Hash] desired_capabilities A capability
64
- # @return [::Selenium::WebDriver::Remote::Capabilities, ::Selenium::WebDriver::Remote::W3C::Capabilities]
82
+ # @param [::Appium::Core::Base::Capabilities, Hash] capabilities A capability
83
+ # @return [::Appium::Core::Base::Capabilities]
65
84
  #
66
85
  # @example
67
86
  #
@@ -79,39 +98,29 @@ module Appium
79
98
  # }
80
99
  # }
81
100
  # core = ::Appium::Core.for(caps)
82
- # driver = core.start_driver #=> driver.dialect == :w3c if the Appium server support W3C.
101
+ # driver = core.start_driver
83
102
  #
84
- def create_session(desired_capabilities)
85
- response = execute(:new_session, {}, merged_capabilities(desired_capabilities))
86
-
87
- @session_id = response['sessionId']
88
- oss_status = response['status'] # for compatibility with Appium 1.7.1-
89
- value = response['value']
90
-
91
- if value.is_a?(Hash) # include for W3C format
92
- @session_id = value['sessionId'] if value.key?('sessionId')
103
+ def create_session(capabilities)
104
+ @available_commands = ::Appium::Core::Commands::COMMANDS.dup
93
105
 
94
- if value.key?('capabilities')
95
- value = value['capabilities']
96
- elsif value.key?('value')
97
- value = value['value']
98
- end
99
- end
106
+ always_match = add_appium_prefix(capabilities)
107
+ response = execute(:new_session, {}, { capabilities: { alwaysMatch: always_match, firstMatch: [{}] } })
100
108
 
109
+ @session_id = response['sessionId']
101
110
  raise ::Selenium::WebDriver::Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
102
111
 
103
- json_create(oss_status, value)
112
+ @capabilities = json_create(response['capabilities'])
104
113
  end
105
114
 
106
115
  # Append +appium:+ prefix for Appium following W3C spec
107
116
  # https://www.w3.org/TR/webdriver/#dfn-validate-capabilities
108
117
  #
109
- # @param [::Selenium::WebDriver::Remote::W3C::Capabilities, Hash] capabilities A capability
110
- # @return [::Selenium::WebDriver::Remote::W3C::Capabilities]
118
+ # @param [::Appium::Core::Base::Capabilities, Hash] capabilities A capability
119
+ # @return [::Appium::Core::Base::Capabilities]
111
120
  def add_appium_prefix(capabilities)
112
- w3c_capabilities = ::Selenium::WebDriver::Remote::W3C::Capabilities.new
121
+ w3c_capabilities = ::Appium::Core::Base::Capabilities.new
113
122
 
114
- capabilities = capabilities.__send__(:capabilities) unless capabilities.is_a?(Hash)
123
+ capabilities = capabilities.send(:capabilities) unless capabilities.is_a?(Hash)
115
124
 
116
125
  capabilities.each do |name, value|
117
126
  next if value.nil?
@@ -128,61 +137,283 @@ module Appium
128
137
 
129
138
  private
130
139
 
131
- def camel_case(str)
132
- str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
140
+ def camel_case(str_or_sym)
141
+ str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
133
142
  end
134
143
 
135
144
  def extension_prefix?(capability_name)
136
- snake_cased_capability_names = ::Selenium::WebDriver::Remote::W3C::Capabilities::KNOWN.map(&:to_s)
145
+ snake_cased_capability_names = ::Appium::Core::Base::Capabilities::KNOWN.map(&:to_s)
137
146
  camel_cased_capability_names = snake_cased_capability_names.map { |v| camel_case(v) }
138
147
 
148
+ # Check 'EXTENSION_CAPABILITY_PATTERN'
139
149
  snake_cased_capability_names.include?(capability_name) ||
140
150
  camel_cased_capability_names.include?(capability_name) ||
141
- capability_name.match(::Selenium::WebDriver::Remote::W3C::Capabilities::EXTENSION_CAPABILITY_PATTERN)
151
+ capability_name.match(':')
142
152
  end
143
153
 
144
- def json_create(oss_status, value)
145
- if oss_status
146
- ::Selenium::WebDriver.logger.info 'Detected OSS dialect.'
147
- @dialect = :oss
148
- ::Selenium::WebDriver::Remote::Capabilities.json_create(value)
149
- else
150
- ::Selenium::WebDriver.logger.info 'Detected W3C dialect.'
151
- @dialect = :w3c
152
- ::Selenium::WebDriver::Remote::W3C::Capabilities.json_create(value)
153
- end
154
+ def json_create(value)
155
+ ::Appium::Core::Base::Capabilities.json_create(value)
154
156
  end
155
157
 
156
- def delete_force_mjsonwp(capabilities)
157
- w3c_capabilities = ::Selenium::WebDriver::Remote::W3C::Capabilities.new
158
+ public
158
159
 
159
- capabilities = capabilities.__send__(:capabilities) unless capabilities.is_a?(Hash)
160
- capabilities.each do |name, value|
161
- next if value.nil?
162
- next if value.is_a?(String) && value.empty?
163
- next if name == FORCE_MJSONWP
160
+ # command for Appium 2.0.
161
+ def add_command(method:, url:, name:, &block)
162
+ ::Appium::Logger.info "Overriding the method '#{name}' for '#{url}'" if @available_commands.key? name
163
+
164
+ @available_commands[name] = [method, url]
165
+
166
+ ::Appium::Core::Device.add_endpoint_method name, &block
167
+ end
168
+
169
+ def commands(command)
170
+ @available_commands[command]
171
+ end
172
+
173
+ # Returns all available sessions on the Appium server instance
174
+ def sessions
175
+ execute :get_all_sessions
176
+ end
177
+
178
+ def status
179
+ execute :status
180
+ end
181
+
182
+ # Perform 'touch' actions for W3C module.
183
+ # Generate +touch+ pointer action here and users can use this via +driver.action+
184
+ # - https://www.selenium.dev/documentation/webdriver/actions_api/
185
+ # - https://www.selenium.dev/selenium/docs/api/rb/Selenium/WebDriver/ActionBuilder.html
186
+ # - https://www.selenium.dev/selenium/docs/api/rb/Selenium/WebDriver/PointerActions.html
187
+ # - https://www.selenium.dev/selenium/docs/api/rb/Selenium/WebDriver/KeyActions.html
188
+ #
189
+ # The pointer type is 'touch' by default in the Appium Ruby client.
190
+ #
191
+ # @example
192
+ #
193
+ # element = @driver.find_element(:id, "some id")
194
+ # @driver.action.click(element).perform # The 'click' is a part of 'PointerActions'
195
+ #
196
+ def action(_deprecated_async = nil, async: false, devices: nil)
197
+ ::Selenium::WebDriver::ActionBuilder.new(
198
+ self,
199
+ devices: devices || [::Selenium::WebDriver::Interactions.pointer(:touch, name: 'touch')],
200
+ async: async,
201
+ duration: 50 # milliseconds
202
+ )
203
+ end
204
+
205
+ # Port from MJSONWP
206
+ def get_timeouts
207
+ execute :get_timeouts
208
+ end
209
+
210
+ # Port from MJSONWP
211
+ def session_capabilities
212
+ ::Appium::Core::Base::Capabilities.json_create execute(:get_capabilities)
213
+ end
214
+
215
+ # For Appium
216
+ # override
217
+ def element_displayed?(element)
218
+ # For W3C
219
+ # https://github.com/SeleniumHQ/selenium/commit/b618499adcc3a9f667590652c5757c0caa703289
220
+ # execute_atom :isDisplayed, element
221
+ execute :is_element_displayed, id: element.id
222
+ end
223
+
224
+ # For Appium
225
+ # override
226
+ def element_attribute(element, name)
227
+ # For W3C in Selenium Client
228
+ # execute_atom :getAttribute, element, name.
229
+ # 'dom_attribute' in the WebDriver Selenium.
230
+ execute :get_element_attribute, id: element.id, name: name
231
+ end
232
+
233
+ # For Appium
234
+ # override
235
+ def active_element
236
+ ::Appium::Core::Element.new self, element_id_from(execute(:get_active_element))
237
+ end
238
+ alias switch_to_active_element active_element
239
+
240
+ # For Appium
241
+ # override
242
+ def find_element_by(how, what, parent_ref = [])
243
+ how, what = convert_locator(how, what)
244
+
245
+ return execute_atom(:findElements, Support::RelativeLocator.new(what).as_json).first if how == 'relative'
246
+
247
+ parent_type, parent_id = parent_ref
248
+ id = case parent_type
249
+ when :element
250
+ execute :find_child_element, { id: parent_id }, { using: how, value: what.to_s }
251
+ when :shadow_root
252
+ execute :find_shadow_child_element, { id: parent_id }, { using: how, value: what.to_s }
253
+ else
254
+ execute :find_element, {}, { using: how, value: what.to_s }
255
+ end
256
+
257
+ ::Appium::Core::Element.new self, element_id_from(id)
258
+ end
259
+
260
+ # For Appium
261
+ # override
262
+ def find_elements_by(how, what, parent_ref = [])
263
+ how, what = convert_locator(how, what)
264
+
265
+ return execute_atom :findElements, Support::RelativeLocator.new(what).as_json if how == 'relative'
266
+
267
+ parent_type, parent_id = parent_ref
268
+ ids = case parent_type
269
+ when :element
270
+ execute :find_child_elements, { id: parent_id }, { using: how, value: what.to_s }
271
+ when :shadow_root
272
+ execute :find_shadow_child_elements, { id: parent_id }, { using: how, value: what.to_s }
273
+ else
274
+ execute :find_elements, {}, { using: how, value: what.to_s }
275
+ end
276
+
277
+ ids.map { |id| ::Appium::Core::Element.new self, element_id_from(id) }
278
+ end
279
+
280
+ # For Appium
281
+ # @param [Hash] id The id which can get as a response from server
282
+ # @return [::Appium::Core::Element]
283
+ def convert_to_element(id)
284
+ ::Appium::Core::Element.new self, element_id_from(id)
285
+ end
286
+
287
+ # For Appium
288
+ # override
289
+ # called in 'extend DriverExtensions::HasNetworkConnection'
290
+ def network_connection
291
+ execute :get_network_connection
292
+ end
293
+
294
+ # For Appium
295
+ # override
296
+ # called in 'extend DriverExtensions::HasNetworkConnection'
297
+ def network_connection=(type)
298
+ execute :set_network_connection, {}, { parameters: { type: type } }
299
+ end
300
+
301
+ # For Appium
302
+ # No implementation for W3C webdriver module
303
+ # called in 'extend DriverExtensions::HasLocation'
304
+ def location
305
+ obj = execute(:get_location) || {}
306
+ ::Appium::Location.new obj['latitude'], obj['longitude'], obj['altitude']
307
+ end
308
+
309
+ # For Appium
310
+ # No implementation for W3C webdriver module
311
+ def set_location(lat, lon, alt = 0.0, speed: nil, satellites: nil)
312
+ loc = { latitude: lat, longitude: lon, altitude: alt }
313
+ loc[:speed] = speed unless speed.nil?
314
+ loc[:satellites] = satellites unless satellites.nil?
315
+ execute :set_location, {}, { location: loc }
316
+ end
317
+
318
+ #
319
+ # logs
320
+ #
321
+ # For Appium
322
+ # No implementation for W3C webdriver module
323
+ def available_log_types
324
+ types = execute :get_available_log_types
325
+ Array(types).map(&:to_sym)
326
+ end
164
327
 
165
- w3c_capabilities[name] = value
328
+ # For Appium
329
+ # No implementation for W3C webdriver module
330
+ def log(type)
331
+ data = execute :get_log, {}, { type: type.to_s }
332
+
333
+ Array(data).map do |l|
334
+ ::Selenium::WebDriver::LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
335
+ rescue KeyError
336
+ next
166
337
  end
338
+ end
167
339
 
168
- w3c_capabilities
340
+ # For Appium
341
+ def log_event(vendor, event)
342
+ execute :post_log_event, {}, { vendor: vendor, event: event }
343
+ end
344
+
345
+ # For Appium
346
+ def log_events(type = nil)
347
+ args = {}
348
+ args['type'] = type unless type.nil?
349
+
350
+ execute :get_log_events, {}, args
351
+ end
352
+
353
+ def viewport_screenshot
354
+ execute_script('mobile: viewportScreenshot')
169
355
  end
170
356
 
171
- def merged_capabilities(desired_capabilities)
172
- force_mjsonwp = desired_capabilities[FORCE_MJSONWP]
173
- desired_capabilities = delete_force_mjsonwp(desired_capabilities) unless force_mjsonwp.nil?
357
+ def element_screenshot(element_id)
358
+ execute :take_element_screenshot, id: element_id
359
+ end
360
+
361
+ # for selenium-webdriver compatibility in chrome browser session.
362
+ # This may be needed in selenium-webdriver 4.8 or over? (around the version)
363
+ # when a session starts browserName: 'chrome' for bridge.
364
+ # This method is not only for Android, but also chrome desktop browser as well.
365
+ # So this bridge itself does not restrict the target module.
366
+ def send_command(command_params)
367
+ execute :chrome_send_command, {}, command_params
368
+ end
369
+
370
+ private
371
+
372
+ def unwrap_script_result(arg)
373
+ case arg
374
+ when Array
375
+ arg.map { |e| unwrap_script_result(e) }
376
+ when Hash
377
+ element_id = element_id_from(arg)
378
+ return ::Appium::Core::Element.new(self, element_id) if element_id
174
379
 
175
- ::Appium::Logger.warn "'forceMjsonwp' no longer works. Sending both W3C and MJSONWP capabilities" if force_mjsonwp
380
+ shadow_root_id = shadow_root_id_from(arg)
381
+ return ::Selenium::WebDriver::Remote::ShadowRoot.new self, shadow_root_id if shadow_root_id
176
382
 
177
- new_caps = add_appium_prefix(desired_capabilities)
178
- w3c_capabilities = ::Selenium::WebDriver::Remote::W3C::Capabilities.from_oss(new_caps)
383
+ arg.each { |k, v| arg[k] = unwrap_script_result(v) }
384
+ else
385
+ arg
386
+ end
387
+ end
388
+
389
+ def element_id_from(id)
390
+ id['ELEMENT'] || id['element-6066-11e4-a52e-4f735466cecf']
391
+ end
179
392
 
180
- {
181
- desiredCapabilities: desired_capabilities,
182
- capabilities: {
183
- firstMatch: [w3c_capabilities]
184
- }
185
- }
393
+ # Don't convert locators for Appium in native context
394
+ def convert_locator(how, what)
395
+ # case how
396
+ # when 'class name'
397
+ # how = 'css selector'
398
+ # what = ".#{escape_css(what)}"
399
+ # when 'id'
400
+ # how = 'css selector'
401
+ # what = "##{escape_css(what)}"
402
+ # when 'name'
403
+ # how = 'css selector'
404
+ # what = "*[name='#{escape_css(what)}']"
405
+ # when 'tag name'
406
+ # how = 'css selector'
407
+ # end
408
+ #
409
+ # if what.is_a?(Hash)
410
+ # what = what.each_with_object({}) do |(h, w), hash|
411
+ # h, w = convert_locator(h.to_s, w)
412
+ # hash[h] = w
413
+ # end
414
+ # end
415
+
416
+ [how, what]
186
417
  end
187
418
  end # class Bridge
188
419
  end # class Base
@@ -15,15 +15,14 @@
15
15
  module Appium
16
16
  module Core
17
17
  class Base
18
- module Capabilities
19
- # @private
20
- # @param [Hash] opts_caps Capabilities for Appium server. All capability keys are converted to lowerCamelCase when
21
- # this client sends capabilities to Appium server as JSON format.
22
- # @return [::Selenium::WebDriver::Remote::W3C::Capabilities] Return instance of Appium::Core::Base::Capabilities
23
- # inherited ::Selenium::WebDriver::Remote::W3C::Capabilities
24
- def self.create_capabilities(opts_caps = {})
25
- ::Selenium::WebDriver::Remote::W3C::Capabilities.new(opts_caps)
26
- end
18
+ class Capabilities < ::Selenium::WebDriver::Remote::Capabilities
19
+ # TODO: Move to 'Options' way instead of 'Capabilities'.
20
+ # Selenium 5 will have Options instead of 'Capabilities'.
21
+ # https://github.com/SeleniumHQ/selenium/blob/trunk/rb/lib/selenium/webdriver/common/options.rb
22
+ # Then, Ruby client also shoud move to the Options way.
23
+ # Appium's capabilities could change by depending on Appium versions. So it does not have
24
+ # standard options like chrome and firefox etc. So, the implementation should differ from
25
+ # other browsers. But here should inherit `Options` to follow Selenium.
27
26
  end
28
27
  end
29
28
  end
@@ -0,0 +1,49 @@
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 DeviceIME
22
+ # @private this class is private
23
+ def initialize(bridge)
24
+ @bridge = bridge
25
+ end
26
+
27
+ def activate(ime_name)
28
+ @bridge.ime_activate(ime_name)
29
+ end
30
+
31
+ def available_engines
32
+ @bridge.ime_available_engines
33
+ end
34
+
35
+ def active_engine
36
+ @bridge.ime_active_engine
37
+ end
38
+
39
+ def activated?
40
+ @bridge.ime_activated
41
+ end
42
+
43
+ def deactivate
44
+ @bridge.ime_deactivate
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end