selenium-webdriver 4.9.0 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +28 -0
  3. data/Gemfile +2 -0
  4. data/README.md +1 -1
  5. data/bin/linux/selenium-manager +0 -0
  6. data/bin/macos/selenium-manager +0 -0
  7. data/bin/windows/selenium-manager.exe +0 -0
  8. data/lib/selenium/server.rb +1 -1
  9. data/lib/selenium/webdriver/atoms/findElements.js +3 -4
  10. data/lib/selenium/webdriver/common/action_builder.rb +0 -8
  11. data/lib/selenium/webdriver/common/child_process.rb +9 -9
  12. data/lib/selenium/webdriver/common/driver_finder.rb +11 -7
  13. data/lib/selenium/webdriver/common/error.rb +28 -3
  14. data/lib/selenium/webdriver/common/logger.rb +87 -30
  15. data/lib/selenium/webdriver/common/options.rb +1 -1
  16. data/lib/selenium/webdriver/common/port_prober.rb +1 -1
  17. data/lib/selenium/webdriver/common/proxy.rb +1 -1
  18. data/lib/selenium/webdriver/common/selenium_manager.rb +42 -25
  19. data/lib/selenium/webdriver/common/service.rb +10 -2
  20. data/lib/selenium/webdriver/common/service_manager.rb +4 -2
  21. data/lib/selenium/webdriver/common/socket_lock.rb +1 -1
  22. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  23. data/lib/selenium/webdriver/common/websocket_connection.rb +2 -2
  24. data/lib/selenium/webdriver/devtools.rb +1 -1
  25. data/lib/selenium/webdriver/edge/options.rb +14 -0
  26. data/lib/selenium/webdriver/firefox/profile.rb +1 -1
  27. data/lib/selenium/webdriver/remote/bridge.rb +6 -5
  28. data/lib/selenium/webdriver/remote/http/common.rb +3 -3
  29. data/lib/selenium/webdriver/remote/http/curb.rb +1 -1
  30. data/lib/selenium/webdriver/remote/http/default.rb +1 -1
  31. data/lib/selenium/webdriver/safari/service.rb +10 -0
  32. data/lib/selenium/webdriver/support/color.rb +8 -8
  33. data/lib/selenium/webdriver/version.rb +1 -1
  34. data/lib/selenium/webdriver.rb +2 -1
  35. data/selenium-webdriver.gemspec +2 -2
  36. metadata +13 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1ae360596be57c29db02808a7dae16c36062801e7639e83b366a54cdba5e3b2
4
- data.tar.gz: f31169f7cfec055abb7a2f3595eee8e453acf316651a829af5f254a0f824cf9e
3
+ metadata.gz: 57f5a526cd47137c459f2eb349f03fbebc28b428a4d1eba1aed962cb8b32f0d4
4
+ data.tar.gz: 0e246eec8fc308f54bb651245cebaf3610a5abf4f6027728a6e96210b72a397e
5
5
  SHA512:
