selenium-webdriver 4.0.0.alpha3 → 4.0.0.alpha4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGES +50 -1
- data/lib/selenium/server.rb +1 -1
- data/lib/selenium/webdriver.rb +2 -0
- data/lib/selenium/webdriver/atoms/findElements.js +122 -0
- data/lib/selenium/webdriver/atoms/getAttribute.js +84 -7
- data/lib/selenium/webdriver/atoms/isDisplayed.js +75 -77
- data/lib/selenium/webdriver/chrome.rb +4 -2
- data/lib/selenium/webdriver/chrome/driver.rb +1 -16
- data/lib/selenium/webdriver/chrome/options.rb +1 -1
- data/lib/selenium/webdriver/chrome/service.rb +0 -4
- data/lib/selenium/webdriver/common.rb +1 -0
- data/lib/selenium/webdriver/common/driver.rb +25 -5
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +38 -0
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +2 -1
- data/lib/selenium/webdriver/common/logger.rb +47 -15
- data/lib/selenium/webdriver/common/options.rb +2 -1
- data/lib/selenium/webdriver/common/platform.rb +3 -0
- data/lib/selenium/webdriver/common/port_prober.rb +2 -2
- data/lib/selenium/webdriver/common/proxy.rb +0 -0
- data/lib/selenium/webdriver/common/search_context.rb +3 -2
- data/lib/selenium/webdriver/common/service.rb +0 -13
- data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
- data/lib/selenium/webdriver/common/wait.rb +1 -1
- data/lib/selenium/webdriver/edge.rb +4 -2
- data/lib/selenium/webdriver/edge_chrome/driver.rb +1 -1
- data/lib/selenium/webdriver/edge_chrome/service.rb +0 -4
- data/lib/selenium/webdriver/edge_html/driver.rb +1 -15
- data/lib/selenium/webdriver/edge_html/options.rb +1 -1
- data/lib/selenium/webdriver/edge_html/service.rb +1 -5
- data/lib/selenium/webdriver/firefox.rb +10 -4
- data/lib/selenium/webdriver/firefox/driver.rb +0 -16
- data/lib/selenium/webdriver/firefox/options.rb +4 -1
- data/lib/selenium/webdriver/firefox/profile.rb +4 -77
- data/lib/selenium/webdriver/firefox/service.rb +0 -4
- data/lib/selenium/webdriver/ie.rb +4 -2
- data/lib/selenium/webdriver/ie/driver.rb +0 -15
- data/lib/selenium/webdriver/ie/service.rb +5 -9
- data/lib/selenium/webdriver/remote/bridge.rb +31 -29
- data/lib/selenium/webdriver/remote/capabilities.rb +1 -0
- data/lib/selenium/webdriver/remote/driver.rb +6 -12
- data/lib/selenium/webdriver/remote/http/default.rb +3 -3
- data/lib/selenium/webdriver/safari.rb +4 -2
- data/lib/selenium/webdriver/safari/driver.rb +0 -16
- data/lib/selenium/webdriver/safari/service.rb +0 -4
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
- data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
- data/lib/selenium/webdriver/version.rb +1 -1
- data/selenium-webdriver.gemspec +4 -3
- metadata +24 -15
- data/lib/selenium/webdriver/firefox/binary.rb +0 -110
- data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
@@ -30,13 +30,15 @@ module Selenium
|
|
30
30
|
|
31
31
|
def self.driver_path=(path)
|
32
32
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome#driver_path=',
|
33
|
-
'Selenium::WebDriver::Chrome::Service#driver_path='
|
33
|
+
'Selenium::WebDriver::Chrome::Service#driver_path=',
|
34
|
+
id: :driver_path
|
34
35
|
Selenium::WebDriver::Chrome::Service.driver_path = path
|
35
36
|
end
|
36
37
|
|
37
38
|
def self.driver_path
|
38
39
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Chrome#driver_path',
|
39
|
-
'Selenium::WebDriver::Chrome::Service#driver_path'
|
40
|
+
'Selenium::WebDriver::Chrome::Service#driver_path',
|
41
|
+
id: :driver_path
|
40
42
|
Selenium::WebDriver::Chrome::Service.driver_path
|
41
43
|
end
|
42
44
|
|
@@ -32,22 +32,7 @@ module Selenium
|
|
32
32
|
include DriverExtensions::HasLocation
|
33
33
|
include DriverExtensions::TakesScreenshot
|
34
34
|
include DriverExtensions::DownloadsFiles
|
35
|
-
|
36
|
-
def initialize(opts = {})
|
37
|
-
opts[:desired_capabilities] ||= Remote::Capabilities.send(browser)
|
38
|
-
|
39
|
-
opts[:url] ||= service_url(opts)
|
40
|
-
|
41
|
-
listener = opts.delete(:listener)
|
42
|
-
desired_capabilities = opts.delete(:desired_capabilities)
|
43
|
-
options = opts.delete(:options)
|
44
|
-
|
45
|
-
@bridge = Remote::Bridge.new(opts)
|
46
|
-
@bridge.extend Bridge
|
47
|
-
@bridge.create_session(desired_capabilities, options)
|
48
|
-
|
49
|
-
super(@bridge, listener: listener)
|
50
|
-
end
|
35
|
+
include DriverExtensions::HasDevTools
|
51
36
|
|
52
37
|
def browser
|
53
38
|
:chrome
|
@@ -169,7 +169,7 @@ module Selenium
|
|
169
169
|
# options = Selenium::WebDriver::Chrome::Options.new
|
170
170
|
# options.add_emulation(device_metrics: {width: 400, height: 800, pixelRatio: 1, touch: true})
|
171
171
|
#
|
172
|
-
# @param [Hash] opts the pre-defined options for adding
|
172
|
+
# @param [Hash] opts the pre-defined options for adding mobile emulation values
|
173
173
|
# @option opts [String] :device_name A valid device name from the Chrome DevTools Emulation panel
|
174
174
|
# @option opts [Hash] :device_metrics Hash containing width, height, pixelRatio, touch
|
175
175
|
# @option opts [String] :user_agent Full user agent
|
@@ -62,6 +62,7 @@ require 'selenium/webdriver/common/driver_extensions/has_permissions'
|
|
62
62
|
require 'selenium/webdriver/common/driver_extensions/has_debugger'
|
63
63
|
require 'selenium/webdriver/common/driver_extensions/uploads_files'
|
64
64
|
require 'selenium/webdriver/common/driver_extensions/has_addons'
|
65
|
+
require 'selenium/webdriver/common/driver_extensions/has_devtools'
|
65
66
|
require 'selenium/webdriver/common/keys'
|
66
67
|
require 'selenium/webdriver/common/profile_helper'
|
67
68
|
require 'selenium/webdriver/common/options'
|
@@ -71,10 +71,10 @@ module Selenium
|
|
71
71
|
# @api private
|
72
72
|
#
|
73
73
|
|
74
|
-
def initialize(bridge, listener: nil)
|
74
|
+
def initialize(bridge: nil, listener: nil, **opts)
|
75
75
|
@service = nil
|
76
|
-
|
77
|
-
@bridge = Support::EventFiringBridge.new(bridge, listener)
|
76
|
+
bridge ||= create_bridge(opts)
|
77
|
+
@bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
|
78
78
|
end
|
79
79
|
|
80
80
|
def inspect
|
@@ -276,7 +276,7 @@ module Selenium
|
|
276
276
|
end
|
277
277
|
|
278
278
|
def browser
|
279
|
-
bridge
|
279
|
+
bridge&.browser
|
280
280
|
end
|
281
281
|
|
282
282
|
def capabilities
|
@@ -294,12 +294,32 @@ module Selenium
|
|
294
294
|
|
295
295
|
attr_reader :bridge
|
296
296
|
|
297
|
+
def create_bridge(**opts)
|
298
|
+
opts[:url] ||= service_url(opts)
|
299
|
+
|
300
|
+
desired_capabilities = opts.delete(:desired_capabilities) || Remote::Capabilities.send(browser || :new)
|
301
|
+
options = opts.delete(:options)
|
302
|
+
|
303
|
+
bridge = Remote::Bridge.new(http_client: opts.delete(:http_client), url: opts.delete(:url))
|
304
|
+
raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
|
305
|
+
|
306
|
+
namespacing = self.class.to_s.split('::')
|
307
|
+
|
308
|
+
if Object.const_defined?("#{namespacing[0..-2].join('::')}::Bridge") && !namespacing.include?('Remote')
|
309
|
+
bridge.extend Object.const_get("#{namespacing[0, namespacing.length - 1].join('::')}::Bridge")
|
310
|
+
end
|
311
|
+
|
312
|
+
bridge.create_session(desired_capabilities, options)
|
313
|
+
bridge
|
314
|
+
end
|
315
|
+
|
297
316
|
def service_url(opts)
|
298
317
|
@service = opts.delete(:service)
|
299
318
|
%i[driver_opts driver_path port].each do |key|
|
300
319
|
next unless opts.key? key
|
301
320
|
|
302
|
-
WebDriver.logger.deprecate(":#{key}", ':service with an instance of Selenium::WebDriver::Service'
|
321
|
+
WebDriver.logger.deprecate(":#{key}", ':service with an instance of Selenium::WebDriver::Service',
|
322
|
+
id: "service_#{key}".to_sym)
|
303
323
|
end
|
304
324
|
@service ||= Service.send(browser,
|
305
325
|
args: opts.delete(:driver_opts),
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Licensed to the Software Freedom Conservancy (SFC) under one
|
4
|
+
# or more contributor license agreements. See the NOTICE file
|
5
|
+
# distributed with this work for additional information
|
6
|
+
# regarding copyright ownership. The SFC licenses this file
|
7
|
+
# to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance
|
9
|
+
# with the License. You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing,
|
14
|
+
# software distributed under the License is distributed on an
|
15
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
16
|
+
# KIND, either express or implied. See the License for the
|
17
|
+
# specific language governing permissions and limitations
|
18
|
+
# under the License.
|
19
|
+
|
20
|
+
module Selenium
|
21
|
+
module WebDriver
|
22
|
+
module DriverExtensions
|
23
|
+
module HasDevTools
|
24
|
+
|
25
|
+
#
|
26
|
+
# Retrieves connection to DevTools.
|
27
|
+
#
|
28
|
+
# @return [DevTools]
|
29
|
+
#
|
30
|
+
|
31
|
+
def devtools
|
32
|
+
@devtools ||= DevTools.new(capabilities['goog:chromeOptions']['debuggerAddress'])
|
33
|
+
end
|
34
|
+
|
35
|
+
end # HasDevTools
|
36
|
+
end # DriverExtensions
|
37
|
+
end # WebDriver
|
38
|
+
end # Selenium
|
@@ -35,7 +35,8 @@ module Selenium
|
|
35
35
|
extension = File.extname(png_path).downcase
|
36
36
|
if extension != '.png'
|
37
37
|
WebDriver.logger.warn "name used for saved screenshot does not match file type. "\
|
38
|
-
"It should end with .png extension"
|
38
|
+
"It should end with .png extension",
|
39
|
+
id: :screenshot
|
39
40
|
end
|
40
41
|
File.open(png_path, 'wb') { |f| f << screenshot_as(:png) }
|
41
42
|
end
|
@@ -45,8 +45,12 @@ module Selenium
|
|
45
45
|
:fatal, :fatal?,
|
46
46
|
:level, :level=
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
#
|
49
|
+
# @param [String] progname Allow child projects to use Selenium's Logger pattern
|
50
|
+
#
|
51
|
+
def initialize(progname = 'Selenium')
|
52
|
+
@logger = create_logger(progname)
|
53
|
+
@ignored = []
|
50
54
|
end
|
51
55
|
|
52
56
|
#
|
@@ -73,28 +77,60 @@ module Selenium
|
|
73
77
|
@logger.instance_variable_get(:@logdev).dev
|
74
78
|
end
|
75
79
|
|
80
|
+
#
|
81
|
+
# Will not log the provided ID.
|
82
|
+
#
|
83
|
+
# @param [Array, Symbol] id
|
84
|
+
#
|
85
|
+
def ignore(id)
|
86
|
+
Array(id).each { |ignore| @ignored << ignore }
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Overrides default #warn to skip ignored messages by provided id
|
91
|
+
#
|
92
|
+
# @param [String] message
|
93
|
+
# @param [Symbol, Array<Sybmol>] id
|
94
|
+
# @yield see #deprecate
|
95
|
+
#
|
96
|
+
def warn(message, id: [])
|
97
|
+
id = Array(id)
|
98
|
+
return if (@ignored & id).any?
|
99
|
+
|
100
|
+
msg = id.empty? ? message : "[#{id.map(&:inspect).join(', ')}] #{message} "
|
101
|
+
msg += " #{yield}" if block_given?
|
102
|
+
|
103
|
+
@logger.warn { msg }
|
104
|
+
end
|
105
|
+
|
76
106
|
#
|
77
107
|
# Marks code as deprecated with/without replacement.
|
78
108
|
#
|
79
109
|
# @param [String] old
|
80
110
|
# @param [String, nil] new
|
111
|
+
# @param [Symbol, Array<Sybmol>] id
|
112
|
+
# @yield appends additional message to end of provided template
|
81
113
|
#
|
82
|
-
def deprecate(old, new = nil)
|
83
|
-
|
114
|
+
def deprecate(old, new = nil, id: [], &block)
|
115
|
+
id = Array(id)
|
116
|
+
return if @ignored.include?(:deprecations) || (@ignored & id).any?
|
117
|
+
|
118
|
+
ids = id.empty? ? '' : "[#{id.map(&:inspect).join(', ')}] "
|
119
|
+
|
120
|
+
message = +"[DEPRECATION] #{ids}#{old} is deprecated"
|
84
121
|
message << if new
|
85
122
|
". Use #{new} instead."
|
86
123
|
else
|
87
|
-
' and will be removed in
|
124
|
+
' and will be removed in a future release.'
|
88
125
|
end
|
89
|
-
|
90
|
-
warn message
|
126
|
+
warn message, &block
|
91
127
|
end
|
92
128
|
|
93
129
|
private
|
94
130
|
|
95
|
-
def create_logger(
|
96
|
-
logger = ::Logger.new(
|
97
|
-
logger.progname =
|
131
|
+
def create_logger(name)
|
132
|
+
logger = ::Logger.new($stdout)
|
133
|
+
logger.progname = name
|
98
134
|
logger.level = default_level
|
99
135
|
logger.formatter = proc do |severity, time, progname, msg|
|
100
136
|
"#{time.strftime('%F %T')} #{severity} #{progname} #{msg}\n"
|
@@ -104,11 +140,7 @@ module Selenium
|
|
104
140
|
end
|
105
141
|
|
106
142
|
def default_level
|
107
|
-
|
108
|
-
:debug
|
109
|
-
else
|
110
|
-
:warn
|
111
|
-
end
|
143
|
+
$DEBUG || ENV.key?('DEBUG') ? :debug : :warn
|
112
144
|
end
|
113
145
|
end # Logger
|
114
146
|
end # WebDriver
|
@@ -25,7 +25,8 @@ module Selenium
|
|
25
25
|
def initialize(options: nil, **opts)
|
26
26
|
@options = if options
|
27
27
|
WebDriver.logger.deprecate(":options as keyword for initializing #{self.class}",
|
28
|
-
"custom values directly in #new constructor"
|
28
|
+
"custom values directly in #new constructor",
|
29
|
+
id: :options_options)
|
29
30
|
opts.merge(options)
|
30
31
|
else
|
31
32
|
opts
|
@@ -34,8 +34,8 @@ module Selenium
|
|
34
34
|
Platform.interfaces.each do |host|
|
35
35
|
begin
|
36
36
|
TCPServer.new(host, port).close
|
37
|
-
rescue *IGNORED_ERRORS =>
|
38
|
-
WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{
|
37
|
+
rescue *IGNORED_ERRORS => e
|
38
|
+
WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
|
39
39
|
# ignored - some machines appear unable to bind to some of their interfaces
|
40
40
|
end
|
41
41
|
end
|
File without changes
|
@@ -30,6 +30,7 @@ module Selenium
|
|
30
30
|
link_text: 'link text',
|
31
31
|
name: 'name',
|
32
32
|
partial_link_text: 'partial link text',
|
33
|
+
relative: 'relative',
|
33
34
|
tag_name: 'tag name',
|
34
35
|
xpath: 'xpath'
|
35
36
|
}.freeze
|
@@ -59,7 +60,7 @@ module Selenium
|
|
59
60
|
by = FINDERS[how.to_sym]
|
60
61
|
raise ArgumentError, "cannot find element by #{how.inspect}" unless by
|
61
62
|
|
62
|
-
bridge.find_element_by by, what
|
63
|
+
bridge.find_element_by by, what, ref
|
63
64
|
rescue Selenium::WebDriver::Error::TimeoutError
|
64
65
|
# Implicit Wait times out in Edge
|
65
66
|
raise Selenium::WebDriver::Error::NoSuchElementError
|
@@ -77,7 +78,7 @@ module Selenium
|
|
77
78
|
by = FINDERS[how.to_sym]
|
78
79
|
raise ArgumentError, "cannot find elements by #{how.inspect}" unless by
|
79
80
|
|
80
|
-
bridge.find_elements_by by, what
|
81
|
+
bridge.find_elements_by by, what, ref
|
81
82
|
rescue Selenium::WebDriver::Error::TimeoutError
|
82
83
|
# Implicit Wait times out in Edge
|
83
84
|
[]
|
@@ -37,19 +37,6 @@ module Selenium
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def firefox(**opts)
|
40
|
-
binary_path = Firefox::Binary.path
|
41
|
-
args = opts.delete(:args)
|
42
|
-
case args
|
43
|
-
when Hash
|
44
|
-
args[:binary] ||= binary_path
|
45
|
-
opts[:args] = args
|
46
|
-
when Array
|
47
|
-
opts[:args] = ["--binary=#{binary_path}"]
|
48
|
-
opts[:args] += args
|
49
|
-
else
|
50
|
-
opts[:args] = ["--binary=#{binary_path}"]
|
51
|
-
end
|
52
|
-
|
53
40
|
Firefox::Service.new(**opts)
|
54
41
|
end
|
55
42
|
|
@@ -69,8 +69,8 @@ module Selenium
|
|
69
69
|
ChildProcess.close_on_exec @server
|
70
70
|
|
71
71
|
true
|
72
|
-
rescue SocketError, Errno::EADDRINUSE, Errno::EBADF =>
|
73
|
-
WebDriver.logger.debug("#{self}: #{
|
72
|
+
rescue SocketError, Errno::EADDRINUSE, Errno::EBADF => e
|
73
|
+
WebDriver.logger.debug("#{self}: #{e.message}")
|
74
74
|
false
|
75
75
|
end
|
76
76
|
|
@@ -28,13 +28,15 @@ module Selenium
|
|
28
28
|
|
29
29
|
def self.driver_path=(path)
|
30
30
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Edge#driver_path=',
|
31
|
-
'Selenium::WebDriver::Edge::Service#driver_path='
|
31
|
+
'Selenium::WebDriver::Edge::Service#driver_path=',
|
32
|
+
id: :driver_path
|
32
33
|
Selenium::WebDriver::Edge::Service.driver_path = path
|
33
34
|
end
|
34
35
|
|
35
36
|
def self.driver_path
|
36
37
|
WebDriver.logger.deprecate 'Selenium::WebDriver::Edge#driver_path',
|
37
|
-
'Selenium::WebDriver::Edge::Service#driver_path'
|
38
|
+
'Selenium::WebDriver::Edge::Service#driver_path',
|
39
|
+
id: :driver_path
|
38
40
|
Selenium::WebDriver::Edge::Service.driver_path
|
39
41
|
end
|
40
42
|
end # EdgeHtml
|
@@ -30,24 +30,10 @@ module Selenium
|
|
30
30
|
include DriverExtensions::HasWebStorage
|
31
31
|
include DriverExtensions::TakesScreenshot
|
32
32
|
|
33
|
-
def initialize(opts = {})
|
34
|
-
opts[:desired_capabilities] ||= Remote::Capabilities.edge
|
35
|
-
|
36
|
-
opts[:url] ||= service_url(opts)
|
37
|
-
|
38
|
-
listener = opts.delete(:listener)
|
39
|
-
desired_capabilities = opts.delete(:desired_capabilities)
|
40
|
-
|
41
|
-
@bridge = Remote::Bridge.new(opts)
|
42
|
-
@bridge.create_session(desired_capabilities)
|
43
|
-
|
44
|
-
super(@bridge, listener: listener)
|
45
|
-
end
|
46
|
-
|
47
33
|
def browser
|
48
34
|
:edge
|
49
35
|
end
|
50
36
|
end # Driver
|
51
|
-
end #
|
37
|
+
end # EdgeHtml
|
52
38
|
end # WebDriver
|
53
39
|
end # Selenium
|