appium_lib_core 4.1.0 → 7.4.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 (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