6
- metadata.gz: 675dad14a433939c81dabbb0276b1c5a97d95f0b1451ca48aa0e908c2cc0658f1d90e3970be4e3f62e65ff5eaef5cf391b5d646f50413ca46ea2f24de821fb5a
7
- data.tar.gz: dd9d26b855e7b1f01f667d113181f6e7b35367ee74459b693a3c5872cc92a9e58f9d2d849de3aaff9738e3e77cb3f3117617219b4f76e2fda2f66bc75279ee8d
6
+ metadata.gz: 679674b291a9b3da8d41a917ed782d14743150b524767a915e464e39751971ce9420e7a21127dcf10ca070f3bd7bff14a61690c028b013daab8d638550f38a61
7
+ data.tar.gz: a39c8fdecf8a60ad8736aa3392bba7f540c692bdba451546463b8db4e9b967d81d1d30ca665aedb99901e6f173deb3af29fcdfcd7d7c087783b8e24358ae8814
data/CHANGES CHANGED
@@ -1,3 +1,31 @@
1
+ 4.10.0 (2023-06-07)
2
+ =========================
3
+ Ruby:
4
+ * Implement proxy support for Selenium Manager
5
+ * Prevent setting driver log level in Safari
6
+ * Change all Selenium Manager logging to :debug (#12145)
7
+ * Error messages include links to documentation
8
+ * Add custom error class for driver location and improve error logic
9
+
10
+ BiDi:
11
+ * Released selenium-devtools 0.114.0 (supports CDP v85, v112, v113, v114)
12
+
13
+ Edge:
14
+ * Add support for webview2
15
+
16
+ 4.9.1 (2023-05-08)
17
+ =========================
18
+ Ruby:
19
+ * Allow users to specify driver process output in Service class (#11964)
20
+ * Updated minimum required Ruby version to 3.0
21
+ * Selenium Logger defaults to :info and all debugging is now logged as :debug (#11967)
22
+ * Every logging entry can be ignored based on ID, not just warnings
23
+ * Logging entries can be filtered to allow or ignore specific IDs
24
+
25
+ BiDi:
26
+ * Fix bug with loading devtools (#11931) (thanks Boris Petrov!)
27
+ * Released selenium-devtools 0.113.0 (supports CDP v85, v111, v112, v113)
28
+
1
29
  4.9.0 (2023-04-21)
2
30
  =========================
3
31
  Ruby:
data/Gemfile CHANGED
@@ -4,3 +4,5 @@ source 'https://rubygems.org'
4
4
  Dir["#{__dir__}/*.gemspec"].each do |spec|
5
5
  gemspec name: File.basename(spec, '.gemspec')
6
6
  end
7
+
8
+ gem 'debug', '~> 1.7', require: false, platforms: %i[mri mingw x64_mingw]
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # selenium-webdriver
2
2
 
3
- This gem provides Ruby bindings for Selenium and supports MRI >= 2.6
3
+ This gem provides Ruby bindings for Selenium and supports MRI >= 3.0.
4
4
 
5
5
  ## Install
6
6
 
Binary file
Binary file
Binary file
@@ -254,7 +254,7 @@ module Selenium
254
254
  args = ['-jar', @jar, @role, '--port', @port.to_s]
255
255
  server_command = ['java'] + properties + args + @additional_args
256
256
  cp = WebDriver::ChildProcess.build(*server_command)
257
- WebDriver.logger.debug("Executing Process #{server_command}")
257
+ WebDriver.logger.debug("Executing Process #{server_command}", id: :server)
258
258
 
259
259
  if @log.is_a?(String)
260
260
  cp.io = @log
@@ -113,10 +113,9 @@ function nd(a,b,c,d){a=a.nodeValue.replace(/[\u200b\u200e\u200f]/g,"");a=a.repla
113
113
  function pd(a,b,c,d,e){if(3==a.nodeType&&c)nd(a,b,d,e);else if(S(a))if(S(a,"CONTENT")||S(a,"SLOT")){for(var f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(a=S(a,"CONTENT")?a.getDistributedNodes():a.assignedNodes(),l(a,function(g){pd(g,b,c,d,e)})):jd(a,b)}else if(S(a,"SHADOW")){for(f=a;f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)l(a.childNodes,function(g){pd(g,b,c,d,e)}),a=a.olderShadowRoot}else jd(a,b)}
114
114
  function jd(a,b){a.shadowRoot&&l(a.shadowRoot.childNodes,function(c){pd(c,b,!0,null,null)});ld(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)||pd(c,d,e,f,g)})};var qd={C:function(a,b){return!(!a.querySelectorAll||!a.querySelector)&&!/^\d.*/.test(b)},o:function(a,b){var c=eb(b),d="string"===typeof a?c.a.getElementById(a):a;return d?Uc(d,"id")==a&&b!=d&&hb(b,d)?d:ua(mb(c,"*"),function(e){return Uc(e,"id")==a&&b!=e&&hb(b,e)}):null},j:function(a,b){if(!a)return[];if(qd.C(b,a))try{return b.querySelectorAll("#"+qd.T(a))}catch(c){return[]}b=mb(eb(b),"*",null,b);return pa(b,function(c){return Uc(c,"id")==a})},T:function(a){return a.replace(/([\s'"\\#.:;,!?+<>=~*^$|%&@`{}\-\/\[\]\(\)])/g,
115
115
  "\\$1")}};var Y={},rd={};Y.N=function(a,b,c){try{var d=Nc.j("a",b)}catch(e){d=mb(eb(b),"A",null,b)}return ua(d,function(e){e=id(e);e=e.replace(/^[\s]+|[\s]+$/g,"");return c&&-1!=e.indexOf(a)||e==a})};Y.K=function(a,b,c){try{var d=Nc.j("a",b)}catch(e){d=mb(eb(b),"A",null,b)}return pa(d,function(e){e=id(e);e=e.replace(/^[\s]+|[\s]+$/g,"");return c&&-1!=e.indexOf(a)||e==a})};Y.o=function(a,b){return Y.N(a,b,!1)};Y.j=function(a,b){return Y.K(a,b,!1)};rd.o=function(a,b){return Y.N(a,b,!0)};
116
- rd.j=function(a,b){return Y.K(a,b,!0)};var Z={F:function(a,b){return function(c){var d=Z.u(a);d=W(d);c=W(c);return b.call(null,d,c)}},R:function(a){return Z.F(a,function(b,c){return c.b+c.height<b.b})},S:function(a){return Z.F(a,function(b,c){return b.b+b.height<c.b})},V:function(a){return Z.F(a,function(b,c){return c.a+c.width<b.a})},aa:function(a){return Z.F(a,function(b,c){return b.a+b.width<c.a})},W:function(a,b){var c;b?c=b:"number"==typeof a.distance&&(c=a.distance);c||(c=100);return function(d){var e=Z.u(a);if(e===d)return!1;e=
117
- W(e);d=W(d);var f=Math.abs(e.a+e.width-d.a),g=Math.abs(e.b+e.height-d.b);g=Math.abs(e.b-(d.b+d.height))<=c||g<=c;return(Math.abs(e.a-(d.a+d.width))<=c||f<=c)&&g?!0:Math.sqrt(Math.pow(Math.abs(e.a+e.width/2-(d.a+d.width/2)),2)+Math.pow(Math.abs(e.b+e.height/2-(d.b+d.height/2)),2))<=c}},u:function(a){if(ha(a)&&1==a.nodeType)return a;if(ea(a))return Z.u(a.call(null));if(ha(a)){var b;a:{if(b=sd(a)){var c=td[b];if(c&&ea(c.o)){b=c.o(a[b],Bc.document);break a}}throw new P(61,"Unsupported locator strategy: "+
118
- b);}if(!b)throw new P(7,"No element has been found by "+JSON.stringify(a));return b}throw new P(61,"Selector is of wrong type: "+JSON.stringify(a));}};Z.P={left:Z.V,right:Z.aa,above:Z.R,below:Z.S,near:Z.W};Z.O={left:Z.u,right:Z.u,above:Z.u,below:Z.u,near:Z.u};
119
- Z.U=function(a,b){var c=[];l(a,function(e){e&&ta(b,function(f){var g=f.kind,h=Z.P[g];if(!h)throw new P(61,"Cannot find filter suitable for "+g);return h.apply(null,f.args)(e)},null)&&c.push(e)},null);a=b[b.length-1];var d=Z.O[a?a.kind:"unknown"];return d?(a=d.apply(null,a.args))?Z.ba(a,c):c:c};
116
+ rd.j=function(a,b){return Y.K(a,b,!0)};var Z={F:function(a,b){return function(c){var d=Z.u(a);d=W(d);c=W(c);return b.call(null,d,c)}},R:function(a){return Z.F(a,function(b,c){return c.b+c.height<b.b})},S:function(a){return Z.F(a,function(b,c){return b.b+b.height<c.b})},V:function(a){return Z.F(a,function(b,c){return c.a+c.width<b.a})},aa:function(a){return Z.F(a,function(b,c){return b.a+b.width<c.a})},W:function(a,b){var c;b?c=b:"number"==typeof a.distance&&(c=a.distance);c||(c=50);return function(d){var e=Z.u(a);if(e===d)return!1;e=W(e);
117
+ d=W(d);e=new U(e.a-c,e.b-c,e.width+2*c,e.height+2*c);return e.a<=d.a+d.width&&d.a<=e.a+e.width&&e.b<=d.b+d.height&&d.b<=e.b+e.height}},u:function(a){if(ha(a)&&1==a.nodeType)return a;if(ea(a))return Z.u(a.call(null));if(ha(a)){var b;a:{if(b=sd(a)){var c=td[b];if(c&&ea(c.o)){b=c.o(a[b],Bc.document);break a}}throw new P(61,"Unsupported locator strategy: "+b);}if(!b)throw new P(7,"No element has been found by "+JSON.stringify(a));return b}throw new P(61,"Selector is of wrong type: "+JSON.stringify(a));
118
+ }};Z.P={left:Z.V,right:Z.aa,above:Z.R,below:Z.S,near:Z.W};Z.O={left:Z.u,right:Z.u,above:Z.u,below:Z.u,near:Z.u};Z.U=function(a,b){var c=[];l(a,function(e){e&&ta(b,function(f){var g=f.kind,h=Z.P[g];if(!h)throw new P(61,"Cannot find filter suitable for "+g);return h.apply(null,f.args)(e)},null)&&c.push(e)},null);a=b[b.length-1];var d=Z.O[a?a.kind:"unknown"];return d?(a=d.apply(null,a.args))?Z.ba(a,c):c:c};
120
119
  Z.ba=function(a,b){function c(f){f=W(f);return Math.sqrt(Math.pow(d-(f.a+Math.max(1,f.width)/2),2)+Math.pow(e-(f.b+Math.max(1,f.height)/2),2))}a=W(a);var d=a.a+Math.max(1,a.width)/2,e=a.b+Math.max(1,a.height)/2;xa(b,function(f,g){return c(f)-c(g)});return b};Z.o=function(a,b){a=Z.j(a,b);return 0==a.length?null:a[0]};
121
120
  Z.j=function(a,b){if(!a.hasOwnProperty("root")||!a.hasOwnProperty("filters"))throw new P(61,"Locator not suitable for relative locators: "+JSON.stringify(a));var c=a.filters,d=da(c);if("array"!=d&&("object"!=d||"number"!=typeof c.length))throw new P(61,"Targets should be an array: "+JSON.stringify(a));var e;S(a.root)?e=[a.root]:e=ud(a.root,b);return 0==e.length?[]:Z.U(e,a.filters)};var vd={o:function(a,b){if(""===a)throw new P(32,'Unable to locate an element with the tagName ""');return b.getElementsByTagName(a)[0]||null},j:function(a,b){if(""===a)throw new P(32,'Unable to locate an element with the tagName ""');return b.getElementsByTagName(a)}};var td={className:Dc,"class name":Dc,css:Nc,"css selector":Nc,relative:Z,id:qd,linkText:Y,"link text":Y,name:{o:function(a,b){b=mb(eb(b),"*",null,b);return ua(b,function(c){return Uc(c,"name")==a})},j:function(a,b){b=mb(eb(b),"*",null,b);return pa(b,function(c){return Uc(c,"name")==a})}},partialLinkText:rd,"partial link text":rd,tagName:vd,"tag name":vd,xpath:T};function sd(a){for(var b in a)if(a.hasOwnProperty(b))return b;return null}
122
121
  function ud(a,b){var c=sd(a);if(c){var d=td[c];if(d&&ea(d.j))return d.j(a[c],b||Bc.document)}throw new P(61,"Unsupported locator strategy: "+c);};ca("_",ud);; return this._.apply(null,arguments);}).apply({navigator:typeof window!='undefined'?window.navigator:null,document:typeof window!='undefined'?window.document:null}, arguments);}
@@ -250,14 +250,6 @@ module Selenium
250
250
  @devices << device
251
251
  device
252
252
  end
253
-
254
- def deprecate_method(device = nil, duration = nil, number = nil, method: :pause)
255
- return unless device || number || duration
256
-
257
- WebDriver.logger.deprecate "ActionBuilder##{method} with ordered parameters",
258
- ':device, :duration, :number keywords',
259
- id: method
260
- end
261
253
  end # ActionBuilder
262
254
  end # WebDriver
263
255
  end # Selenium
@@ -53,9 +53,9 @@ module Selenium
53
53
  options = {%i[out err] => io}
54
54
  options[:pgroup] = true unless Platform.windows? # NOTE: this is a bug only in Windows 7
55
55
 
56
- WebDriver.logger.debug("Starting process: #{@command} with #{options}")
56
+ WebDriver.logger.debug("Starting process: #{@command} with #{options}", id: :process)
57
57
  @pid = Process.spawn(*@command, options)
58
- WebDriver.logger.debug(" -> pid: #{@pid}")
58
+ WebDriver.logger.debug(" -> pid: #{@pid}", id: :process)
59
59
 
60
60
  Process.detach(@pid) if detach
61
61
  end
@@ -64,16 +64,16 @@ module Selenium
64
64
  return unless @pid
65
65
  return if exited?
66
66
 
67
- WebDriver.logger.debug("Sending TERM to process: #{@pid}")
67
+ WebDriver.logger.debug("Sending TERM to process: #{@pid}", id: :process)
68
68
  terminate(@pid)
69
69
  poll_for_exit(timeout)
70
70
 
71
- WebDriver.logger.debug(" -> stopped #{@pid}")
71
+ WebDriver.logger.debug(" -> stopped #{@pid}", id: :process)
72
72
  rescue TimeoutError, Errno::EINVAL
73
- WebDriver.logger.debug(" -> sending KILL to process: #{@pid}")
73
+ WebDriver.logger.debug(" -> sending KILL to process: #{@pid}", id: :process)
74
74
  kill(@pid)
75
75
  wait
76
- WebDriver.logger.debug(" -> killed #{@pid}")
76
+ WebDriver.logger.debug(" -> killed #{@pid}", id: :process)
77
77
  end
78
78
 
79
79
  def alive?
@@ -83,18 +83,18 @@ module Selenium
83
83
  def exited?
84
84
  return unless @pid
85
85
 
86
- WebDriver.logger.debug("Checking if #{@pid} is exited:")
86
+ WebDriver.logger.debug("Checking if #{@pid} is exited:", id: :process)
87
87
  _, @status = Process.waitpid2(@pid, Process::WNOHANG | Process::WUNTRACED) if @status.nil?
88
88
  return if @status.nil?
89
89
 
90
90
  exit_code = @status.exitstatus || @status.termsig
91
- WebDriver.logger.debug(" -> exit code is #{exit_code.inspect}")
91
+ WebDriver.logger.debug(" -> exit code is #{exit_code.inspect}", id: :process)
92
92
 
93
93
  !!exit_code
94
94
  end
95
95
 
96
96
  def poll_for_exit(timeout)
97
- WebDriver.logger.debug("Polling #{timeout} seconds for exit of #{@pid}")
97
+ WebDriver.logger.debug("Polling #{timeout} seconds for exit of #{@pid}", id: :process)
98
98
 
99
99
  end_time = Time.now + timeout
100
100
  sleep POLL_INTERVAL until exited? || Time.now > end_time
@@ -26,16 +26,20 @@ module Selenium
26
26
  path ||= Platform.find_binary(klass::EXECUTABLE)
27
27
 
28
28
  path ||= begin
29
- SeleniumManager.driver_path(options)
29
+ SeleniumManager.driver_path(options) unless options.is_a?(Remote::Capabilities)
30
30
  rescue StandardError => e
31
- WebDriver.logger.warn("Unable obtain driver using Selenium Manager\n #{e.message}")
32
- nil
31
+ raise Error::NoSuchDriverError, "Unable to obtain #{klass::EXECUTABLE} using Selenium Manager; #{e.message}"
32
+ end
33
+
34
+ begin
35
+ Platform.assert_file(path)
36
+ Platform.assert_executable(path)
37
+ rescue TypeError
38
+ raise Error::NoSuchDriverError, "Unable to locate or obtain #{klass::EXECUTABLE}"
39
+ rescue Error::WebDriverError => e
40
+ raise Error::NoSuchDriverError, "#{klass::EXECUTABLE} located, but: #{e.message}"
33
41
  end
34
- msg = "Unable to locate the #{klass::EXECUTABLE} executable; for more information on how to install drivers, " \
35
- 'see https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/'
36
- raise Error::WebDriverError, msg unless path
37
42
 
38
- Platform.assert_executable path
39
43
  path
40
44
  end
41
45
  end
@@ -34,13 +34,20 @@ module Selenium
34
34
  WebDriverError
35
35
  end
36
36
 
37
+ SUPPORT_MSG = 'For documentation on this error, please visit:'
38
+ ERROR_URL = 'https://www.selenium.dev/documentation/webdriver/troubleshooting/errors'
39
+
37
40
  class WebDriverError < StandardError; end
38
41
 
39
42
  #
40
43
  # An element could not be located on the page using the given search parameters.
41
44
  #
42
45
 
43
- class NoSuchElementError < WebDriverError; end
46
+ class NoSuchElementError < WebDriverError
47
+ def initialize(msg = '')
48
+ super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}#no-such-element-exception")
49
+ end
50
+ end
44
51
 
45
52
  #
46
53
  # A command to switch to a frame could not be satisfied because the frame could not be found.
@@ -58,7 +65,11 @@ module Selenium
58
65
  # A command failed because the referenced element is no longer attached to the DOM.
59
66
  #
60
67
 
61
- class StaleElementReferenceError < WebDriverError; end
68
+ class StaleElementReferenceError < WebDriverError
69
+ def initialize(msg = '')
70
+ super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}#stale-element-reference-exception")
71
+ end
72
+ end
62
73
 
63
74
  #
64
75
  # A command failed because the referenced shadow root is no longer attached to the DOM.
@@ -132,7 +143,11 @@ module Selenium
132
143
  # Argument was an invalid selector.
133
144
  #
134
145
 
135
- class InvalidSelectorError < WebDriverError; end
146
+ class InvalidSelectorError < WebDriverError
147
+ def initialize(msg = '')
148
+ super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}#invalid-selector-exception")
149
+ end
150
+ end
136
151
 
