selenium-webdriver 4.0.0.alpha6 → 4.0.0.beta4

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +137 -4
  3. data/Gemfile +3 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/lib/selenium/server.rb +18 -26
  8. data/lib/selenium/webdriver.rb +1 -4
  9. data/lib/selenium/webdriver/atoms/findElements.js +93 -93
  10. data/lib/selenium/webdriver/atoms/getAttribute.js +75 -59
  11. data/lib/selenium/webdriver/atoms/isDisplayed.js +72 -72
  12. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  13. data/lib/selenium/webdriver/chrome.rb +1 -1
  14. data/lib/selenium/webdriver/chrome/driver.rb +25 -10
  15. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +3 -3
  16. data/lib/selenium/webdriver/chrome/options.rb +51 -39
  17. data/lib/selenium/webdriver/chrome/profile.rb +6 -3
  18. data/lib/selenium/webdriver/chrome/service.rb +4 -2
  19. data/lib/selenium/webdriver/common.rb +8 -2
  20. data/lib/selenium/webdriver/common/driver.rb +36 -8
  21. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  23. data/lib/selenium/webdriver/{edge_html/driver.rb → common/driver_extensions/has_cdp.rb} +12 -13
  24. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +6 -1
  25. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  26. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +149 -0
  27. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  29. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +67 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  32. data/lib/selenium/webdriver/common/element.rb +66 -12
  33. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  34. data/lib/selenium/webdriver/common/logger.rb +5 -2
  35. data/lib/selenium/webdriver/common/manager.rb +6 -1
  36. data/lib/selenium/webdriver/common/options.rb +76 -14
  37. data/lib/selenium/webdriver/common/platform.rb +3 -1
  38. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  39. data/lib/selenium/webdriver/common/search_context.rb +4 -1
  40. data/lib/selenium/webdriver/common/service.rb +1 -8
  41. data/lib/selenium/webdriver/common/service_manager.rb +1 -1
  42. data/lib/selenium/webdriver/common/socket_poller.rb +19 -30
  43. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  44. data/lib/selenium/webdriver/common/target_locator.rb +4 -4
  45. data/lib/selenium/webdriver/devtools.rb +44 -18
  46. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  47. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  48. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  49. data/lib/selenium/webdriver/devtools/{console.rb → request.rb} +22 -22
  50. data/lib/selenium/webdriver/edge.rb +7 -29
  51. data/lib/selenium/webdriver/{edge_chrome → edge}/driver.rb +8 -6
  52. data/lib/selenium/webdriver/{edge_chrome/bridge.rb → edge/features.rb} +9 -7
  53. data/lib/selenium/webdriver/{edge_chrome → edge}/options.rb +11 -4
  54. data/lib/selenium/webdriver/{edge_chrome → edge}/profile.rb +2 -2
  55. data/lib/selenium/webdriver/{edge_chrome → edge}/service.rb +2 -2
  56. data/lib/selenium/webdriver/firefox.rb +5 -1
  57. data/lib/selenium/webdriver/firefox/driver.rb +18 -5
  58. data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +9 -4
  59. data/lib/selenium/webdriver/firefox/options.rb +20 -21
  60. data/lib/selenium/webdriver/firefox/profile.rb +12 -2
  61. data/lib/selenium/webdriver/firefox/service.rb +1 -1
  62. data/lib/selenium/webdriver/ie/driver.rb +1 -2
  63. data/lib/selenium/webdriver/ie/options.rb +1 -11
  64. data/lib/selenium/webdriver/ie/service.rb +4 -2
  65. data/lib/selenium/webdriver/remote/bridge.rb +48 -30
  66. data/lib/selenium/webdriver/remote/capabilities.rb +105 -64
  67. data/lib/selenium/webdriver/remote/commands.rb +3 -0
  68. data/lib/selenium/webdriver/remote/driver.rb +10 -3
  69. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  70. data/lib/selenium/webdriver/remote/http/default.rb +8 -7
  71. data/lib/selenium/webdriver/remote/http/persistent.rb +6 -0
  72. data/lib/selenium/webdriver/safari.rb +8 -1
  73. data/lib/selenium/webdriver/safari/driver.rb +3 -8
  74. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  75. data/lib/selenium/webdriver/safari/options.rb +0 -25
  76. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  77. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  78. data/lib/selenium/webdriver/support/cdp_client_generator.rb +44 -13
  79. data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
  80. data/lib/selenium/webdriver/support/guards.rb +95 -0
  81. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  82. data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
  83. data/lib/selenium/webdriver/support/select.rb +2 -2
  84. data/lib/selenium/webdriver/version.rb +1 -1
  85. data/selenium-webdriver.gemspec +26 -12
  86. metadata +91 -108
  87. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -65
  88. data/lib/selenium/webdriver/devtools/accessibility.rb +0 -62
  89. data/lib/selenium/webdriver/devtools/animation.rb +0 -98
  90. data/lib/selenium/webdriver/devtools/application_cache.rb +0 -64
  91. data/lib/selenium/webdriver/devtools/audits.rb +0 -61
  92. data/lib/selenium/webdriver/devtools/background_service.rb +0 -67
  93. data/lib/selenium/webdriver/devtools/browser.rb +0 -123
  94. data/lib/selenium/webdriver/devtools/cache_storage.rb +0 -73
  95. data/lib/selenium/webdriver/devtools/cast.rb +0 -70
  96. data/lib/selenium/webdriver/devtools/css.rb +0 -165
  97. data/lib/selenium/webdriver/devtools/database.rb +0 -64
  98. data/lib/selenium/webdriver/devtools/debugger.rb +0 -229
  99. data/lib/selenium/webdriver/devtools/device_orientation.rb +0 -53
  100. data/lib/selenium/webdriver/devtools/dom.rb +0 -320
  101. data/lib/selenium/webdriver/devtools/domdebugger.rb +0 -93
  102. data/lib/selenium/webdriver/devtools/domsnapshot.rb +0 -65
  103. data/lib/selenium/webdriver/devtools/domstorage.rb +0 -79
  104. data/lib/selenium/webdriver/devtools/emulation.rb +0 -180
  105. data/lib/selenium/webdriver/devtools/fetch.rb +0 -97
  106. data/lib/selenium/webdriver/devtools/headless_experimental.rb +0 -61
  107. data/lib/selenium/webdriver/devtools/heap_profiler.rb +0 -107
  108. data/lib/selenium/webdriver/devtools/indexed_db.rb +0 -100
  109. data/lib/selenium/webdriver/devtools/input.rb +0 -140
  110. data/lib/selenium/webdriver/devtools/inspector.rb +0 -55
  111. data/lib/selenium/webdriver/devtools/io.rb +0 -59
  112. data/lib/selenium/webdriver/devtools/layer_tree.rb +0 -95
  113. data/lib/selenium/webdriver/devtools/log.rb +0 -66
  114. data/lib/selenium/webdriver/devtools/media.rb +0 -57
  115. data/lib/selenium/webdriver/devtools/memory.rb +0 -86
  116. data/lib/selenium/webdriver/devtools/network.rb +0 -228
  117. data/lib/selenium/webdriver/devtools/overlay.rb +0 -157
  118. data/lib/selenium/webdriver/devtools/page.rb +0 -374
  119. data/lib/selenium/webdriver/devtools/performance.rb +0 -63
  120. data/lib/selenium/webdriver/devtools/profiler.rb +0 -111
  121. data/lib/selenium/webdriver/devtools/runtime.rb +0 -193
  122. data/lib/selenium/webdriver/devtools/schema.rb +0 -46
  123. data/lib/selenium/webdriver/devtools/security.rb +0 -71
  124. data/lib/selenium/webdriver/devtools/service_worker.rb +0 -116
  125. data/lib/selenium/webdriver/devtools/storage.rb +0 -95
  126. data/lib/selenium/webdriver/devtools/system_info.rb +0 -50
  127. data/lib/selenium/webdriver/devtools/target.rb +0 -141
  128. data/lib/selenium/webdriver/devtools/tethering.rb +0 -55
  129. data/lib/selenium/webdriver/devtools/tracing.rb +0 -76
  130. data/lib/selenium/webdriver/devtools/web_audio.rb +0 -70
  131. data/lib/selenium/webdriver/devtools/web_authn.rb +0 -94
  132. data/lib/selenium/webdriver/edge_html/options.rb +0 -84
  133. data/lib/selenium/webdriver/edge_html/service.rb +0 -47
