selenium-webdriver 4.9.0 → 4.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +40 -0
  3. data/Gemfile +2 -0
  4. data/README.md +2 -2
  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 +4 -16
  9. data/lib/selenium/webdriver/atoms/findElements.js +3 -4
  10. data/lib/selenium/webdriver/chrome/service.rb +1 -3
  11. data/lib/selenium/webdriver/chromium/options.rb +0 -18
  12. data/lib/selenium/webdriver/chromium.rb +0 -1
  13. data/lib/selenium/webdriver/common/action_builder.rb +0 -8
  14. data/lib/selenium/webdriver/common/child_process.rb +11 -11
  15. data/lib/selenium/webdriver/common/driver_finder.rb +10 -8
  16. data/lib/selenium/webdriver/common/error.rb +28 -3
  17. data/lib/selenium/webdriver/common/logger.rb +87 -30
  18. data/lib/selenium/webdriver/common/options.rb +3 -22
  19. data/lib/selenium/webdriver/common/platform.rb +0 -49
  20. data/lib/selenium/webdriver/common/port_prober.rb +1 -1
  21. data/lib/selenium/webdriver/common/proxy.rb +1 -1
  22. data/lib/selenium/webdriver/common/selenium_manager.rb +50 -27
  23. data/lib/selenium/webdriver/common/service.rb +11 -13
  24. data/lib/selenium/webdriver/common/service_manager.rb +4 -2
  25. data/lib/selenium/webdriver/common/socket_lock.rb +1 -1
  26. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  27. data/lib/selenium/webdriver/common/websocket_connection.rb +3 -3
  28. data/lib/selenium/webdriver/devtools.rb +1 -1
  29. data/lib/selenium/webdriver/edge/options.rb +14 -0
  30. data/lib/selenium/webdriver/edge/service.rb +1 -3
  31. data/lib/selenium/webdriver/firefox/options.rb +0 -15
  32. data/lib/selenium/webdriver/firefox/profile.rb +1 -1
  33. data/lib/selenium/webdriver/firefox/service.rb +0 -12
  34. data/lib/selenium/webdriver/ie/options.rb +2 -1
  35. data/lib/selenium/webdriver/ie/service.rb +0 -16
  36. data/lib/selenium/webdriver/remote/bridge.rb +6 -5
  37. data/lib/selenium/webdriver/remote/capabilities.rb +0 -72
  38. data/lib/selenium/webdriver/remote/http/common.rb +3 -3
  39. data/lib/selenium/webdriver/remote/http/curb.rb +1 -1
  40. data/lib/selenium/webdriver/remote/http/default.rb +2 -3
  41. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  42. data/lib/selenium/webdriver/safari/service.rb +10 -0
  43. data/lib/selenium/webdriver/support/color.rb +8 -8
  44. data/lib/selenium/webdriver/version.rb +1 -1
  45. data/lib/selenium/webdriver.rb +2 -1
  46. data/selenium-webdriver.gemspec +2 -2
  47. metadata +13 -14
  48. data/lib/selenium/webdriver/chromium/service.rb +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1ae360596be57c29db02808a7dae16c36062801e7639e83b366a54cdba5e3b2
4
- data.tar.gz: f31169f7cfec055abb7a2f3595eee8e453acf316651a829af5f254a0f824cf9e
3
+ metadata.gz: 55c2b164be56b90064957852c6b1f890f9cda063d5c0ef164752b7c67f6e40bb
4
+ data.tar.gz: 778d0c6d2450a3d178d709762c76b9ef2c24832131d4487f6c84b5789a32b1de
5
5
  SHA512:
6
- metadata.gz: 675dad14a433939c81dabbb0276b1c5a97d95f0b1451ca48aa0e908c2cc0658f1d90e3970be4e3f62e65ff5eaef5cf391b5d646f50413ca46ea2f24de821fb5a
7
- data.tar.gz: dd9d26b855e7b1f01f667d113181f6e7b35367ee74459b693a3c5872cc92a9e58f9d2d849de3aaff9738e3e77cb3f3117617219b4f76e2fda2f66bc75279ee8d
6
+ metadata.gz: 6777b04b259f2e7be27d7c2635f77b0e9006464f931e1e79a1e10f517474b71344534a8b02ba84445801581f4c50cb79901d15ef8e74133c08357625e5ad9de6
7
+ data.tar.gz: 5f1e3af40a4bbcc3e4e77407321d64b1e6920ca91fcf7605bce780d42138fd587bfc951563205d8cf6e4b63952e7e4e35dd52aba496fcb1e468e6a086c81c92d
data/CHANGES CHANGED
@@ -1,3 +1,43 @@
1
+ 4.11.0 (2023-07-31)
2
+ =========================
3
+ Ruby:
4
+ * Made network interception threads fail silently (#12226)
5
+ * Have Selenium Manager binary locate drivers on PATH (#12345)
6
+ * Add browser output from selenium manager to options (#12398)
7
+ * Remove deprecated code (#12417)
8
+ BiDi:
9
+ * Released selenium-devtools 0.115.0 (supports CDP v85, v113, v114, v115)
10
+ Edge:
11
+ * Adding ignore process match for IE Mode across bindings (#12279)
12
+
13
+ 4.10.0 (2023-06-07)
14
+ =========================
15
+ Ruby:
16
+ * Implement proxy support for Selenium Manager
17
+ * Prevent setting driver log level in Safari
18
+ * Change all Selenium Manager logging to :debug (#12145)
19
+ * Error messages include links to documentation
20
+ * Add custom error class for driver location and improve error logic
21
+
22
+ BiDi:
23
+ * Released selenium-devtools 0.114.0 (supports CDP v85, v112, v113, v114)
24
+
25
+ Edge:
26
+ * Add support for webview2
27
+
28
+ 4.9.1 (2023-05-08)
29
+ =========================
30
+ Ruby:
31
+ * Allow users to specify driver process output in Service class (#11964)
32
+ * Updated minimum required Ruby version to 3.0
33
+ * Selenium Logger defaults to :info and all debugging is now logged as :debug (#11967)
34
+ * Every logging entry can be ignored based on ID, not just warnings
35
+ * Logging entries can be filtered to allow or ignore specific IDs
36
+
37
+ BiDi:
38
+ * Fix bug with loading devtools (#11931) (thanks Boris Petrov!)
39
+ * Released selenium-devtools 0.113.0 (supports CDP v85, v111, v112, v113)
40
+
1
41
  4.9.0 (2023-04-21)
2
42
  =========================
3
43
  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
 
@@ -15,7 +15,7 @@ This gem provides Ruby bindings for Selenium and supports MRI >= 2.6
15
15
 
16
16
  ## License
17
17
 
18
- Copyright 2009-2021 Software Freedom Conservancy
18
+ Copyright 2009-2023 Software Freedom Conservancy
19
19
 
20
20
  Licensed to the Software Freedom Conservancy (SFC) under one
21
21
  or more contributor license agreements. See the NOTICE file
Binary file
Binary file
Binary file
@@ -18,6 +18,7 @@
18
18
  # under the License.
19
19
 
20
20
  require 'selenium/webdriver/common/child_process'
21
+ require 'selenium/webdriver/common/port_prober'
21
22
  require 'selenium/webdriver/common/socket_poller'
22
23
  require 'net/http'
23
24
 
@@ -165,7 +166,7 @@ module Selenium
165
166
  # :standalone, #hub, #node
166
167
  #
167
168
 
168
- attr_accessor :role, :port, :timeout, :background, :log
169
+ attr_accessor :role, :host, :port, :timeout, :background, :log
169
170
 
170
171
  #
171
172
  # @param [String] jar Path to the server jar.
@@ -185,7 +186,7 @@ module Selenium
185
186
  @jar = jar
186
187
  @host = '127.0.0.1'
187
188
  @role = opts.fetch(:role, 'standalone')
188
- @port = opts.fetch(:port, 4444)
189
+ @port = opts.fetch(:port, WebDriver::PortProber.above(4444))
189
190
  @timeout = opts.fetch(:timeout, 30)
190
191
  @background = opts.fetch(:background, false)
191
192
  @additional_args = opts.fetch(:args, [])
@@ -207,12 +208,6 @@ module Selenium
207
208
  end
208
209
 
209
210
  def stop
210
- begin
211
- Net::HTTP.get(@host, '/selenium-server/driver/?cmd=shutDownSeleniumServer', @port)
212
- rescue Errno::ECONNREFUSED
213
- nil
214
- end
215
-
216
211
  stop_process if @process
217
212
  poll_for_shutdown
218
213
 
@@ -234,13 +229,7 @@ module Selenium
234
229
  private
235
230
 
236
231
  def stop_process
237
- return unless @process.alive?
238
-
239
- begin
240
- @process.poll_for_exit(5)
241
- rescue WebDriver::ChildProcess::TimeoutError
242
- @process.stop
243
- end
232
+ @process.stop
244
233
  rescue Errno::ECHILD
245
234
  # already dead
246
235
  ensure
@@ -254,7 +243,6 @@ module Selenium
254
243
  args = ['-jar', @jar, @role, '--port', @port.to_s]
255
244
  server_command = ['java'] + properties + args + @additional_args
256
245
  cp = WebDriver::ChildProcess.build(*server_command)
257
- WebDriver.logger.debug("Executing Process #{server_command}")
258
246
 
259
247
  if @log.is_a?(String)
260
248
  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);}
@@ -17,12 +17,10 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/chromium/service'
21
-
22
20
  module Selenium
23
21
  module WebDriver
24
22
  module Chrome
25
- class Service < Chromium::Service
23
+ class Service < WebDriver::Service
26
24
  DEFAULT_PORT = 9515
27
25
  EXECUTABLE = 'chromedriver'
28
26
  SHUTDOWN_SUPPORTED = true
@@ -159,24 +159,6 @@ module Selenium
159
159
  @options[:prefs][name] = value
160
160
  end
161
161
 
162
- #
163
- # Run Chrome in headless mode.
164
- # Old headless uses a non-production browser and is set with `--headless`
165
- # Native headless from v86 - v108 is set with `--headless=chrome`
166
- # Native headless from v109+ is set with `--headless=new`
167
- #
168
- # @example Enable headless mode
169
- # options = Selenium::WebDriver::Chrome::Options.new
170
- # options.headless!
171
- #
172
-
173
- def headless!
174
- WebDriver.logger.deprecate('`Options#headless!`',
175
- "`Options#add_argument('--headless=new')`",
176
- id: :headless)
177
- add_argument '--headless'
178
- end
179
-
180
162
  #
181
163
  # Add emulation device information
182
164
  #
@@ -26,7 +26,6 @@ module Selenium
26
26
  autoload :Driver, 'selenium/webdriver/chromium/driver'
27
27
  autoload :Profile, 'selenium/webdriver/chromium/profile'
28
28
  autoload :Options, 'selenium/webdriver/chromium/options'
29
- autoload :Service, 'selenium/webdriver/chromium/service'
30
29
  end # Chromium
31
30
  end # WebDriver
32
31
  end # Selenium
@@ -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?
@@ -81,20 +81,20 @@ module Selenium
81
81
  end
82
82
 
83
83
  def exited?
84
- return unless @pid
84
+ return false 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
- return if @status.nil?
88
+ return false 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
@@ -23,19 +23,21 @@ module Selenium
23
23
  def self.path(options, klass)
24
24
  path = klass.driver_path
25
25
  path = path.call if path.is_a?(Proc)
26
- path ||= Platform.find_binary(klass::EXECUTABLE)
27
26
 
28
27
  path ||= begin
29
- SeleniumManager.driver_path(options)
28
+ SeleniumManager.driver_path(options) unless options.is_a?(Remote::Capabilities)
30
29
  rescue StandardError => e
31
- WebDriver.logger.warn("Unable obtain driver using Selenium Manager\n #{e.message}")
32
- nil
30
+ raise Error::NoSuchDriverError, "Unable to obtain #{klass::EXECUTABLE} using Selenium Manager; #{e.message}"
31
+ end
32
+
33
+ begin
34
+ Platform.assert_executable(path)
35
+ rescue TypeError
36
+ raise Error::NoSuchDriverError, "Unable to locate or obtain #{klass::EXECUTABLE}"
37
+ rescue Error::WebDriverError => e
38
+ raise Error::NoSuchDriverError, "#{klass::EXECUTABLE} located, but: #{e.message}"
33
39
  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
40
 
38
- Platform.assert_executable path
39
41
  path
40
42
  end
41
43
  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
@@ -86,12 +86,6 @@ module Selenium
86
86
 
87
87
  def add_option(name, value = nil)
88
88
  name, value = name.first if value.nil? && name.is_a?(Hash)
89
-
90
- unless name.to_s.include?(':')
91
- WebDriver.logger.deprecate('Options#add_option for w3c or browser specific capabilities',
92
- 'applicable attribute accessors or pass into constructor',
93
- id: :add_option)
94
- end
95
89
  @options[name] = value
96
90
  end
97
91
 
@@ -113,24 +107,11 @@ module Selenium
113
107
  w3c_options = process_w3c_options(options)
114
108
 
115
109
  browser_options = self.class::CAPABILITIES.each_with_object({}) do |(capability_alias, capability_name), hash|
116
- from_name = options.delete(capability_name)
117
- from_alias = options.delete(capability_alias)
118
- capability_value = if !from_name.nil? && capability_alias != capability_name
119
- WebDriver.logger.deprecate("#{capability_name} as option",
120
- capability_alias.to_s, id: :option_symbols)
121
- from_name
122
- elsif !from_alias.nil?
123
- from_alias
124
- end
125
-
110
+ capability_value = options.delete(capability_alias)
126
111
  hash[capability_name] = capability_value unless capability_value.nil?
127
112
  end
128
113
 
129
- unless options.empty?
130
- msg = 'These options are not w3c compliant and will result in failures in a future release'
131
- WebDriver.logger.warn("#{msg}: #{options}")
132
- browser_options.merge!(options)
133
- end
114
+ raise Error::WebDriverError, "These options are not w3c compliant: #{options}" unless options.empty?
134
115
 
135
116
  browser_options = {self.class::KEY => browser_options} if defined?(self.class::KEY)
136
117
 
@@ -145,7 +126,7 @@ module Selenium
145
126
  end
146
127
 
147
128
  def process_w3c_options(options)
148
- w3c_options = options.select { |key, _val| w3c?(key) }
129
+ w3c_options = options.select { |key, val| w3c?(key) && !val.nil? }
149
130
  w3c_options[:unhandled_prompt_behavior] &&= w3c_options[:unhandled_prompt_behavior]&.to_s&.tr('_', ' ')
150
131
  options.delete_if { |key, _val| w3c?(key) }
151
132
  w3c_options