137
152
  #
138
153
  # A new session could not be created.
@@ -212,6 +227,16 @@ module Selenium
212
227
  #
213
228
 
214
229
  class UnsupportedOperationError < WebDriverError; end
230
+
231
+ #
232
+ # Indicates that driver was not specified and could not be located.
233
+ #
234
+
235
+ class NoSuchDriverError < WebDriverError
236
+ def initialize(msg = '')
237
+ super("#{msg}; #{SUPPORT_MSG} #{ERROR_URL}/driver_location")
238
+ end
239
+ end
215
240
  end # Error
216
241
  end # WebDriver
217
242
  end # Selenium
@@ -38,22 +38,33 @@ module Selenium
38
38
 
39
39
  def_delegators :@logger,
40
40
  :close,
41
- :debug, :debug?,
42
- :info, :info?,
41
+ :debug?,
42
+ :info?,
43
43
  :warn?,
44
- :error, :error?,
44
+ :error?,
45
45
  :fatal, :fatal?,
46
- :level, :level=
46
+ :level
47
47
 
48
48
  #
49
49
  # @param [String] progname Allow child projects to use Selenium's Logger pattern
50
50
  #
51
- def initialize(progname = 'Selenium', ignored: nil)
52
- @logger = create_logger(progname)
51
+ def initialize(progname = 'Selenium', default_level: nil, ignored: nil, allowed: nil)
52
+ default_level ||= $DEBUG || ENV.key?('DEBUG') ? :debug : :warn
53
+
54
+ @logger = create_logger(progname, level: default_level)
53
55
  @ignored = Array(ignored)