@@ -32,7 +32,7 @@ module Selenium
32
32
 
33
33
  private
34
34
 
35
- # Note: This processing is deprecated
35
+ # NOTE: This processing is deprecated
36
36
  def extract_service_args(driver_opts)
37
37
  driver_args = super
38
38
  driver_opts = driver_opts.dup
@@ -28,8 +28,7 @@ module Selenium
28
28
  #
29
29
 
30
30
  class Driver < WebDriver::Driver
31
- include DriverExtensions::HasWebStorage
32
- include DriverExtensions::TakesScreenshot
31
+ EXTENSIONS = [DriverExtensions::HasWebStorage].freeze
33
32
 
34
33
  def browser
35
34
  :internet_explorer
@@ -41,17 +41,7 @@ module Selenium
41
41
  use_per_process_proxy: 'ie.usePerProcessProxy',
42
42
  validate_cookie_document_type: 'ie.validateCookieDocumentType'
43
43
  }.freeze
44
- BROWSER = 'internet_explorer'
45
-
46
- CAPABILITIES.each_key do |key|
47
- define_method key do
48
- @options[key]
49
- end
50
-
51
- define_method "#{key}=" do |value|
52
- @options[key] = value
53
- end
54
- end
44
+ BROWSER = 'internet explorer'
55
45
 
