selenium-webdriver 4.0.0.alpha5 → 4.0.0.alpha6

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +38 -0
  3. data/LICENSE +1 -1
  4. data/lib/selenium/webdriver/atoms/findElements.js +1 -1
  5. data/lib/selenium/webdriver/chrome/bridge.rb +4 -6
  6. data/lib/selenium/webdriver/chrome/driver.rb +4 -0
  7. data/lib/selenium/webdriver/chrome/options.rb +24 -19
  8. data/lib/selenium/webdriver/common.rb +1 -0
  9. data/lib/selenium/webdriver/common/driver.rb +55 -23
  10. data/lib/selenium/webdriver/common/logger.rb +1 -1
  11. data/lib/selenium/webdriver/common/manager.rb +5 -0
  12. data/lib/selenium/webdriver/common/options.rb +32 -9
  13. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  14. data/lib/selenium/webdriver/common/service.rb +12 -106
  15. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  16. data/lib/selenium/webdriver/devtools.rb +118 -0
  17. data/lib/selenium/webdriver/devtools/accessibility.rb +62 -0
  18. data/lib/selenium/webdriver/devtools/animation.rb +98 -0
  19. data/lib/selenium/webdriver/devtools/application_cache.rb +64 -0
  20. data/lib/selenium/webdriver/devtools/audits.rb +61 -0
  21. data/lib/selenium/webdriver/devtools/background_service.rb +67 -0
  22. data/lib/selenium/webdriver/devtools/browser.rb +123 -0
  23. data/lib/selenium/webdriver/devtools/cache_storage.rb +73 -0
  24. data/lib/selenium/webdriver/devtools/cast.rb +70 -0
  25. data/lib/selenium/webdriver/devtools/console.rb +57 -0
  26. data/lib/selenium/webdriver/devtools/css.rb +165 -0
  27. data/lib/selenium/webdriver/devtools/database.rb +64 -0
  28. data/lib/selenium/webdriver/devtools/debugger.rb +229 -0
  29. data/lib/selenium/webdriver/devtools/device_orientation.rb +53 -0
  30. data/lib/selenium/webdriver/devtools/dom.rb +320 -0
  31. data/lib/selenium/webdriver/devtools/domdebugger.rb +93 -0
  32. data/lib/selenium/webdriver/devtools/domsnapshot.rb +65 -0
  33. data/lib/selenium/webdriver/devtools/domstorage.rb +79 -0
  34. data/lib/selenium/webdriver/devtools/emulation.rb +180 -0
  35. data/lib/selenium/webdriver/devtools/fetch.rb +97 -0
  36. data/lib/selenium/webdriver/devtools/headless_experimental.rb +61 -0
  37. data/lib/selenium/webdriver/devtools/heap_profiler.rb +107 -0
  38. data/lib/selenium/webdriver/devtools/indexed_db.rb +100 -0
  39. data/lib/selenium/webdriver/devtools/input.rb +140 -0
  40. data/lib/selenium/webdriver/devtools/inspector.rb +55 -0
  41. data/lib/selenium/webdriver/devtools/io.rb +59 -0
  42. data/lib/selenium/webdriver/devtools/layer_tree.rb +95 -0
  43. data/lib/selenium/webdriver/devtools/log.rb +66 -0
  44. data/lib/selenium/webdriver/devtools/media.rb +57 -0
  45. data/lib/selenium/webdriver/devtools/memory.rb +86 -0
  46. data/lib/selenium/webdriver/devtools/network.rb +228 -0
  47. data/lib/selenium/webdriver/devtools/overlay.rb +157 -0
  48. data/lib/selenium/webdriver/devtools/page.rb +374 -0
  49. data/lib/selenium/webdriver/devtools/performance.rb +63 -0
  50. data/lib/selenium/webdriver/devtools/profiler.rb +111 -0
  51. data/lib/selenium/webdriver/devtools/runtime.rb +193 -0
  52. data/lib/selenium/webdriver/devtools/schema.rb +46 -0
  53. data/lib/selenium/webdriver/devtools/security.rb +71 -0
  54. data/lib/selenium/webdriver/devtools/service_worker.rb +116 -0
  55. data/lib/selenium/webdriver/devtools/storage.rb +95 -0
  56. data/lib/selenium/webdriver/devtools/system_info.rb +50 -0
  57. data/lib/selenium/webdriver/devtools/target.rb +141 -0
  58. data/lib/selenium/webdriver/devtools/tethering.rb +55 -0
  59. data/lib/selenium/webdriver/devtools/tracing.rb +76 -0
  60. data/lib/selenium/webdriver/devtools/web_audio.rb +70 -0
  61. data/lib/selenium/webdriver/devtools/web_authn.rb +94 -0
  62. data/lib/selenium/webdriver/edge_chrome/bridge.rb +9 -2
  63. data/lib/selenium/webdriver/edge_chrome/driver.rb +4 -0
  64. data/lib/selenium/webdriver/edge_chrome/options.rb +2 -0
  65. data/lib/selenium/webdriver/edge_html/options.rb +2 -9
  66. data/lib/selenium/webdriver/firefox/bridge.rb +1 -1
  67. data/lib/selenium/webdriver/firefox/driver.rb +4 -0
  68. data/lib/selenium/webdriver/firefox/options.rb +5 -10
  69. data/lib/selenium/webdriver/ie/options.rb +7 -10
  70. data/lib/selenium/webdriver/remote/bridge.rb +3 -13
  71. data/lib/selenium/webdriver/remote/capabilities.rb +11 -6
  72. data/lib/selenium/webdriver/safari/bridge.rb +1 -1
  73. data/lib/selenium/webdriver/safari/driver.rb +4 -0
  74. data/lib/selenium/webdriver/safari/options.rb +1 -8
  75. data/lib/selenium/webdriver/support/cdp_client_generator.rb +77 -0
  76. data/lib/selenium/webdriver/support/color.rb +2 -2
  77. data/lib/selenium/webdriver/version.rb +1 -1
  78. data/selenium-webdriver.gemspec +2 -2
  79. metadata +53 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d04cb682531f39f2806727c1267c2bad759729c9c3a11f134ce3b3b03577bfd2
