selenium-webdriver 4.0.0.alpha5 → 4.0.0.beta3

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/lib/selenium/devtools.rb +30 -0
  3. data/lib/selenium/server.rb +18 -26
  4. data/lib/selenium/webdriver.rb +1 -3
  5. data/lib/selenium/webdriver/atoms/findElements.js +93 -93
  6. data/lib/selenium/webdriver/atoms/getAttribute.js +75 -59
  7. data/lib/selenium/webdriver/atoms/isDisplayed.js +72 -72
  8. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  9. data/lib/selenium/webdriver/chrome.rb +1 -1
  10. data/lib/selenium/webdriver/chrome/driver.rb +28 -6
  11. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +6 -8
  12. data/lib/selenium/webdriver/chrome/options.rb +54 -37
  13. data/lib/selenium/webdriver/chrome/profile.rb +6 -3
  14. data/lib/selenium/webdriver/chrome/service.rb +4 -2
  15. data/lib/selenium/webdriver/common.rb +7 -2
  16. data/lib/selenium/webdriver/common/driver.rb +86 -26
  17. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  18. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +6 -1
  19. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  20. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +149 -0
  21. data/lib/selenium/webdriver/{edge_chrome/bridge.rb → common/driver_extensions/has_logs.rb} +7 -7
  22. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  23. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +67 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  25. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  26. data/lib/selenium/webdriver/common/element.rb +66 -12
  27. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  28. data/lib/selenium/webdriver/common/logger.rb +6 -3
  29. data/lib/selenium/webdriver/common/manager.rb +11 -1
  30. data/lib/selenium/webdriver/common/options.rb +90 -11
  31. data/lib/selenium/webdriver/common/platform.rb +3 -1
  32. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  33. data/lib/selenium/webdriver/common/proxy.rb +4 -1
  34. data/lib/selenium/webdriver/common/search_context.rb +4 -1
  35. data/lib/selenium/webdriver/common/service.rb +13 -114
  36. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  37. data/lib/selenium/webdriver/common/socket_poller.rb +19 -30
  38. data/lib/selenium/webdriver/common/takes_screenshot.rb +63 -0
  39. data/lib/selenium/webdriver/common/target_locator.rb +4 -4
  40. data/lib/selenium/webdriver/devtools.rb +144 -0
  41. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  42. data/lib/selenium/webdriver/{edge_html/driver.rb → devtools/exception_event.rb} +10 -13
  43. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  44. data/lib/selenium/webdriver/devtools/request.rb +57 -0
  45. data/lib/selenium/webdriver/edge.rb +7 -29
  46. data/lib/selenium/webdriver/{edge_chrome → edge}/driver.rb +10 -4
  47. data/lib/selenium/webdriver/edge/features.rb +39 -0
  48. data/lib/selenium/webdriver/{edge_chrome → edge}/options.rb +12 -3
  49. data/lib/selenium/webdriver/{edge_chrome → edge}/profile.rb +2 -2
  50. data/lib/selenium/webdriver/{edge_chrome → edge}/service.rb +2 -2
  51. data/lib/selenium/webdriver/firefox.rb +5 -1
  52. data/lib/selenium/webdriver/firefox/driver.rb +19 -3
  53. data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +3 -3
  54. data/lib/selenium/webdriver/firefox/options.rb +25 -31
  55. data/lib/selenium/webdriver/firefox/profile.rb +12 -2
  56. data/lib/selenium/webdriver/firefox/service.rb +1 -1
  57. data/lib/selenium/webdriver/ie/driver.rb +1 -2
  58. data/lib/selenium/webdriver/ie/options.rb +7 -20
  59. data/lib/selenium/webdriver/ie/service.rb +4 -2
  60. data/lib/selenium/webdriver/remote/bridge.rb +50 -42
  61. data/lib/selenium/webdriver/remote/capabilities.rb +127 -71
  62. data/lib/selenium/webdriver/remote/commands.rb +3 -0
  63. data/lib/selenium/webdriver/remote/driver.rb +10 -3
  64. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  65. data/lib/selenium/webdriver/remote/http/default.rb +8 -7
  66. data/lib/selenium/webdriver/remote/http/persistent.rb +6 -0
  67. data/lib/selenium/webdriver/safari.rb +8 -1
  68. data/lib/selenium/webdriver/safari/driver.rb +3 -4
  69. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  70. data/lib/selenium/webdriver/safari/options.rb +1 -33
  71. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  72. data/lib/selenium/webdriver/support/color.rb +2 -2
  73. data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
  74. data/lib/selenium/webdriver/support/guards.rb +95 -0
  75. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  76. data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
  77. data/lib/selenium/webdriver/support/select.rb +2 -2
  78. data/lib/selenium/webdriver/version.rb +1 -1
  79. metadata +69 -32
  80. data/CHANGES +0 -1725
  81. data/Gemfile +0 -4
  82. data/LICENSE +0 -202
  83. data/README.md +0 -35
  84. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -65
  85. data/lib/selenium/webdriver/edge_html/options.rb +0 -91
  86. data/lib/selenium/webdriver/edge_html/service.rb +0 -47
  87. data/selenium-webdriver.gemspec +0 -48