56
+ @allowed = Array(allowed)
54
57
  @first_warning = false
55
58
  end
56
59
 
60
+ def level=(level)
61
+ if level == :info && @logger.level == :info
62
+ info(':info is now the default log level, to see additional logging, set log level to :debug')
63
+ end
64
+
65
+ @logger.level = level
66
+ end
67
+
57
68
  #
58
69
  # Changes logger output to a new IO.
59
70
  #
@@ -81,34 +92,64 @@ module Selenium
81
92
  #
82
93
  # Will not log the provided ID.
83
94
  #
84
- # @param [Array, Symbol] id
95
+ # @param [Array, Symbol] ids
85
96
  #
86
- def ignore(id)
87
- Array(id).each { |ignore| @ignored << ignore }
97
+ def ignore(*ids)
98
+ @ignored += Array(ids).flatten
88
99
  end
89
100
 
90
101
  #
91
- # Overrides default #warn to skip ignored messages by provided id
102
+ # Will only log the provided ID.
103
+ #
104
+ # @param [Array, Symbol] ids
105
+ #
106
+ def allow(ids)
107
+ @allowed += Array(ids).flatten
108
+ end
109
+
110
+ #
111
+ # Used to supply information of interest for debugging a problem
112
+ # Overrides default #debug to skip ignored messages by provided id
92
113
  #
93
114
  # @param [String] message
94
115
  # @param [Symbol, Array<Sybmol>] id
95
116
  # @yield see #deprecate
96
117
  #
97
- def warn(message, id: [])
98
- unless @first_warning
99
- @first_warning = true
100
- warn("Details on how to use and modify Selenium logger:\n", id: [:logger_info]) do
101
- "https://selenium.dev/documentation/webdriver/troubleshooting/logging#ruby\n"
102
- end
103
- end
118
+ def debug(message, id: [], &block)
119
+ discard_or_log(:debug, message, id, &block)
120
+ end
104
121
 
