selenium-webdriver 4.0.0.alpha3 → 4.0.0.alpha4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +50 -1
  3. data/lib/selenium/server.rb +1 -1
  4. data/lib/selenium/webdriver.rb +2 -0
  5. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  6. data/lib/selenium/webdriver/atoms/getAttribute.js +84 -7
  7. data/lib/selenium/webdriver/atoms/isDisplayed.js +75 -77
  8. data/lib/selenium/webdriver/chrome.rb +4 -2
  9. data/lib/selenium/webdriver/chrome/driver.rb +1 -16
  10. data/lib/selenium/webdriver/chrome/options.rb +1 -1
  11. data/lib/selenium/webdriver/chrome/service.rb +0 -4
  12. data/lib/selenium/webdriver/common.rb +1 -0
  13. data/lib/selenium/webdriver/common/driver.rb +25 -5
  14. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +38 -0
  15. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +2 -1
  16. data/lib/selenium/webdriver/common/logger.rb +47 -15
  17. data/lib/selenium/webdriver/common/options.rb +2 -1
  18. data/lib/selenium/webdriver/common/platform.rb +3 -0
  19. data/lib/selenium/webdriver/common/port_prober.rb +2 -2
  20. data/lib/selenium/webdriver/common/proxy.rb +0 -0
  21. data/lib/selenium/webdriver/common/search_context.rb +3 -2
  22. data/lib/selenium/webdriver/common/service.rb +0 -13
  23. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  24. data/lib/selenium/webdriver/common/wait.rb +1 -1
  25. data/lib/selenium/webdriver/edge.rb +4 -2
  26. data/lib/selenium/webdriver/edge_chrome/driver.rb +1 -1
  27. data/lib/selenium/webdriver/edge_chrome/service.rb +0 -4
  28. data/lib/selenium/webdriver/edge_html/driver.rb +1 -15
  29. data/lib/selenium/webdriver/edge_html/options.rb +1 -1
  30. data/lib/selenium/webdriver/edge_html/service.rb +1 -5
  31. data/lib/selenium/webdriver/firefox.rb +10 -4
  32. data/lib/selenium/webdriver/firefox/driver.rb +0 -16
  33. data/lib/selenium/webdriver/firefox/options.rb +4 -1
  34. data/lib/selenium/webdriver/firefox/profile.rb +4 -77
  35. data/lib/selenium/webdriver/firefox/service.rb +0 -4
  36. data/lib/selenium/webdriver/ie.rb +4 -2
  37. data/lib/selenium/webdriver/ie/driver.rb +0 -15
  38. data/lib/selenium/webdriver/ie/service.rb +5 -9
  39. data/lib/selenium/webdriver/remote/bridge.rb +31 -29
  40. data/lib/selenium/webdriver/remote/capabilities.rb +1 -0
  41. data/lib/selenium/webdriver/remote/driver.rb +6 -12
  42. data/lib/selenium/webdriver/remote/http/default.rb +3 -3
  43. data/lib/selenium/webdriver/safari.rb +4 -2
  44. data/lib/selenium/webdriver/safari/driver.rb +0 -16
  45. data/lib/selenium/webdriver/safari/service.rb +0 -4
  46. data/lib/selenium/webdriver/support.rb +1 -0
  47. data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
  48. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  49. data/lib/selenium/webdriver/version.rb +1 -1
  50. data/selenium-webdriver.gemspec +4 -3
  51. metadata +24 -15
  52. data/lib/selenium/webdriver/firefox/binary.rb +0 -110
  53. 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 mobilie emulation values
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
@@ -20,10 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Chrome
23
- #
24
- # @api private
25
- #
26
-
27
23
  class Service < WebDriver::Service
28
24
  DEFAULT_PORT = 9515
29
25
  EXECUTABLE = 'chromedriver'
@@ -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
- @bridge = bridge
77
- @bridge = Support::EventFiringBridge.new(bridge, listener) if 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.browser
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
- def initialize
49
- @logger = create_logger($stdout)
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
- message = +"[DEPRECATION] #{old} is deprecated"
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 the next releases.'
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(output)
96
- logger = ::Logger.new(output)
97
- logger.progname = 'Selenium'
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
- if $DEBUG || ENV.key?('DEBUG')
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
@@ -96,6 +96,9 @@ module Selenium
96
96
  return false unless linux?
97
97
 
98
98
  File.read('/proc/version').include?('Microsoft')
99
+ rescue Errno::EACCES
100
+ # the file cannot be accessed on Linux on DeX
101
+ false
99
102
  end
100
103
 
101
104
  def cygwin?
@@ -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 => ex
38
- WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{ex.message})")
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.to_s, ref
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.to_s, ref
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 => ex
73
- WebDriver.logger.debug("#{self}: #{ex.message}")
72
+ rescue SocketError, Errno::EADDRINUSE, Errno::EBADF => e
73
+ WebDriver.logger.debug("#{self}: #{e.message}")
74
74
  false
75
75
  end
76
76
 
@@ -55,7 +55,7 @@ module Selenium
55
55
  begin
56
56
  result = yield
57
57
  return result if result
58
- rescue *@ignored => last_error
58
+ rescue *@ignored => last_error # rubocop:disable Naming/RescuedExceptionsVariableName
59
59
  # swallowed
60
60
  end
61
61
 
@@ -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
@@ -33,6 +33,6 @@ module Selenium
33
33
  :edge_chrome
34
34
  end
35
35
  end # Driver
36
- end # Chrome
36
+ end # EdgeChrome
37
37
  end # WebDriver
38
38
  end # Selenium
@@ -22,10 +22,6 @@ require 'selenium/webdriver/chrome/service'
22
22
  module Selenium
23
23
  module WebDriver
24
24
  module EdgeChrome
25
- #
26
- # @api private
27
- #
28
-
29
25
  class Service < Selenium::WebDriver::Chrome::Service
30
26
  DEFAULT_PORT = 9515
31
27
  EXECUTABLE = 'msedgedriver'
@@ -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 # Edge
37
+ end # EdgeHtml
52
38
  end # WebDriver
53
39
  end # Selenium
@@ -86,6 +86,6 @@ module Selenium
86
86
  raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.directory?(path)
87
87
  end
88
88
  end # Options
89
- end # Edge
89
+ end # EdgeHtml
90
90
  end # WebDriver
91
91
  end # Selenium