@@ -57,6 +57,8 @@ module Selenium
57
57
  :jenkins
58
58
  elsif ENV['APPVEYOR']
59
59
  :appveyor
60
+ elsif ENV['GITHUB_ACTIONS']
61
+ :github
60
62
  end
61
63
  end
62
64
 
@@ -95,7 +97,7 @@ module Selenium
95
97
  def wsl?
96
98
  return false unless linux?
97
99
 
98
- File.read('/proc/version').include?('Microsoft')
100
+ File.read('/proc/version').downcase.include?('microsoft')
99
101
  rescue Errno::EACCES
100
102
  # the file cannot be accessed on Linux on DeX
101
103
  false
@@ -32,12 +32,10 @@ module Selenium
32
32
 
33
33
  def self.free?(port)
34
34
  Platform.interfaces.each do |host|
35
- begin
36
- TCPServer.new(host, port).close
37
- rescue *IGNORED_ERRORS => e
38
- WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
39
- # ignored - some machines appear unable to bind to some of their interfaces
40
- end
35
+ TCPServer.new(host, port).close
36
+ rescue *IGNORED_ERRORS => e
37
+ WebDriver.logger.debug("port prober could not bind to #{host}:#{port} (#{e.message})")
38
+ # ignored - some machines appear unable to bind to some of their interfaces
41
39
  end
42
40
 
43
41
  true
@@ -127,7 +127,10 @@ module Selenium
127
127
  end
128
128
 
129
129
  def type=(type)
130
- raise ArgumentError, "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}" unless TYPES.key? type
130
+ unless TYPES.key? type
131
+ raise ArgumentError,
132
+ "invalid proxy type: #{type.inspect}, expected one of #{TYPES.keys.inspect}"
133
+ end
131
134
 
132
135
  if defined?(@type) && type != @type
133
136
  raise ArgumentError, "incompatible proxy type #{type.inspect} (already set to #{@type.inspect})"
@@ -93,7 +93,10 @@ module Selenium
93
93
  when 1
94
94
  arg = args.first
95
95
 
96
- raise ArgumentError, "expected #{arg.inspect}:#{arg.class} to respond to #shift" unless arg.respond_to?(:shift)
96
+ unless arg.respond_to?(:shift)
97
+ raise ArgumentError,
98
+ "expected #{arg.inspect}:#{arg.class} to respond to #shift"
99
+ end
97
100
 
98
101
  # this will be a single-entry hash, so use #shift over #first or #[]
99
102
  arr = arg.dup.shift
@@ -21,14 +21,10 @@ module Selenium
21
21
  module WebDriver
22
22
  #
23
23
  # Base class implementing default behavior of service object,