105
- id = Array(id)
106
- return if (@ignored & id).any?
122
+ #
123
+ # Used to supply information of general interest
124
+ #
125
+ # @param [String] message
126
+ # @param [Symbol, Array<Sybmol>] id
127
+ # @yield see #deprecate
128
+ #
129
+ def info(message, id: [], &block)
130
+ discard_or_log(:info, message, id, &block)
131
+ end
107
132
 
108
- msg = id.empty? ? message : "[#{id.map(&:inspect).join(', ')}] #{message} "
109
- msg += " #{yield}" if block_given?
133
+ #
134
+ # Used to supply information that suggests an error occurred
135
+ #
136
+ # @param [String] message
137
+ # @param [Symbol, Array<Sybmol>] id
138
+ # @yield see #deprecate
139
+ #
140
+ def error(message, id: [], &block)
141
+ discard_or_log(:error, message, id, &block)
142
+ end
110
143
 
111
- @logger.warn { msg }
144
+ #
145
+ # Used to supply information that suggests action be taken by user
146
+ #
147
+ # @param [String] message
148
+ # @param [Symbol, Array<Sybmol>] id
149
+ # @yield see #deprecate
150
+ #
151
+ def warn(message, id: [], &block)
152
+ discard_or_log(:warn, message, id, &block)
112
153
  end
113
154
 
114
155
  #
@@ -122,11 +163,11 @@ module Selenium
122
163
  #
123
164
  def deprecate(old, new = nil, id: [], reference: '', &block)
124
165
  id = Array(id)
125
- return if @ignored.include?(:deprecations) || (@ignored & id).any?
166
+ return if @ignored.include?(:deprecations)
126
167
 
127
- ids = id.empty? ? '' : "[#{id.map(&:inspect).join(', ')}] "
168
+ id << :deprecations if @allowed.include?(:deprecations)
128
169
 
129
- message = +"[DEPRECATION] #{ids}#{old} is deprecated"
170
+ message = +"[DEPRECATION] #{old} is deprecated"
130
171
  message << if new
131
172
  ". Use #{new} instead."
132
173
  else
@@ -134,15 +175,15 @@ module Selenium
134
175
  end
135
176
  message << " See explanation for this deprecation: #{reference}." unless reference.empty?
136
177
 
137
- warn message, &block
178
+ discard_or_log(:warn, message, id, &block)
138
179
  end
139
180
 
140
181
  private
141
182
 
142
- def create_logger(name)
183
+ def create_logger(name, level:)
143
184
  logger = ::Logger.new($stdout)
144
185
  logger.progname = name
145
- logger.level = default_level
186
+ logger.level = level
146
187
  logger.formatter = proc do |severity, time, progname, msg|
147
188
  "#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n"
148
189
  end
@@ -150,8 +191,24 @@ module Selenium
150
191
  logger
151
192
  end
152
193
 
153
- def default_level
154
- $DEBUG || ENV.key?('DEBUG') ? :debug : :warn
194
+ def discard_or_log(level, message, id)
195
+ id = Array(id)
196
+ return if (@ignored & id).any?
197
+ return if @allowed.any? && (@allowed & id).none?
198
+
199
+ return if ::Logger::Severity.const_get(level.upcase) < @logger.level
200
+
201
+ unless @first_warning
202
+ @first_warning = true
203
+ info("Details on how to use and modify Selenium logger:\n", id: [:logger_info]) do
204
+ "https://selenium.dev/documentation/webdriver/troubleshooting/logging\n"
205
+ end
206
+ end
207
+
208
+ msg = id.empty? ? message : "[#{id.map(&:inspect).join(', ')}] #{message} "
209
+ msg += " #{yield}" if block_given?
210
+
211
+ @logger.send(level) { msg }
155
212
  end
156
213
  end # Logger
157
214
  end # WebDriver
@@ -128,7 +128,7 @@ module Selenium
128
128
 
129
129
  unless options.empty?
130
130
  msg = 'These options are not w3c compliant and will result in failures in a future release'
131
- WebDriver.logger.warn("#{msg}: #{options}")
131
+ WebDriver.logger.warn("#{msg}: #{options}", id: :w3c_options)
132
132
  browser_options.merge!(options)
133
133
  end
134
134
 
@@ -34,7 +34,7 @@ module Selenium
34
34
  Platform.interfaces.each do |host|
35
35
  TCPServer.new(host, port).close
36
36
  rescue *IGNORED_ERRORS => e
37
- WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
37
+ WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})", id: :driver_service)
38
38
  # ignored - some machines appear unable to bind to some of their interfaces
39
39
  end
40
40
 
@@ -152,7 +152,7 @@ module Selenium
152
152
  'socksUsername' => socks_username,
153
153
  'socksPassword' => socks_password,
154
154
  'socksVersion' => socks_version
155
- }.delete_if { |_k, v| v.nil? }
155
+ }.compact
156
156
 
157
157
  json_result if json_result.length > 1
158
158
  end
@@ -27,19 +27,31 @@ module Selenium
27
27
  # @api private
28
28
  #
29
29
  class SeleniumManager
30
- BIN_PATH = '../../../../../bin'
31
-
32
30
  class << self
31
+ attr_writer :bin_path
32
+
33
+ def bin_path
34
+ @bin_path ||= '../../../../../bin'
35
+ end
36
+
33
37
  # @param [Options] options browser options.
34
38
  # @return [String] the path to the correct driver.
35
39
  def driver_path(options)
36
- message = 'applicable driver not found; attempting to install with Selenium Manager'
37
- WebDriver.logger.warn(message)
40
+ message = 'applicable driver not found; attempting to install with Selenium Manager (Beta)'
41
+ WebDriver.logger.debug(message, id: :selenium_manager)
38
42
 
39
- unless options.is_a?(Options)
40
- raise ArgumentError, "SeleniumManager requires a WebDriver::Options instance, not #{options.inspect}"
41
- end
43
+ command = generate_command(binary, options)
44
+
45
+ location = run(*command)
46
+ WebDriver.logger.debug("Driver found at #{location}", id: :selenium_manager)
47
+ Platform.assert_executable location
48
+
49
+ location
50
+ end
51
+
52
+ private
42
53
 
54
+ def generate_command(binary, options)
43
55
  command = [binary, '--browser', options.browser_name, '--output', 'json']
44
56
  if options.browser_version
45
57
  command << '--browser-version'
@@ -49,21 +61,18 @@ module Selenium
49
61
  command << '--browser-path'
50
62
  command << options.binary.gsub('\\', '\\\\\\')
51
63
  end