56
46
  attr_reader :args
57
47
 
@@ -32,13 +32,15 @@ module Selenium
32
32
 
33
33
  private
34
34
 
35
- # Note: This processing is deprecated
35
+ # NOTE: This processing is deprecated
36
36
  def extract_service_args(driver_opts)
37
37
  driver_args = super
38
38
  driver_opts = driver_opts.dup
39
39
  driver_args << "--log-level=#{driver_opts[:log_level].to_s.upcase}" if driver_opts.key?(:log_level)
40
40
  driver_args << "--log-file=#{driver_opts[:log_file]}" if driver_opts.key?(:log_file)
41
- driver_args << "--implementation=#{driver_opts[:implementation].to_s.upcase}" if driver_opts.key?(:implementation)
41
+ if driver_opts.key?(:implementation)
42
+ driver_args << "--implementation=#{driver_opts[:implementation].to_s.upcase}"
43
+ end
42
44
  driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key?(:host)
43
45
  driver_args << "--extract_path=#{driver_opts[:extract_path]}" if driver_opts.key?(:extract_path)
44
46
  driver_args << "--silent" if driver_opts[:silent] == true
@@ -35,7 +35,7 @@ module Selenium
35
35
  # @api private
36
36
  #
37
37
 
38
- def initialize(http_client: nil, url:)
38
+ def initialize(url:, http_client: nil)
39
39
  uri = url.is_a?(URI) ? url : URI.parse(url)
40
40
  uri.path += '/' unless uri.path.end_with?('/')
41
41
 
@@ -49,7 +49,7 @@ module Selenium
49
49
  #
50
50
 
51
51
  def create_session(capabilities)
52
- response = execute(:new_session, {}, {capabilities: {firstMatch: [capabilities]}})
52
+ response = execute(:new_session, {}, prepare_capabilities_payload(capabilities))
53
53
 
54
54
  @session_id = response['sessionId']
55
55
  capabilities = response['capabilities']
@@ -57,6 +57,17 @@ module Selenium
57
57
  raise Error::WebDriverError, 'no sessionId in returned payload' unless @session_id
58
58
 
59
59
  @capabilities = Capabilities.json_create(capabilities)
60
+
61
+ case @capabilities[:browser_name]
62
+ when 'chrome'
63
+ extend(WebDriver::Chrome::Features)
64
+ when 'firefox'
65
+ extend(WebDriver::Firefox::Features)
66
+ when 'msedge'
67
+ extend(WebDriver::Edge::Features)
68
+ when 'Safari', 'Safari Technology Preview'
69
+ extend(WebDriver::Safari::Features)
70
+ end
60
71
  end
61
72
 
62
73
  #
@@ -70,7 +81,7 @@ module Selenium
70
81
  def browser
71
82
  @browser ||= begin
72
83
  name = @capabilities.browser_name
73
- name ? name.tr(' ', '_').to_sym : 'unknown'
84
+ name ? name.tr(' ', '_').downcase.to_sym : 'unknown'
74
85
  end
75
86
  end
76
87
 
@@ -207,7 +218,10 @@ module Selenium
207
218
  end
208
219
 
209
220
  def window_size(handle = :current)
