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.
- checksums.yaml +4 -4
- data/CHANGES +40 -0
- data/Gemfile +2 -0
- data/README.md +2 -2
- data/bin/linux/selenium-manager +0 -0
- data/bin/macos/selenium-manager +0 -0
- data/bin/windows/selenium-manager.exe +0 -0
- data/lib/selenium/server.rb +4 -16
- data/lib/selenium/webdriver/atoms/findElements.js +3 -4
- data/lib/selenium/webdriver/chrome/service.rb +1 -3
- data/lib/selenium/webdriver/chromium/options.rb +0 -18
- data/lib/selenium/webdriver/chromium.rb +0 -1
- data/lib/selenium/webdriver/common/action_builder.rb +0 -8
- data/lib/selenium/webdriver/common/child_process.rb +11 -11
- data/lib/selenium/webdriver/common/driver_finder.rb +10 -8
- data/lib/selenium/webdriver/common/error.rb +28 -3
- data/lib/selenium/webdriver/common/logger.rb +87 -30
- data/lib/selenium/webdriver/common/options.rb +3 -22
- data/lib/selenium/webdriver/common/platform.rb +0 -49
- data/lib/selenium/webdriver/common/port_prober.rb +1 -1
- data/lib/selenium/webdriver/common/proxy.rb +1 -1
- data/lib/selenium/webdriver/common/selenium_manager.rb +50 -27
- data/lib/selenium/webdriver/common/service.rb +11 -13
- data/lib/selenium/webdriver/common/service_manager.rb +4 -2
- data/lib/selenium/webdriver/common/socket_lock.rb +1 -1
- data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
- data/lib/selenium/webdriver/common/websocket_connection.rb +3 -3
- data/lib/selenium/webdriver/devtools.rb +1 -1
- data/lib/selenium/webdriver/edge/options.rb +14 -0
- data/lib/selenium/webdriver/edge/service.rb +1 -3
- data/lib/selenium/webdriver/firefox/options.rb +0 -15
- data/lib/selenium/webdriver/firefox/profile.rb +1 -1
- data/lib/selenium/webdriver/firefox/service.rb +0 -12
- data/lib/selenium/webdriver/ie/options.rb +2 -1
- data/lib/selenium/webdriver/ie/service.rb +0 -16
- data/lib/selenium/webdriver/remote/bridge.rb +6 -5
- data/lib/selenium/webdriver/remote/capabilities.rb +0 -72
- data/lib/selenium/webdriver/remote/http/common.rb +3 -3
- data/lib/selenium/webdriver/remote/http/curb.rb +1 -1
- data/lib/selenium/webdriver/remote/http/default.rb +2 -3
- data/lib/selenium/webdriver/remote/server_error.rb +1 -1
- data/lib/selenium/webdriver/safari/service.rb +10 -0
- data/lib/selenium/webdriver/support/color.rb +8 -8
- data/lib/selenium/webdriver/version.rb +1 -1
- data/lib/selenium/webdriver.rb +2 -1
- data/selenium-webdriver.gemspec +2 -2
- metadata +13 -14
- data/lib/selenium/webdriver/chromium/service.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55c2b164be56b90064957852c6b1f890f9cda063d5c0ef164752b7c67f6e40bb
|
4
|
+
data.tar.gz: 778d0c6d2450a3d178d709762c76b9ef2c24832131d4487f6c84b5789a32b1de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
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 >=
|
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-
|
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
|
data/bin/linux/selenium-manager
CHANGED
Binary file
|
data/bin/macos/selenium-manager
CHANGED
Binary file
|
Binary file
|
data/lib/selenium/server.rb
CHANGED
@@ -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
|
-
|
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=
|
117
|
-
|
118
|
-
|
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 <
|
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
|
-
|
32
|
-
|
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
|
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
|
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
|
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
|
42
|
-
:info
|
41
|
+
:debug?,
|
42
|
+
:info?,
|
43
43
|
:warn?,
|
44
|
-
:error
|
44
|
+
:error?,
|
45
45
|
:fatal, :fatal?,
|
46
|
-
: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
|
-
|
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]
|
95
|
+
# @param [Array, Symbol] ids
|
85
96
|
#
|
86
|
-
def ignore(
|
87
|
-
Array(
|
97
|
+
def ignore(*ids)
|
98
|
+
@ignored += Array(ids).flatten
|
88
99
|
end
|
89
100
|
|
90
101
|
#
|
91
|
-
#
|
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
|
98
|
-
|
99
|
-
|
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
|
-
|
106
|
-
|
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
|
-
|
109
|
-
|
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
|
-
|
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)
|
166
|
+
return if @ignored.include?(:deprecations)
|
126
167
|
|
127
|
-
|
168
|
+
id << :deprecations if @allowed.include?(:deprecations)
|
128
169
|
|
129
|
-
message = +"[DEPRECATION] #{
|
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 =
|
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
|
154
|
-
|
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
|
-
|
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,
|
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
|