64
+ if options.proxy
65
+ command << '--proxy'
66
+ (command << options.proxy.ssl) || options.proxy.http
67
+ end
52
68
  command << '--debug' if WebDriver.logger.debug?
53
-
54
- location = run(*command)
55
- WebDriver.logger.debug("Driver found at #{location}")
56
- Platform.assert_executable location
57
-
58
- location
69
+ command
59
70
  end
60
71
 
61
- private
62
-
63
72
  # @return [String] the path to the correct selenium manager
64
73
  def binary
65
74
  @binary ||= begin
66
- path = File.expand_path(BIN_PATH, __FILE__)
75
+ path = File.expand_path(bin_path, __FILE__)
67
76
  path << if Platform.windows?
68
77
  '/windows/selenium-manager.exe'
69
78
  elsif Platform.mac?
@@ -72,32 +81,40 @@ module Selenium
72
81
  '/linux/selenium-manager'
73
82
  end
74
83
  location = File.expand_path(path, __FILE__)
75
- unless location.is_a?(String) && File.exist?(location) && File.executable?(location)
76
- raise Error::WebDriverError, 'Unable to obtain Selenium Manager'
84
+
85
+ begin
86
+ Platform.assert_file(location)
87
+ Platform.assert_executable(location)
88
+ rescue TypeError
89
+ raise Error::WebDriverError,
90
+ "Unable to locate or obtain Selenium Manager binary; #{location} is not a valid file object"
91
+ rescue Error::WebDriverError => e
92
+ raise Error::WebDriverError, "Selenium Manager binary located, but #{e.message}"
77
93
  end
78
94
 
79
- WebDriver.logger.debug("Selenium Manager found at #{location}")
95
+ WebDriver.logger.debug("Selenium Manager binary found at #{location}", id: :selenium_manager)
80
96
  location
81
97
  end
82
98
  end
83
99
 
84
100
  def run(*command)
85
- WebDriver.logger.debug("Executing Process #{command}")
101
+ WebDriver.logger.debug("Executing Process #{command}", id: :selenium_manager)
86
102
 
87
103
  begin
88
104
  stdout, stderr, status = Open3.capture3(*command)
89
105
  json_output = stdout.empty? ? nil : JSON.parse(stdout)
90
106
  result = json_output&.dig('result', 'message')
91
107
  rescue StandardError => e
92
- raise Error::WebDriverError, "Unsuccessful command executed: #{command}", e.message
108
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}; #{e.message}"
93
109
  end
94
110
 
95
- if status.exitstatus.positive?
96
- raise Error::WebDriverError, "Unsuccessful command executed: #{command}\n#{result}#{stderr}"
111
+ (json_output&.fetch('logs') || []).each do |log|
112
+ level = log['level'].casecmp('info').zero? ? 'debug' : log['level'].downcase
113
+ WebDriver.logger.send(level, log['message'], id: :selenium_manager)
97
114
  end
98
115
 
99
- json_output['logs'].each do |log|
100
- WebDriver.logger.send(log['level'].downcase, log['message'])
116
+ if status.exitstatus.positive?
117
+ raise Error::WebDriverError, "Unsuccessful command executed: #{command}\n#{result}#{stderr}"
101
118
  end
102
119
 
103
120
  result
@@ -57,7 +57,7 @@ module Selenium
57
57
  end
58
58
  end
59
59
 
60
- attr_accessor :host, :executable_path, :port, :args
60
+ attr_accessor :host, :executable_path, :port, :log, :args
61
61
  alias extra_args args
62
62
 
63
63
  #
@@ -66,13 +66,21 @@ module Selenium
66
66
  # @api private
67
67
  #
68
68
 
69
- def initialize(path: nil, port: nil, args: nil)
69
+ def initialize(path: nil, port: nil, log: nil, args: nil)
70
70
  port ||= self.class::DEFAULT_PORT
71
71
  args ||= []
72
72
 
73
73
  @executable_path = path
74
74
  @host = Platform.localhost
75
75
  @port = Integer(port)
76
+ @log = case log
77
+ when :stdout
78
+ $stdout
79
+ when :stderr
80
+ $stderr
81
+ else
82
+ log
83
+ end
76
84
 
77
85
  @args = args.is_a?(Hash) ? extract_service_args(args) : args
78
86
 
@@ -41,6 +41,7 @@ module Selenium
41
41
  @host = Platform.localhost
42
42
  @port = config.port
43
43
  @extra_args = config.args
44
+ @io = config.log
44
45
  @shutdown_supported = config.shutdown_supported
45
46
 
46
47
  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
@@ -77,9 +78,10 @@ module Selenium
77
78
  private
78
79
 
79
80
  def build_process(*command)
80
- WebDriver.logger.debug("Executing Process #{command}")
81
+ WebDriver.logger.debug("Executing Process #{command}", id: :driver_service)
81
82
  @process = ChildProcess.build(*command)
82
- @process.io = WebDriver.logger.io if WebDriver.logger.debug?
83
+ @io ||= WebDriver.logger.io if WebDriver.logger.debug?
84
+ @process.io = @io if @io
83
85
 
84
86
  @process
85
87
  end
@@ -70,7 +70,7 @@ module Selenium
70
70
  @server.close_on_exec = true
71
71
  true
72
72
  rescue SocketError, Errno::EADDRINUSE, Errno::EBADF => e
73
- WebDriver.logger.debug("#{self}: #{e.message}")
73
+ WebDriver.logger.debug("#{self}: #{e.message}", id: :driver_service)
74
74
  false
75
75
  end
76
76
 
@@ -93,7 +93,7 @@ module Selenium
93
93
  true
94
94
  rescue *NOT_CONNECTED_ERRORS
95
95
  sock&.close
96
- WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
96
+ WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}", id: :driver_service)
97
97
  false
98
98
  end
99
99
  end
@@ -55,7 +55,7 @@ module Selenium
55
55
  def send_cmd(**payload)
56
56
  id = next_id
57
57
  data = payload.merge(id: id)
58
- WebDriver.logger.debug "WebSocket -> #{data}"[...MAX_LOG_MESSAGE_SIZE]
58
+ WebDriver.logger.debug "WebSocket -> #{data}"[...MAX_LOG_MESSAGE_SIZE], id: :bidi
59
59
  data = JSON.generate(data)
60
60
  out_frame = WebSocket::Frame::Outgoing::Client.new(version: ws.version, data: data, type: 'text')
61
61
  socket.write(out_frame.to_s)
@@ -112,7 +112,7 @@ module Selenium
112
112
 