24
- # responsible for starting and stopping driver implementations.
24
+ # responsible for storing a service manager configuration.
25
25
  #
26
26
 
27
27
  class Service
28
- START_TIMEOUT = 20
29
- SOCKET_LOCK_TIMEOUT = 45
30
- STOP_TIMEOUT = 20
31
-
32
28
  class << self
33
29
  attr_reader :driver_path
34
30
 
@@ -48,14 +44,7 @@ module Selenium
48
44
  def edge(**opts)
49
45
  Edge::Service.new(**opts)
50
46
  end
51
-
52
- def edge_chrome(**opts)
53
- EdgeChrome::Service.new(**opts)
54
- end
55
-
56
- def edge_html(**opts)
57
- EdgeHtml::Service.new(**opts)
58
- end
47
+ alias_method :microsoftedge, :edge
59
48
 
60
49
  def safari(**opts)
61
50
  Safari::Service.new(**opts)
@@ -68,7 +57,7 @@ module Selenium
68
57
  end
69
58
 
70
59
  attr_accessor :host
71
- attr_reader :executable_path
60
+ attr_reader :executable_path, :port, :extra_args
72
61
 
73
62
  #
74
63
  # End users should use a class method for the desired driver, rather than using this directly.
@@ -90,31 +79,20 @@ module Selenium
90
79
  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
91
80
  end
92
81
 
93
- def start
94
- raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
95
-
96
- Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running
97
-
98
- socket_lock.locked do
99
- find_free_port
100
- start_process
101
- connect_until_stable
102
- end
82
+ def launch
83
+ sm = ServiceManager.new(self)
84
+ sm.start
85
+ sm
103
86
  end
104
87
 
105
- def stop
106
- return unless self.class::SHUTDOWN_SUPPORTED
107
-
108
- stop_server
109
- @process.poll_for_exit STOP_TIMEOUT
110
- rescue ChildProcess::TimeoutError
111
- nil # noop
112
- ensure
113
- stop_process
88
+ def shutdown_supported
89
+ self.class::SHUTDOWN_SUPPORTED
114
90
  end
115
91
 
116
- def uri
117
- @uri ||= URI.parse("http://#{@host}:#{@port}")
92
+ protected
93
+
94
+ def extract_service_args(driver_opts)
95
+ driver_opts.key?(:args) ? driver_opts.delete(:args) : []
118
96
  end
119
97
 
120
98
  private
@@ -128,85 +106,6 @@ module Selenium
128
106
  Platform.assert_executable path
129
107
  path
130
108
  end
131
-
132
- def build_process(*command)
133
- WebDriver.logger.debug("Executing Process #{command}")
134
- @process = ChildProcess.build(*command)
135
- if WebDriver.logger.debug?
136
- @process.io.stdout = @process.io.stderr = WebDriver.logger.io
137
- elsif Platform.jruby?
138
- # Apparently we need to read the output of drivers on JRuby.
139
- @process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
140
- end
141
-
142
- @process
143
- end
144
-
145
- def connect_to_server
146
- Net::HTTP.start(@host, @port) do |http|
147
- http.open_timeout = STOP_TIMEOUT / 2
148
- http.read_timeout = STOP_TIMEOUT / 2
149
-
150
- yield http
151
- end
152
- end
153
-
154
- def find_free_port
155
- @port = PortProber.above(@port)
156
- end
157
-
158
- def start_process
159
- @process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
160
- # Note: this is a bug only in Windows 7
161
- @process.leader = true unless Platform.windows?
162
- @process.start
163
- end
164
-
165
- def stop_process
166
- return if process_exited?
167
-
168
- @process.stop STOP_TIMEOUT
169
- @process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
170
- end
171
-
172
- def stop_server
173
- return if process_exited?
174
-
175
- connect_to_server do |http|
176
- headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup
177
- http.get('/shutdown', headers)
178
- end
179
- end
180
-
181
- def process_running?
182
- defined?(@process) && @process&.alive?
183
- end
184
-
185
- def process_exited?
186
- @process.nil? || @process.exited?
187
- end
188
-
189
- def connect_until_stable
190
- socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
191
- return if socket_poller.connected?
192
-
193
- raise Error::WebDriverError, cannot_connect_error_text
194
- end
195
-
196
- def cannot_connect_error_text
197
- "unable to connect to #{self.class::EXECUTABLE} #{@host}:#{@port}"
198
- end
199
-
200
- def socket_lock
201
- @socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
202
- end
203
-
204
- protected
205
-
206
- def extract_service_args(driver_opts)
207
- driver_opts.key?(:args) ? driver_opts.delete(:args) : []
208
- end
209
-
210
109
  end # Service