210
- raise Error::UnsupportedOperationError, 'Switch to desired window before getting its size' unless handle == :current
221
+ unless handle == :current
222
+ raise Error::UnsupportedOperationError,
223
+ 'Switch to desired window before getting its size'
224
+ end
211
225
 
212
226
  data = execute :get_window_rect
213
227
  Dimension.new data['width'], data['height']
@@ -218,7 +232,10 @@ module Selenium
218
232
  end
219
233
 
220
234
  def maximize_window(handle = :current)
221
- raise Error::UnsupportedOperationError, 'Switch to desired window before changing its size' unless handle == :current
235
+ unless handle == :current
236
+ raise Error::UnsupportedOperationError,
237
+ 'Switch to desired window before changing its size'
238
+ end
222
239
 
223
240
  execute :maximize_window
224
241
  end
@@ -251,6 +268,10 @@ module Selenium
251
268
  execute :take_screenshot
252
269
  end
253
270
 
271
+ def element_screenshot(element)
272
+ execute :take_element_screenshot, id: element.ref
273
+ end
274
+
254
275
  #
255
276
  # HTML 5
256
277
  #
@@ -303,22 +324,6 @@ module Selenium
303
324
  execute_script('return sessionStorage.length')
304
325
  end
305
326
 
306
- def location
307
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
308
- end
309
-
310
- def set_location(_lat, _lon, _alt)
311
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
312
- end
313
-
314
- def network_connection
315
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting network connection'
316
- end
317
-
318
- def network_connection=(_type)
319
- raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting network connection'
320
- end
321
-
322
327
  #
323
328
  # javascript execution
324
329
  #
@@ -389,6 +394,10 @@ module Selenium
389
394
  execute :release_actions
390
395
  end
391
396
 
397
+ def print_page(options = {})
398
+ execute :print_page, {}, {options: options}
399
+ end
400
+
392
401
  def click_element(element)
393
402
  execute :element_click, id: element
394
403
  end
@@ -428,14 +437,6 @@ module Selenium
428
437
  'if (arguments[0].dispatchEvent(e)) { arguments[0].submit() }', form.as_json)
429
438
  end
430
439
 
431
- def screen_orientation=(orientation)
432
- execute :set_screen_orientation, {}, {orientation: orientation}
433
- end
434
-
435
- def screen_orientation
436
- execute :get_screen_orientation
437
- end
438
-
439
440
  #
440
441
  # element properties
441
442
  #
@@ -449,10 +450,22 @@ module Selenium
449
450
  execute_atom :getAttribute, element, name
450
451
  end
451
452
 
453
+ def element_dom_attribute(element, name)
454
+ execute :get_element_attribute, id: element.ref, name: name
455
+ end
456
+
452
457
  def element_property(element, name)
453
458
  execute :get_element_property, id: element.ref, name: name
454
459
  end
455
460
 
461
+ def element_aria_role(element)
462
+ execute :get_element_aria_role, id: element.ref
463
+ end
464
+
465
+ def element_aria_label(element)
466
+ execute :get_element_aria_label, id: element.ref
467
+ end
468
+
456
469
  def element_value(element)
457
470
  element_property element, 'value'
458
471
  end
@@ -589,6 +602,11 @@ module Selenium
589
602
  id['ELEMENT'] || id['element-6066-11e4-a52e-4f735466cecf']
590
603
  end
591
604
 
605
+ def prepare_capabilities_payload(capabilities)
606
+ capabilities = {alwaysMatch: capabilities} if !capabilities['alwaysMatch'] && !capabilities['firstMatch']
607
+ {capabilities: capabilities}
608
+ end
609
+
592
610
  def convert_locator(how, what)
593
611
  how = SearchContext::FINDERS[how.to_sym] || how
594
612
 
@@ -616,7 +634,7 @@ module Selenium
616
634
  [how, what]
617
635
  end
618
636
 
619
- ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]\(\)])/.freeze
637
+ ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/.freeze
620
638
  UNICODE_CODE_POINT = 30
621
639
 
622
640
  # Escapes invalid characters in CSS selector.
@@ -40,22 +40,15 @@ module Selenium
40
40
  :unhandled_prompt_behavior,
41
41
  :strict_file_interactability,
42
42
 