113
113
  message = JSON.parse(message)
114
114
  messages[message['id']] = message
115
- WebDriver.logger.debug "WebSocket <- #{message}"[...MAX_LOG_MESSAGE_SIZE]
115
+ WebDriver.logger.debug "WebSocket <- #{message}"[...MAX_LOG_MESSAGE_SIZE], id: :bidi
116
116
 
117
117
  message
118
118
  end
@@ -60,7 +60,7 @@ module Selenium
60
60
  "#{namespace}::#{Object.const_get(methods_to_classes)[method]}"
61
61
  else
62
62
  # selenium-devtools 0.112 and older
63
- "#{namespace}::#{method.capitalize}}"
63
+ "#{namespace}::#{method.capitalize}"
64
64
  end
65
65
 
66
66
  return unless Object.const_defined?(desired_class)
@@ -26,6 +26,20 @@ module Selenium
26
26
  KEY = 'ms:edgeOptions'
27
27
  BROWSER = 'MicrosoftEdge'
28
28
 
29
+ #
30
+ # Changes the browser name enable webview2
31
+ # see: https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/webdriver
32
+ # Automation of WebView2 apps with Microsoft Edge WebDriver
33
+ #
34
+ # @example Enable webview2
35
+ # options = Selenium::WebDriver::Edge::Options.new
36
+ # options.webview2!
37
+ #
38
+
39
+ def webview2!
40
+ @options[:browser_name] = 'webview2'
41
+ end
42
+
29
43
  private
30
44
 
31
45
  def enable_logging(browser_options)
@@ -160,7 +160,7 @@ module Selenium
160
160
  destination = File.join(directory, 'extensions')
161
161
 
162
162
  @extensions.each do |name, extension|
163
- WebDriver.logger.debug({extenstion: name}.inspect)
163
+ WebDriver.logger.debug({extension: name}.inspect, id: :firefox_profile)
164
164
  extension.write_to(destination)
165
165
  end
166
166
  end
@@ -407,7 +407,8 @@ module Selenium
407
407
 
408
408
  def upload(local_file)
409
409
  unless File.file?(local_file)
410
- WebDriver.logger.debug("File detector only works with files. #{local_file.inspect} isn`t a file!")
410
+ WebDriver.logger.debug("File detector only works with files. #{local_file.inspect} isn`t a file!",
411
+ id: :file_detector)
411
412
  raise Error::WebDriverError, "You are trying to work with something that isn't a file."
412
413
  end
413
414
 
@@ -443,7 +444,7 @@ module Selenium
443
444
  end
444
445
 
445
446
  def element_attribute(element, name)
446
- WebDriver.logger.info "Using script for :getAttribute of #{name}"
447
+ WebDriver.logger.debug "Using script for :getAttribute of #{name}", id: :script
447
448
  execute_atom :getAttribute, element, name
448
449
  end
449
450
 
@@ -503,7 +504,7 @@ module Selenium
503
504
  end
504
505
 
505
506
  def element_displayed?(element)
506
- WebDriver.logger.info 'Using script for :isDisplayed'
507
+ WebDriver.logger.debug 'Using script for :isDisplayed', id: :script
507
508
  execute_atom :isDisplayed, element
508
509
  end
509
510
 
@@ -615,7 +616,7 @@ module Selenium
615
616
  raise ArgumentError, "#{opts.inspect} invalid for #{command.inspect}"
616
617
  end
617
618
 
618
- WebDriver.logger.info("-> #{verb.to_s.upcase} #{path}")
619
+ WebDriver.logger.debug("-> #{verb.to_s.upcase} #{path}", id: :command)
619
620
  http.call(verb, path, command_hash)['value']
620
621
  end
621
622
 
@@ -682,7 +683,7 @@ module Selenium
682
683
  [how, what]
683
684
  end
684
685
 