211
110
  end # WebDriver
212
111
  end # Selenium
@@ -0,0 +1,151 @@
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
+ #
23
+ # Base class implementing default behavior of service_manager object,
24
+ # responsible for starting and stopping driver implementations.
25
+ #
26
+ # @api private
27
+ #
28
+ class ServiceManager
29
+ START_TIMEOUT = 20
30
+ SOCKET_LOCK_TIMEOUT = 45
31
+ STOP_TIMEOUT = 20
32
+
33
+ #
34
+ # End users should use a class method for the desired driver, rather than using this directly.
35
+ #
36
+ # @api private
37
+ #
38
+
39
+ def initialize(config)
40
+ @executable_path = config.executable_path
41
+ @host = Platform.localhost
42
+ @port = config.port
43
+ @extra_args = config.extra_args
44
+ @shutdown_supported = config.shutdown_supported
45
+
46
+ raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
47
+ end
48
+
49
+ def start
50
+ raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
51
+
52
+ Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running
53
+
54
+ socket_lock.locked do
55
+ find_free_port
56
+ start_process
57
+ connect_until_stable
58
+ end
59
+ end
60
+
61
+ def stop
62
+ return unless @shutdown_supported
63
+
64
+ stop_server
65
+ @process.poll_for_exit STOP_TIMEOUT
66
+ rescue ChildProcess::TimeoutError
67
+ nil # noop
68
+ ensure
69
+ stop_process
70
+ end
71
+
72
+ def uri
73
+ @uri ||= URI.parse("http://#{@host}:#{@port}")
74
+ end
75
+
76
+ private
77
+
78
+ def build_process(*command)
79
+ WebDriver.logger.debug("Executing Process #{command}")
80
+ @process = ChildProcess.build(*command)
81
+ if WebDriver.logger.debug?
82
+ @process.io.stdout = @process.io.stderr = WebDriver.logger.io
83
+ elsif Platform.jruby?
84
+ # Apparently we need to read the output of drivers on JRuby.
85
+ @process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
86
+ end
87
+
88
+ @process
89
+ end
90
+
91
+ def connect_to_server
92
+ Net::HTTP.start(@host, @port) do |http|
93
+ http.open_timeout = STOP_TIMEOUT / 2
94
+ http.read_timeout = STOP_TIMEOUT / 2
95
+
96
+ yield http
97
+ end
98
+ end
99
+
100
+ def find_free_port
101
+ @port = PortProber.above(@port)
102
+ end
103
+
104
+ def start_process
105
+ @process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
106
+ # NOTE: this is a bug only in Windows 7
107
+ @process.leader = true unless Platform.windows?
108
+ @process.start
109
+ end
110
+
111
+ def stop_process
112
+ return if process_exited?
113
+
114
+ @process.stop STOP_TIMEOUT
115
+ @process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
116
+ end
117
+
118
+ def stop_server
119
+ return if process_exited?
120
+
121
+ connect_to_server do |http|
122
+ headers = WebDriver::Remote::Http::Common::DEFAULT_HEADERS.dup
123
+ http.get('/shutdown', headers)
124
+ end
125
+ end
126
+
127
+ def process_running?
128
+ defined?(@process) && @process&.alive?
129
+ end
130
+
131
+ def process_exited?
132
+ @process.nil? || @process.exited?
133
+ end
134
+
135
+ def connect_until_stable
136
+ socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
137
+ return if socket_poller.connected?
138
+
139
+ raise Error::WebDriverError, cannot_connect_error_text
140
+ end
141
+
142
+ def cannot_connect_error_text
143
+ "unable to connect to #{@executable_path} #{@host}:#{@port}"
144
+ end
145
+
146
+ def socket_lock
147
+ @socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
148
+ end
149
+ end # Service
150
+ end # WebDriver
151
+ end # Selenium
@@ -65,37 +65,26 @@ module Selenium
65
65
  arr << Errno::EALREADY if Platform.wsl?