43
- # remote-specific
44
- :remote_session_id,
45
-
46
- # TODO: (AR) deprecate compatibility with OSS-capabilities
47
- :implicit_timeout,
48
- :page_load_timeout,
49
- :script_timeout
43
+ # remote-specific (webdriver.remote.sessionid)
44
+ :remote_session_id
50
45
  ].freeze
51
46
 
52
- KNOWN.each do |key|
47
+ (KNOWN - %i[proxy timeouts]).each do |key|
53
48
  define_method key do
54
49
  @capabilities.fetch(key)
55
50
  end
56
51
 
57
- next if key == :proxy
58
-
59
52
  define_method "#{key}=" do |value|
60
53
  @capabilities[key] = value
61
54
  end
@@ -82,39 +75,22 @@ module Selenium
82
75
  end
83
76
 
84
77
  def edge(opts = {})
85
- edge_html(opts)
86
- end
87
-
88
- def edge_html(opts = {})
89
- new({
90
- browser_name: 'MicrosoftEdge',
91
- platform_name: :windows
92
- }.merge(opts))
93
- end
94
-
95
- def edge_chrome(opts = {})
96
78
  new({
97
79
  browser_name: 'MicrosoftEdge'
98
80
  }.merge(opts))
99
81
  end
82
+ alias_method :microsoftedge, :edge
100
83
 
101
84
  def firefox(opts = {})
102
- opts[:browser_version] = opts.delete(:version) if opts.key?(:version)
103
- opts[:platform_name] = opts.delete(:platform) if opts.key?(:platform)
104
- opts[:timeouts] = {}
105
- opts[:timeouts]['implicit'] = opts.delete(:implicit_timeout) if opts.key?(:implicit_timeout)
106
- opts[:timeouts]['pageLoad'] = opts.delete(:page_load_timeout) if opts.key?(:page_load_timeout)
107
- opts[:timeouts]['script'] = opts.delete(:script_timeout) if opts.key?(:script_timeout)
108
- opts.delete(:timeouts) if opts[:timeouts].empty?
109
- new({browser_name: 'firefox'}.merge(opts))
85
+ new({
86
+ browser_name: 'firefox'
87
+ }.merge(opts))
110
88
  end
111
-
112
89
  alias_method :ff, :firefox
113
90
 
114
91
  def safari(opts = {})
115
92
  new({
116
- browser_name: 'safari',
117
- platform_name: :mac
93
+ browser_name: Selenium::WebDriver::Safari.technology_preview? ? "Safari Technology Preview" : 'safari'
118
94
  }.merge(opts))
119
95
  end
120
96
 
@@ -132,19 +108,21 @@ module Selenium
132
108
  end
133
109
  alias_method :ie, :internet_explorer
134
110
 
111
+ def always_match(capabilities)
112
+ new(always_match: capabilities)
113
+ end
114
+
115
+ def first_match(*capabilities)
116
+ new(first_match: capabilities)
117
+ end
118
+
135
119
  #
136
120
  # @api private
137
121
  #
138
122
 
139
123
  def json_create(data)
140
124
  data = data.dup
141
-
142
125
  caps = new
143
- caps.browser_name = data.delete('browserName') if data.key?('browserName')
144
- caps.browser_version = data.delete('browserVersion') if data.key?('browserVersion')
145
- caps.platform_name = data.delete('platformName') if data.key?('platformName')
146
- caps.accept_insecure_certs = data.delete('acceptInsecureCerts') if data.key?('acceptInsecureCerts')
147
- caps.page_load_strategy = data.delete('pageLoadStrategy') if data.key?('pageLoadStrategy')
148
126
 
149
127
  process_timeouts(caps, data.delete('timeouts'))
150
128
 
@@ -154,7 +132,14 @@ module Selenium
154
132
  end
155
133
 
156
134
  # Remote Server Specific
157
- caps[:remote_session_id] = data.delete('webdriver.remote.sessionid') if data.key?('webdriver.remote.sessionid')
135
+ if data.key?('webdriver.remote.sessionid')
136
+ caps[:remote_session_id] = data.delete('webdriver.remote.sessionid')
137
+ end
138
+
139
+ KNOWN.each do |cap|
140
+ data_value = camel_case(cap)
141
+ caps[cap] = data.delete(data_value) if data.key?(data_value)
142
+ end
158
143
 
159
144
  # any remaining pairs will be added as is, with no conversion
160
145
  caps.merge!(data)
@@ -162,6 +147,10 @@ module Selenium
162
147
  caps