4
- data.tar.gz: 1a08d5c92d03e56fb5374dae94b568f1531e91c722b04a971f1594ca6ef982f3
3
+ metadata.gz: e4dbf1d975d636f48a1f346ffdb79c19d612287f1f4b625e150ff586b290be49
4
+ data.tar.gz: 1835a0d9d692b3d158a596fc081b132984e458e372c7ab882b17a10bdfc48a81
5
5
  SHA512:
6
- metadata.gz: c13f2b89e2002814d96bf6a82cf384c7000757d29ba9a1038b01fe2b7df4842b145d33531f7f7ae8bf015c6b82b43e8a0205cb068f344af7092e4a9d07f1e6c3
7
- data.tar.gz: ad5cfc2f64a1a1b3e27ed6df91b06638778de23f82246e12e9e5003f162829b88fabbb8db5764d7330f35b315f1ffe2de22342e431a3fd9404cf524f2e623ed1
6
+ metadata.gz: d33d076a090456d98b7361f9d890ad97ca5771ef832f609a0145dcbc19a149602ff4cfceb71d882307954017ce971aa0f4197cd612add189770f0c9b4267aacf
7
+ data.tar.gz: c84c80cf18da2e301122a350df46db0fb35455e1c88738ffff7bb5b784c622a1bb2b63c68fffe885c65fd445133427ac1632562b02473f5fa76c5a02d8649db1
data/CHANGES CHANGED
@@ -1,3 +1,41 @@
1
+ 4.0.0.alpha6 (2020-05-28)
2
+ =========================
3
+
4
+ Chrome:
5
+ * Added DevTools classes and methods generated from the CDP specification.
6
+ It currently supports commands and events and provides Rubyish API:
7
+ driver.devtools.page.navigate(url: 'http://google.com')
8
+ driver.devtools.console.clear_messages
9
+ driver.devtools.page.enable
10
+ driver.devtools.page.on(:load_event_fired) do |params|
11
+ puts("Page loaded in #{params['timestamp']}")
12
+ end
13
+ Check https://chromedevtools.github.io/devtools-protocol/ for more information
14
+ about possible commands and events. Please note that this API is considered
15
+ to be experimental and may change any time before stable 4.0 release.
16
+ * Fixed an issue when passing :prompt_for_download (or similar snake_cased
17
+ symbols) in Options#prefs would be ignored by Chrome because Selenium
18
+ would internally convert it to camelCased format (:promptForDownload).
19
+ Now :prefs are left intact.
20
+
21
+ Edge:
22
+ * Fixed an issue when Driver#execute_cdp would not work for Chromium-based
23
+ Edge browser.
24
+
25
+ Ruby:
26
+ * Deprecated passing :desired_capabilities and :options to driver initialization
27
+ in favor of :capabilities. They now can be combined in an array to make
28
+ custom capabilities requirements:
29
+ caps = Selenium::WebDriver::Remote::Capabilities.chrome
30
+ opts = Selenium::WebDriver::Chrome::Options.new
31
+ Selenium::WebDriver.for(:remote, capabilities: :chrome)
32
+ Selenium::WebDriver.for(:remote, capabilities: caps)
33
+ Selenium::WebDriver.for(:remote, capabilities: opts)
34
+ Selenium::WebDriver.for(:remote, capabilities: [caps, opts])
35
+ * Deprecated passing Hash to :capabilities in favor of Remote::Capabilities object.
36
+ * Updated minimum require Ruby version to 2.5.
37
+ * Improved keyword arguments handling to avoid warnings in Ruby 2.7.
38
+
1
39
  4.0.0.alpha5 (2020-03-18)