66
66
  }.freeze
67
67
 
68
- if Platform.jruby?
69
- # we use a plain TCPSocket here since JRuby has issues closing socket
70
- # see https://github.com/jruby/jruby/issues/5709
71
- def listening?
72
- TCPSocket.new(@host, @port).close
73
- true
74
- rescue *NOT_CONNECTED_ERRORS
75
- false
76
- end
77
- else
78
- def listening?
79
- addr = Socket.getaddrinfo(@host, @port, Socket::AF_INET, Socket::SOCK_STREAM)
80
- sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
81
- sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3])
82
-
83
- begin
84
- sock.connect_nonblock sockaddr
85
- rescue Errno::EINPROGRESS
86
- retry if socket_writable?(sock) && conn_completed?(sock)
87
- raise Errno::ECONNREFUSED
88
- rescue *CONNECTED_ERRORS
89
- # yay!
90
- end
91
-
92
- sock.close
93
- true
94
- rescue *NOT_CONNECTED_ERRORS
95
- sock&.close
96
- WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
97
- false
68
+ def listening?
69
+ addr = Socket.getaddrinfo(@host, @port, Socket::AF_INET, Socket::SOCK_STREAM)
70
+ sock = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
71
+ sockaddr = Socket.pack_sockaddr_in(@port, addr[0][3])
72
+
73
+ begin
74
+ sock.connect_nonblock sockaddr
75
+ rescue Errno::EINPROGRESS
76
+ retry if socket_writable?(sock) && conn_completed?(sock)
77
+ raise Errno::ECONNREFUSED
78
+ rescue *CONNECTED_ERRORS
79
+ # yay!
98
80
  end
81
+
82
+ sock.close
83
+ true
84
+ rescue *NOT_CONNECTED_ERRORS
85
+ sock&.close
86
+ WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
87
+ false
99
88
  end
100
89
 
101
90
  def socket_writable?(sock)
@@ -0,0 +1,63 @@
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
+ #
23
+ # @api private
24
+ #
25
+ module TakesScreenshot
26
+ #
27
+ # Save a PNG screenshot to the given path
28
+ #
29
+ # @api public
30
+ #
31
+
32
+ def save_screenshot(png_path)
33
+ extension = File.extname(png_path).downcase
34
+ if extension != '.png'
35
+ WebDriver.logger.warn "name used for saved screenshot does not match file type. "\
36
+ "It should end with .png extension",
37
+ id: :screenshot
38
+ end
39
+ File.open(png_path, 'wb') { |f| f << screenshot_as(:png) }
40
+ end
41
+
42
+ #
43
+ # Return a PNG screenshot in the given format as a string
44
+ #
45
+ # @param [:base64, :png] format
46
+ # @return String screenshot
47
+ #
48
+ # @api public
49
+
50
+ def screenshot_as(format)
51
+ case format
52
+ when :base64
53
+ screenshot
54
+ when :png
55
+ screenshot.unpack1('m')
56
+ else
57
+ raise Error::UnsupportedOperationError, "unsupported format: #{format.inspect}"
58
+ end
59
+ end
60
+
61
+ end # TakesScreenshot
62
+ end # WebDriver
63
+ end # Selenium