163
148
  end
164
149
 
150
+ def camel_case(str_or_sym)
151
+ str_or_sym.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
152
+ end
153
+
165
154
  private
166
155
 
167
156
  def process_timeouts(caps, timeouts)
@@ -185,8 +174,9 @@ module Selenium
185
174
  #
186
175
 
187
176
  def initialize(opts = {})
188
- @capabilities = opts
189
- self.proxy = opts.delete(:proxy)
177
+ @capabilities = {}
178
+ self.proxy = opts.delete(:proxy) if opts[:proxy]
179
+ @capabilities.merge!(opts)
190
180
  end
191
181
 
192
182
  #
@@ -211,6 +201,10 @@ module Selenium
211
201
  end
212
202
  end
213
203
 
204
+ def proxy
205
+ @capabilities.fetch(:proxy)
206
+ end
207
+
214
208
  def proxy=(proxy)
215
209
  case proxy
216
210
  when Hash
@@ -222,33 +216,46 @@ module Selenium
222
216
  end
223
217
  end
224
218
 
219
+ def timeouts
220
+ @capabilities[:timeouts] ||= {}
221
+ end
222
+
223
+ def timeouts=(timeouts)
224
+ @capabilities[:timeouts] = timeouts
225
+ end
226
+
227
+ def implicit_timeout
228
+ timeouts[:implicit]
229
+ end
230
+
231
+ def implicit_timeout=(timeout)
232
+ timeouts[:implicit] = timeout
233
+ end
234
+
235
+ def page_load_timeout
236
+ timeouts[:page_load] || timeouts[:pageLoad]
237
+ end
238
+
239
+ def page_load_timeout=(timeout)
240
+ timeouts[:page_load] = timeout
241
+ end
242
+
243
+ def script_timeout
244
+ timeouts[:script]
245
+ end
246
+
247
+ def script_timeout=(timeout)
248
+ timeouts[:script] = timeout
249
+ end
250
+
225
251
  #
226
252
  # @api private
227
253
  #
228
254
 
229
255
  def as_json(*)
230
- hash = {}
231
-
232
- @capabilities.each do |key, value|
233
- case key
234
- when :platform
235
- hash['platform'] = value.to_s.upcase
236
- when :proxy
237
- if value
238
- hash['proxy'] = value.as_json
239
- hash['proxy']['proxyType'] &&= hash['proxy']['proxyType'].downcase
240
- hash['proxy']['noProxy'] = hash['proxy']['noProxy'].split(', ') if hash['proxy']['noProxy'].is_a?(String)
241
- end
242
- when String
243
- hash[key.to_s] = value
244
- when Symbol
245
- hash[camel_case(key.to_s)] = value
246
- else
247
- raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class} / #{value.inspect}"
248
- end
256
+ @capabilities.each_with_object({}) do |(key, value), hash|
257
+ hash[convert_key(key)] = process_capabilities(key, value, hash)
249
258
  end
250
-
251
- hash
252
259
  end
253
260
 
254
261
  def to_json(*)
@@ -269,10 +276,44 @@ module Selenium
269
276
 
270
277
  private
271
278
 
272
- def camel_case(str)
273
- str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
279
+ def process_capabilities(key, value, hash)
280
+ case value
281
+ when Array
282
+ value.map { |v| process_capabilities(key, v, hash) }
283
+ when Hash
284
+ value.each_with_object({}) do |(k, v), h|
285
+ h[convert_key(k)] = process_capabilities(k, v, h)
286
+ end
287
+ when Capabilities, Options
288
+ value.as_json
289
+ else
290
+ convert_value(key, value)
291
+ end
274
292
  end
275
293
 
294
+ def convert_key(key)
295
+ case key
296
+ when String
297
+ key.to_s
298
+ when Symbol
299
+ self.class.camel_case(key)
300
+ else
301
+ raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
302
+ end
303
+ end
304
+
305
+ def convert_value(key, value)
306
+ case key
307
+ when :platform
308
+ value.to_s.upcase
309
+ when :proxy
310
+ value&.as_json
311
+ when :unhandled_prompt_behavior
312
+ value.is_a?(Symbol) ? value.to_s.tr('_', ' ') : value
313
+ else
314
+ value
315
+ end
316
+ end
276
317
  end # Capabilities
277
318
  end # Remote
278
319
  end # WebDriver