685
- ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/.freeze
686
+ ESCAPE_CSS_REGEXP = /(['"\\#.:;,!?+<>=~*^$|%&@`{}\-\[\]()])/
686
687
  UNICODE_CODE_POINT = 30
687
688
 
688
689
  # Escapes invalid characters in CSS selector.
@@ -49,8 +49,8 @@ module Selenium
49
49
  payload = JSON.generate(command_hash)
50
50
  headers['Content-Length'] = payload.bytesize.to_s if %i[post put].include?(verb)
51
51
 
52
- WebDriver.logger.info(" >>> #{url} | #{payload}")
53
- WebDriver.logger.debug(" > #{headers.inspect}")
52
+ WebDriver.logger.debug(" >>> #{url} | #{payload}", id: :command)
53
+ WebDriver.logger.debug(" > #{headers.inspect}", id: :header)
54
54
  elsif verb == :post
55
55
  payload = '{}'
56
56
  headers['Content-Length'] = '2'
@@ -75,7 +75,7 @@ module Selenium
75
75
  code = code.to_i
76
76
  body = body.to_s.strip
77
77
  content_type = content_type.to_s
78
- WebDriver.logger.info("<- #{body}")
78
+ WebDriver.logger.debug("<- #{body}", id: :command)
79
79
 
80
80
  if content_type.include? CONTENT_TYPE
81
81
  raise Error::WebDriverError, "empty body: #{content_type.inspect} (#{code})\n#{body}" if body.empty?
@@ -83,7 +83,7 @@ module Selenium
83
83
  c.max_redirects = MAX_REDIRECTS
84
84
  c.follow_location = true
85
85
  c.timeout = @timeout if @timeout
86
- c.verbose = WebDriver.logger.info?
86
+ c.verbose = WebDriver.logger.debug?
87
87
 
88
88
  c
89
89
  end
@@ -100,7 +100,7 @@ module Selenium
100
100
 
101
101
  request(:get, URI.parse(response['Location']), DEFAULT_HEADERS.dup, nil, redirects + 1)
102
102
  else
103
- WebDriver.logger.debug(" <<< #{response.instance_variable_get(:@header).inspect}")
103
+ WebDriver.logger.debug(" <<< #{response.instance_variable_get(:@header).inspect}", id: :header)
104
104
  create_response response.code, response.body, response.content_type
105
105
  end
106
106
  end
@@ -24,6 +24,16 @@ module Selenium
24
24
  DEFAULT_PORT = 7050
25
25
  EXECUTABLE = 'safaridriver'
26
26
  SHUTDOWN_SUPPORTED = false
27
+
28
+ def initialize(path: nil, port: nil, log: nil, args: nil)
29
+ raise Error::WebDriverError, 'Safari Service does not support setting log output' if log
30
+
31
+ super
32
+ end
33
+
34
+ def log=(*)
35
+ raise Error::WebDriverError, 'Safari Service does not support setting log output'
36
+ end
27
37
  end # Service
28
38
  end # Safari
29
39
  end # WebDriver
@@ -23,27 +23,27 @@ module Selenium
23
23
  class Color
24
24
  RGB_PATTERN = /^\s*rgb\(\s*(\d{1,3})\s*,
25
25
  \s*(\d{1,3})\s*,
26
- \s*(\d{1,3})\s*\)\s*$/x.freeze
26
+ \s*(\d{1,3})\s*\)\s*$/x
27
27
  RGB_PCT_PATTERN = /^\s*rgb\(\s*(\d{1,3}|\d{1,2}\.\d+)%\s*,
28
28
  \s*(\d{1,3}|\d{1,2}\.\d+)%\s*,
29
- \s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$/x.freeze
29
+ \s*(\d{1,3}|\d{1,2}\.\d+)%\s*\)\s*$/x
30
30
  RGBA_PATTERN = /^\s*rgba\(\s*(\d{1,3})\s*,
31
31
  \s*(\d{1,3})\s*,
32
32
  \s*(\d{1,3})\s*,
33
- \s*(0|1|0\.\d+)\s*\)\s*$/x.freeze
33
+ \s*(0|1|0\.\d+)\s*\)\s*$/x
34
34
  RGBA_PCT_PATTERN = /^\s*rgba\(\s*(\d{1,3}|\d{1,2}\.\d+)
35
35
  %\s*,\s*(\d{1,3}|\d{1,2}\.\d+)
36
36
  %\s*,\s*(\d{1,3}|\d{1,2}\.\d+)
37
- %\s*,\s*(0|1|0\.\d+)\s*\)\s*$/x.freeze
38
- HEX_PATTERN = /#(\h{2})(\h{2})(\h{2})/.freeze
39
- HEX3_PATTERN = /#(\h)(\h)(\h)/.freeze
37
+ %\s*,\s*(0|1|0\.\d+)\s*\)\s*$/x
38
+ HEX_PATTERN = /#(\h{2})(\h{2})(\h{2})/
39
+ HEX3_PATTERN = /#(\h)(\h)(\h)/
40
40
  HSL_PATTERN = /^\s*hsl\(\s*(\d{1,3})\s*,
41
41
  \s*(\d{1,3})%\s*,
42
- \s*(\d{1,3})%\s*\)\s*$/x.freeze
42
+ \s*(\d{1,3})%\s*\)\s*$/x
43
43
  HSLA_PATTERN = /^\s*hsla\(\s*(\d{1,3})\s*,
44
44
  \s*(\d{1,3})%\s*,
45
45
  \s*(\d{1,3})%\s*,
46
- \s*(0|1|0\.\d+)\s*\)\s*$/x.freeze
46
+ \s*(0|1|0\.\d+)\s*\)\s*$/x
47
47
 
48
48
  attr_reader :red, :green, :blue, :alpha
49
49
 
@@ -19,6 +19,6 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- VERSION = '4.9.0'
22
+ VERSION = '4.10.0'
23
23
  end # WebDriver
24
24
  end # Selenium
@@ -95,7 +95,8 @@ module Selenium
95
95
  #
96
96
 
97
97
  def self.logger(**opts)
98
- @logger ||= WebDriver::Logger.new('Selenium', **opts)
98
+ level = $DEBUG || ENV.key?('DEBUG') ? :debug : :info
99
+ @logger ||= WebDriver::Logger.new('Selenium', default_level: level, **opts)
99
100
  end
100
101
  end # WebDriver
101
102
  end # Selenium
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
30
30
  }
31
31
 
32
32
  s.required_rubygems_version = Gem::Requirement.new('> 1.3.1') if s.respond_to? :required_rubygems_version=
33
- s.required_ruby_version = Gem::Requirement.new('>= 2.7')
33
+ s.required_ruby_version = Gem::Requirement.new('>= 3.0')
34
34
 
35
35
  s.files = [
36
36
  'CHANGES',
@@ -53,8 +53,8 @@ Gem::Specification.new do |s|
53
53
  s.add_runtime_dependency 'rubyzip', ['>= 1.2.2', '< 3.0']
54
54
  s.add_runtime_dependency 'websocket', ['~> 1.0']
55
55
 
56
- s.add_development_dependency 'pry', ['~> 0.14']
57
56
  s.add_development_dependency 'rack', ['~> 2.0']
57
+ s.add_development_dependency 'rake', ['~> 13.0']
58
58
  s.add_development_dependency 'rspec', ['~> 3.0']
59
59
  s.add_development_dependency 'rubocop', ['~> 1.42']
60
60
  s.add_development_dependency 'rubocop-performance', ['~> 1.15']
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: selenium-webdriver
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.9.0
4
+ version: 4.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Rodionov
8
8
  - Titus Fortner
9
9
  - Thomas Walpole
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-04-21 00:00:00.000000000 Z
13
+ date: 2023-06-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rexml
@@ -67,33 +67,33 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: pry
70
+ name: rack
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.14'
75
+ version: '2.0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0.14'
82
+ version: '2.0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: rack
84
+ name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '2.0'
89
+ version: '13.0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '2.0'
96
+ version: '13.0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rspec
99
99
  requirement: !ruby/object:Gem::Requirement
@@ -389,7 +389,7 @@ metadata:
389
389
  github_repo: ssh://github.com/SeleniumHQ/selenium
390
390
  source_code_uri: https://github.com/SeleniumHQ/selenium/tree/trunk/rb
391
391
  rubygems_mfa_required: 'true'
392
- post_install_message:
392
+ post_install_message:
393
393
  rdoc_options: []
394
394
  require_paths:
395
395
  - lib
@@ -397,15 +397,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
397
397
  requirements:
398
398
  - - ">="
399
399
  - !ruby/object:Gem::Version
400
- version: '2.7'
400
+ version: '3.0'
401
401
  required_rubygems_version: !ruby/object:Gem::Requirement
402
402
  requirements:
403
403
  - - ">"
404
404
  - !ruby/object:Gem::Version
405
405
  version: 1.3.1
406
406
  requirements: []
407
- rubygems_version: 3.1.6
408
- signing_key:
407
+ rubygems_version: 3.2.33
408
+ signing_key:
409
409
  specification_version: 4
410
410
  summary: Selenium is a browser automation tool for automated testing of webapps and
411
411
  more