2
40
  =========================
3
41
 
data/LICENSE CHANGED
@@ -187,7 +187,7 @@
187
187
  same "printed page" as the copyright notice for easier
188
188
  identification within third-party archives.
189
189
 
190
- Copyright 2019 Software Freedom Conservancy (SFC)
190
+ Copyright 2020 Software Freedom Conservancy (SFC)
191
191
 
192
192
  Licensed under the Apache License, Version 2.0 (the "License");
193
193
  you may not use this file except in compliance with the License.
@@ -110,7 +110,7 @@ function jd(a){var b=a.shape.toLowerCase();a=a.coords.split(",");if("rect"==b&&4
110
110
  function kd(a){return a.replace(/^[^\S\xa0]+|[^\S\xa0]+$/g,"")}function ld(a){var b=[];$c?md(a,b):nd(a,b);a=pa(b,kd);return kd(a.join("\n")).replace(/\xa0/g," ")}
111
111
  function od(a,b,c){if(T(a,"BR"))b.push("");else{var d=T(a,"TD"),e=W(a,"display"),f=!d&&!(0<=na(pd,e)),g=k(a.previousElementSibling)?a.previousElementSibling:fb(a.previousSibling);g=g?W(g,"display"):"";var h=W(a,"float")||W(a,"cssFloat")||W(a,"styleFloat");!f||"run-in"==g&&"none"==h||/^[\s\xa0]*$/.test(b[b.length-1]||"")||b.push("");var n=hd(a),t=null,p=null;n&&(t=W(a,"white-space"),p=W(a,"text-transform"));r(a.childNodes,function(G){c(G,b,n,t,p)});a=b[b.length-1]||"";!d&&"table-cell"!=e||!a||wa(a)||
112
112
  (b[b.length-1]+=" ");f&&"run-in"!=e&&!/^[\s\xa0]*$/.test(a)&&b.push("")}}function nd(a,b){od(a,b,function(c,d,e,f,g){3==c.nodeType&&e?qd(c,d,f,g):T(c)&&nd(c,d)})}var pd="inline inline-block inline-table none table-cell table-column table-column-group".split(" ");
113
- function qd(a,b,c,d){a=a.nodeValue.replace(/[\u200b\u200e\u200f]/g,"");a=a.replace(/(\r\n|\r|\n)/g,"\n");if("normal"==c||"nowrap"==c)a=a.replace(/\n/g," ");a="pre"==c||"pre-wrap"==c?a.replace(/[ \f\t\v\u2028\u2029]/g,"\u00a0"):a.replace(/[ \f\t\v\u2028\u2029]+/g," ");"capitalize"==d?a=a.replace(/\b(\S)/g,function(e,f){return f.toUpperCase()}):"uppercase"==d?a=a.toUpperCase():"lowercase"==d&&(a=a.toLowerCase());c=b.pop()||"";wa(c)&&0==a.lastIndexOf(" ",0)&&(a=a.substr(1));b.push(c+a)}
113
+ function qd(a,b,c,d){a=a.nodeValue.replace(/[\u200b\u200e\u200f]/g,"");a=a.replace(/(\r\n|\r|\n)/g,"\n");if("normal"==c||"nowrap"==c)a=a.replace(/\n/g," ");a="pre"==c||"pre-wrap"==c?a.replace(/[ \f\t\v\u2028\u2029]/g,"\u00a0"):a.replace(/[ \f\t\v\u2028\u2029]+/g," ");"capitalize"==d?a=a.replace(/(^|\s|\b)(\S)/g,function(e,f,g){return f+g.toUpperCase()}):"uppercase"==d?a=a.toUpperCase():"lowercase"==d&&(a=a.toLowerCase());c=b.pop()||"";wa(c)&&0==a.lastIndexOf(" ",0)&&(a=a.substr(1));b.push(c+a)}
114
114
  function gd(a){if(Oc){if("relative"==W(a,"position"))return 1;a=W(a,"filter");return(a=a.match(/^alpha\(opacity=(\d*)\)/)||a.match(/^progid:DXImageTransform.Microsoft.Alpha\(Opacity=(\d*)\)/))?Number(a[1])/100:1}return rd(a)}function rd(a){var b=1,c=W(a,"opacity");c&&(b=Number(c));(a=ad(a))&&(b*=rd(a));return b}
115
115
  function sd(a,b,c,d,e){if(3==a.nodeType&&c)qd(a,b,d,e);else if(T(a))if(T(a,"CONTENT")||T(a,"SLOT")){for(var f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(a=T(a,"CONTENT")?a.getDistributedNodes():a.assignedNodes(),r(a,function(g){sd(g,b,c,d,e)})):md(a,b)}else if(T(a,"SHADOW")){for(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)r(a.childNodes,function(g){sd(g,b,c,d,e)}),a=a.olderShadowRoot}else md(a,b)}
116
116
  function md(a,b){a.shadowRoot&&r(a.shadowRoot.childNodes,function(c){sd(c,b,!0,null,null)});od(a,b,function(c,d,e,f,g){var h=null;1==c.nodeType?h=c:3==c.nodeType&&(h=c);null!=h&&(null!=h.assignedSlot||h.getDestinationInsertionPoints&&0<h.getDestinationInsertionPoints().length)||sd(c,d,e,f,g)})};var td={A:function(a,b){return!(!a.querySelectorAll||!a.querySelector)&&!/^\d.*/.test(b)},o:function(a,b){var c=db(b),d=l(a)?c.a.getElementById(a):a;return d?Wc(d,"id")==a&&b!=d&&gb(b,d)?d:ta(lb(c,"*"),function(e){return Wc(e,"id")==a&&b!=e&&gb(b,e)}):null},j:function(a,b){if(!a)return[];if(td.A(b,a))try{return b.querySelectorAll("#"+td.R(a))}catch(c){return[]}b=lb(db(b),"*",null,b);return oa(b,function(c){return Wc(c,"id")==a})},R:function(a){return a.replace(/([\s'"\\#.:;,!?+<>=~*^$|%&@`{}\-\/\[\]\(\)])/g,
@@ -20,7 +20,7 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Chrome
23
- module Bridge
23
+ class Bridge < WebDriver::Remote::Bridge
24
24
 
25
25
  COMMANDS = {
26
26
  get_network_conditions: [:get, 'session/:session_id/chromium/network_conditions'],
@@ -55,11 +55,9 @@ module Selenium
55
55
  data = execute :get_log, {}, {type: type.to_s}
56
56
 
57
57
  Array(data).map do |l|
58
- begin
59
- LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
60
- rescue KeyError
61
- next
62
- end
58
+ LogEntry.new l.fetch('level', 'UNKNOWN'), l.fetch('timestamp'), l.fetch('message')
59
+ rescue KeyError
60
+ next
63
61
  end
64
62
  end
65
63
  end # Bridge
@@ -38,6 +38,10 @@ module Selenium
38
38
  :chrome
39
39
  end
40
40
 
41
+ def bridge_class
42
+ Bridge
43
+ end
44
+
41
45
  def execute_cdp(cmd, **params)
42
46
  @bridge.send_command(cmd: cmd, params: params)
43
47
  end
@@ -24,6 +24,7 @@ module Selenium
24
24
  attr_accessor :profile
25
25
 
26
26
  KEY = 'goog:chromeOptions'
27
+ BROWSER = 'chrome'
27
28
 
28
29
  # see: http://chromedriver.chromium.org/capabilities
29
30
  CAPABILITIES = {args: 'args',
@@ -74,7 +75,7 @@ module Selenium
74
75
  #
75
76
 
76
77
  def initialize(profile: nil, encoded_extensions: nil, **opts)
77
- super(opts)
78
+ super(**opts)
78
79
 
79
80
  @profile = profile
80
81
  @options[:encoded_extensions] = encoded_extensions if encoded_extensions
@@ -179,30 +180,23 @@ module Selenium
179
180
  @options[:emulation] = opts
180
181
  end
181
182
 
182
- #
183
- # @api private
184
- #
185
-
186
- def as_json(*)
187
- options = super
188
-
189
- if @profile
190
- options['args'] ||= []
191
- options['args'] << "--user-data-dir=#{@profile[:directory]}"
192
- end
183
+ private
193
184
 
185
+ def process_browser_options(browser_options)
186
+ options = browser_options[KEY]
194
187
  options['binary'] ||= binary_path if binary_path
195
- extensions = options['extensions'] || []
196
- encoded_extensions = options.delete(:encoded_extensions) || []
188
+ (options['args'] || []) << "--user-data-dir=#{@profile[:directory]}" if @profile
189
+ merge_extensions(options)
190
+ end
197
191
 
198
- options['extensions'] = extensions.map(&method(:encode_extension)) + encoded_extensions
199
- options.delete('extensions') if options['extensions'].empty?
192
+ def merge_extensions(browser_options)
193
+ extensions = browser_options['extensions'] || []
194
+ encoded_extensions = browser_options.delete(:encoded_extensions) || []
200
195
 
201
- {KEY => generate_as_json(options)}
196
+ browser_options['extensions'] = extensions.map(&method(:encode_extension)) + encoded_extensions
197
+ browser_options.delete('extensions') if browser_options['extensions'].empty?
202
198
  end
203
199
 
204
- private
205
-
206
200
  def binary_path
207
201
  Chrome.path
208
202
  end
@@ -215,6 +209,17 @@ module Selenium
215
209
  raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.file?(path)
216
210
  raise Error::WebDriverError, "file was not an extension #{path.inspect}" unless File.extname(path) == '.crx'
217
211
  end
212
+
213
+ def generate_as_json(value, camelize_keys: true)
214
+ if value.is_a?(Hash)
215
+ value.each_with_object({}) do |(key, val), hash|
216
+ key = convert_json_key(key, camelize: camelize_keys)
217
+ hash[key] = generate_as_json(val, camelize_keys: key != 'prefs')
218
+ end
219
+ else
220
+ super
221
+ end
222
+ end
218
223
  end # Options
219
224
  end # Chrome
220
225
  end # WebDriver
@@ -23,6 +23,7 @@ require 'selenium/webdriver/common/proxy'
23
23
  require 'selenium/webdriver/common/log_entry'
24
24
  require 'selenium/webdriver/common/file_reaper'
25
25
  require 'selenium/webdriver/common/service'
26
+ require 'selenium/webdriver/common/service_manager'
26
27
  require 'selenium/webdriver/common/socket_lock'
27
28
  require 'selenium/webdriver/common/socket_poller'
28
29
  require 'selenium/webdriver/common/port_prober'
@@ -43,21 +43,21 @@ module Selenium
43
43
  def for(browser, opts = {})
44
44
  case browser
45
45
  when :chrome
46
- Chrome::Driver.new(opts)
46
+ Chrome::Driver.new(**opts)
47
47
  when :internet_explorer, :ie
48
- IE::Driver.new(opts)
48
+ IE::Driver.new(**opts)
49
49
  when :safari
50
- Safari::Driver.new(opts)
50
+ Safari::Driver.new(**opts)
51
51
  when :firefox, :ff
52
- Firefox::Driver.new(opts)
52
+ Firefox::Driver.new(**opts)
53
53
  when :edge
54
- Edge::Driver.new(opts)
54
+ Edge::Driver.new(**opts)
55
55
  when :edge_chrome
56
- EdgeChrome::Driver.new(opts)
56
+ EdgeChrome::Driver.new(**opts)
57
57
  when :edge_html
58
- EdgeHtml::Driver.new(opts)
58
+ EdgeHtml::Driver.new(**opts)
59
59
  when :remote
60
- Remote::Driver.new(opts)
60
+ Remote::Driver.new(**opts)
61
61
  else
62
62
  raise ArgumentError, "unknown driver: #{browser.inspect}"
63
63
  end
@@ -73,7 +73,7 @@ module Selenium
73
73
 
74
74
  def initialize(bridge: nil, listener: nil, **opts)
75
75
  @service = nil
76
- bridge ||= create_bridge(opts)
76
+ bridge ||= create_bridge(**opts)
77
77
  @bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
78
78
  end
79
79
 
@@ -296,36 +296,68 @@ module Selenium
296
296
 
297
297
  def create_bridge(**opts)
298
298
  opts[:url] ||= service_url(opts)
299
+ caps = opts.delete(:capabilities)
300
+ # Note: This is deprecated
301
+ cap_array = caps.is_a?(Hash) ? [caps] : Array(caps)
302
+
303
+ desired_capabilities = opts.delete(:desired_capabilities)
304
+ if desired_capabilities
305
+ WebDriver.logger.deprecate(':desired_capabilities as a parameter for driver initialization',
306
+ ':capabilities with an Array value of capabilities/options if necessary',
307
+ id: :desired_capabilities)
308
+ desired_capabilities = Remote::Capabilities.new(desired_capabilities) if desired_capabilities.is_a?(Hash)
309
+ cap_array << desired_capabilities
310
+ end
299
311
 
300
- desired_capabilities = opts.delete(:desired_capabilities) || Remote::Capabilities.send(browser || :new)
301
312
  options = opts.delete(:options)
313
+ if options
314
+ WebDriver.logger.deprecate(':options as a parameter for driver initialization',
315
+ ':capabilities with an Array of value capabilities/options if necessary',
316
+ id: :browser_options)
317
+ cap_array << options
318
+ end
302
319
 
303
- bridge = Remote::Bridge.new(http_client: opts.delete(:http_client), url: opts.delete(:url))
304
- raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
320
+ capabilities = generate_capabilities(cap_array)
305
321
 
306
- namespacing = self.class.to_s.split('::')
322
+ bridge_opts = {http_client: opts.delete(:http_client), url: opts.delete(:url)}
323
+ raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
307
324
 
308
- if Object.const_defined?("#{namespacing[0..-2].join('::')}::Bridge") && !namespacing.include?('Remote')
309
- bridge.extend Object.const_get("#{namespacing[0, namespacing.length - 1].join('::')}::Bridge")
310
- end
325
+ bridge = (respond_to?(:bridge_class) ? bridge_class : Remote::Bridge).new(**bridge_opts)
311
326
 
312
- bridge.create_session(desired_capabilities, options)
327
+ bridge.create_session(capabilities)
313
328
  bridge
314
329
  end
315
330
 
331
+ def generate_capabilities(cap_array)
332
+ cap_array.map { |cap|
333
+ if cap.is_a? Symbol
334
+ cap = Remote::Capabilities.send(cap)
335
+ elsif cap.is_a? Hash
336
+ WebDriver.logger.deprecate("passing a Hash value to :capabilities",
337
+ 'Capabilities instance initialized with the Hash, or build values with Options class',
338
+ id: :capabilities_hash)
339
+ cap = Remote::Capabilities.new(cap)
340
+ elsif !cap.respond_to? :as_json
341
+ msg = ":capabilities parameter only accepts objects responding to #as_json which #{cap.class} does not"
342
+ raise ArgumentError, msg
343
+ end
344
+ cap&.as_json
345
+ }.inject(:merge) || Remote::Capabilities.send(browser || :new)
346
+ end
347
+
316
348
  def service_url(opts)
317
- @service = opts.delete(:service)
349
+ service_config = opts.delete(:service)
318
350
  %i[driver_opts driver_path port].each do |key|
319
351
  next unless opts.key? key
320
352
 
321
353
  WebDriver.logger.deprecate(":#{key}", ':service with an instance of Selenium::WebDriver::Service',
322
354
  id: "service_#{key}".to_sym)
323
355
  end
324
- @service ||= Service.send(browser,
325
- args: opts.delete(:driver_opts),
326
- path: opts.delete(:driver_path),
327
- port: opts.delete(:port))
328
- @service.start
356
+ service_config ||= Service.send(browser,
357
+ args: opts.delete(:driver_opts),
358
+ path: opts.delete(:driver_path),
359
+ port: opts.delete(:port))
360
+ @service = service_config.launch
329
361
  @service.uri
330
362
  end
331
363
  end # Driver
@@ -40,7 +40,7 @@ module Selenium
40
40
  :close,
41
41
  :debug, :debug?,
42
42
  :info, :info?,
43
- :warn, :warn?,
43
+ :warn?,
44
44
  :error, :error?,
45
45
  :fatal, :fatal?,
46
46
  :level, :level=
@@ -36,6 +36,7 @@ module Selenium
36
36
  # @option opts [String] :value A value
37
37
  # @option opts [String] :path ('/') A path
38
38
  # @option opts [String] :secure (false) A boolean
39
+ # @option opts [String] :same_site (Strict or Lax) currently supported only in chrome 80+ versions
39
40
  # @option opts [Time,DateTime,Numeric,nil] :expires (nil) Expiry date, either as a Time, DateTime, or seconds since epoch.
40
41
  #
41
42
  # @raise [ArgumentError] if :name or :value is not specified
@@ -48,6 +49,9 @@ module Selenium
48
49
  opts[:path] ||= '/'
49
50
  opts[:secure] ||= false
50
51
 
52
+ same_site = opts.delete(:same_site)
53
+ opts[:sameSite] = same_site if same_site
54
+
51
55
  obj = opts.delete(:expires)
52
56
  opts[:expiry] = seconds_from(obj).to_i if obj
53
57
 
@@ -169,6 +173,7 @@ module Selenium
169
173
  path: cookie['path'],
170
174
  domain: cookie['domain'] && strip_port(cookie['domain']),
171
175
  expires: cookie['expiry'] && datetime_at(cookie['expiry']),
176
+ same_site: cookie['sameSite'],
172
177
  secure: cookie['secure']
173
178
  }
174
179
  end
@@ -20,6 +20,19 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  class Options
23
+ W3C_OPTIONS = %i[browser_name browser_version platform_name accept_insecure_certs page_load_strategy proxy
24
+ set_window_rect timeouts unhandled_prompt_behavior strict_file_interactability].freeze
25
+
26
+ W3C_OPTIONS.each do |key|
27
+ define_method key do
28
+ @options[key]
29
+ end
30
+
31
+ define_method "#{key}=" do |value|
32
+ @options[key] = value
33
+ end
34
+ end
35
+
23
36
  attr_accessor :options
24
37
 
25
38
  def initialize(options: nil, **opts)
@@ -31,6 +44,7 @@ module Selenium
31
44
  else
32
45
  opts
33
46
  end
47
+ @options[:browser_name] = self.class::BROWSER
34
48
  end
35
49
 
36
50
  #
@@ -55,22 +69,30 @@ module Selenium
55
69
  def as_json(*)
56
70
  options = @options.dup
57
71
 
58
- opts = self.class::CAPABILITIES.each_with_object({}) do |(capability_alias, capability_name), hash|
72
+ w3c_options = options.select { |key, _val| W3C_OPTIONS.include?(key) }
73
+ options.delete_if { |key, _val| W3C_OPTIONS.include?(key) }
74
+
75
+ self.class::CAPABILITIES.each do |capability_alias, capability_name|
59
76
  capability_value = options.delete(capability_alias)
60
- hash[capability_name] = capability_value unless capability_value.nil?
77
+ options[capability_name] = capability_value unless capability_value.nil?
61
78
  end
62
- opts.merge(options)
79
+ browser_options = defined?(self.class::KEY) ? {self.class::KEY => options} : options
80
+
81
+ process_browser_options(browser_options) if private_methods(false).include?(:process_browser_options)
82
+ generate_as_json(w3c_options.merge(browser_options))
63
83
  end
64
84
 
65
85
  private
66
86
 
67
- def generate_as_json(value)
87
+ def generate_as_json(value, camelize_keys: true)
68
88
  if value.respond_to?(:as_json)
69
89
  value.as_json
70
90
  elsif value.is_a?(Hash)
71
- value.each_with_object({}) { |(key, val), hash| hash[convert_json_key(key)] = generate_as_json(val) }
91
+ value.each_with_object({}) do |(key, val), hash|
92
+ hash[convert_json_key(key, camelize: camelize_keys)] = generate_as_json(val, camelize_keys: camelize_keys)
93
+ end
72
94
  elsif value.is_a?(Array)
73
- value.map(&method(:generate_as_json))
95
+ value.map { |val| generate_as_json(val, camelize_keys: camelize_keys) }
74
96
  elsif value.is_a?(Symbol)
75
97
  value.to_s
76
98
  else
@@ -78,15 +100,16 @@ module Selenium
78
100
  end
79
101
  end
80
102
 
81
- def convert_json_key(key)
82
- key = camel_case(key) if key.is_a?(Symbol)
103
+ def convert_json_key(key, camelize: true)
104
+ key = key.to_s if key.is_a?(Symbol)
105
+ key = camel_case(key) if camelize
83
106
  return key if key.is_a?(String)
84
107
 
85
108
  raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
86
109
  end
87
110
 
88
111
  def camel_case(str)
89
- str.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
112
+ str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
90
113
  end
91
114
  end # Options
92
115
  end # WebDriver
@@ -32,12 +32,10 @@ module Selenium
32
32
 
33
33
  def self.free?(port)
34
34
  Platform.interfaces.each do |host|
35
- begin
36
- TCPServer.new(host, port).close
37
- rescue *IGNORED_ERRORS => e
38
- WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
39
- # ignored - some machines appear unable to bind to some of their interfaces
40
- end
35
+ TCPServer.new(host, port).close
36
+ rescue *IGNORED_ERRORS => e
37
+ WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
38
+ # ignored - some machines appear unable to bind to some of their interfaces
41
39
  end
42
40
 
43
41
  true