selenium-webdriver 4.0.0.alpha5 → 4.0.0.alpha6

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 (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +38 -0
  3. data/LICENSE +1 -1
  4. data/lib/selenium/webdriver/atoms/findElements.js +1 -1
  5. data/lib/selenium/webdriver/chrome/bridge.rb +4 -6
  6. data/lib/selenium/webdriver/chrome/driver.rb +4 -0
  7. data/lib/selenium/webdriver/chrome/options.rb +24 -19
  8. data/lib/selenium/webdriver/common.rb +1 -0
  9. data/lib/selenium/webdriver/common/driver.rb +55 -23
  10. data/lib/selenium/webdriver/common/logger.rb +1 -1
  11. data/lib/selenium/webdriver/common/manager.rb +5 -0
  12. data/lib/selenium/webdriver/common/options.rb +32 -9
  13. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  14. data/lib/selenium/webdriver/common/service.rb +12 -106
  15. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  16. data/lib/selenium/webdriver/devtools.rb +118 -0
  17. data/lib/selenium/webdriver/devtools/accessibility.rb +62 -0
  18. data/lib/selenium/webdriver/devtools/animation.rb +98 -0
  19. data/lib/selenium/webdriver/devtools/application_cache.rb +64 -0
  20. data/lib/selenium/webdriver/devtools/audits.rb +61 -0
  21. data/lib/selenium/webdriver/devtools/background_service.rb +67 -0
  22. data/lib/selenium/webdriver/devtools/browser.rb +123 -0
  23. data/lib/selenium/webdriver/devtools/cache_storage.rb +73 -0
  24. data/lib/selenium/webdriver/devtools/cast.rb +70 -0
  25. data/lib/selenium/webdriver/devtools/console.rb +57 -0
  26. data/lib/selenium/webdriver/devtools/css.rb +165 -0
  27. data/lib/selenium/webdriver/devtools/database.rb +64 -0
  28. data/lib/selenium/webdriver/devtools/debugger.rb +229 -0
  29. data/lib/selenium/webdriver/devtools/device_orientation.rb +53 -0
  30. data/lib/selenium/webdriver/devtools/dom.rb +320 -0
  31. data/lib/selenium/webdriver/devtools/domdebugger.rb +93 -0
  32. data/lib/selenium/webdriver/devtools/domsnapshot.rb +65 -0
  33. data/lib/selenium/webdriver/devtools/domstorage.rb +79 -0
  34. data/lib/selenium/webdriver/devtools/emulation.rb +180 -0
  35. data/lib/selenium/webdriver/devtools/fetch.rb +97 -0
  36. data/lib/selenium/webdriver/devtools/headless_experimental.rb +61 -0
  37. data/lib/selenium/webdriver/devtools/heap_profiler.rb +107 -0
  38. data/lib/selenium/webdriver/devtools/indexed_db.rb +100 -0
  39. data/lib/selenium/webdriver/devtools/input.rb +140 -0
  40. data/lib/selenium/webdriver/devtools/inspector.rb +55 -0
  41. data/lib/selenium/webdriver/devtools/io.rb +59 -0
  42. data/lib/selenium/webdriver/devtools/layer_tree.rb +95 -0
  43. data/lib/selenium/webdriver/devtools/log.rb +66 -0
  44. data/lib/selenium/webdriver/devtools/media.rb +57 -0
  45. data/lib/selenium/webdriver/devtools/memory.rb +86 -0
  46. data/lib/selenium/webdriver/devtools/network.rb +228 -0
  47. data/lib/selenium/webdriver/devtools/overlay.rb +157 -0
  48. data/lib/selenium/webdriver/devtools/page.rb +374 -0
  49. data/lib/selenium/webdriver/devtools/performance.rb +63 -0
  50. data/lib/selenium/webdriver/devtools/profiler.rb +111 -0
  51. data/lib/selenium/webdriver/devtools/runtime.rb +193 -0
  52. data/lib/selenium/webdriver/devtools/schema.rb +46 -0
  53. data/lib/selenium/webdriver/devtools/security.rb +71 -0
  54. data/lib/selenium/webdriver/devtools/service_worker.rb +116 -0
  55. data/lib/selenium/webdriver/devtools/storage.rb +95 -0
  56. data/lib/selenium/webdriver/devtools/system_info.rb +50 -0
  57. data/lib/selenium/webdriver/devtools/target.rb +141 -0
  58. data/lib/selenium/webdriver/devtools/tethering.rb +55 -0
  59. data/lib/selenium/webdriver/devtools/tracing.rb +76 -0
  60. data/lib/selenium/webdriver/devtools/web_audio.rb +70 -0
  61. data/lib/selenium/webdriver/devtools/web_authn.rb +94 -0
  62. data/lib/selenium/webdriver/edge_chrome/bridge.rb +9 -2
  63. data/lib/selenium/webdriver/edge_chrome/driver.rb +4 -0
  64. data/lib/selenium/webdriver/edge_chrome/options.rb +2 -0
  65. data/lib/selenium/webdriver/edge_html/options.rb +2 -9
  66. data/lib/selenium/webdriver/firefox/bridge.rb +1 -1
  67. data/lib/selenium/webdriver/firefox/driver.rb +4 -0
  68. data/lib/selenium/webdriver/firefox/options.rb +5 -10
  69. data/lib/selenium/webdriver/ie/options.rb +7 -10
  70. data/lib/selenium/webdriver/remote/bridge.rb +3 -13
  71. data/lib/selenium/webdriver/remote/capabilities.rb +11 -6
  72. data/lib/selenium/webdriver/safari/bridge.rb +1 -1
  73. data/lib/selenium/webdriver/safari/driver.rb +4 -0
  74. data/lib/selenium/webdriver/safari/options.rb +1 -8
  75. data/lib/selenium/webdriver/support/cdp_client_generator.rb +77 -0
  76. data/lib/selenium/webdriver/support/color.rb +2 -2
  77. data/lib/selenium/webdriver/version.rb +1 -1
  78. data/selenium-webdriver.gemspec +2 -2
  79. metadata +53 -5
@@ -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
 
@@ -68,7 +64,7 @@ module Selenium
68
64
  end
69
65
 
70
66
  attr_accessor :host
71
- attr_reader :executable_path
67
+ attr_reader :executable_path, :port, :extra_args
72
68
 
73
69
  #
74
70
  # End users should use a class method for the desired driver, rather than using this directly.
@@ -90,31 +86,20 @@ module Selenium
90
86
  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
91
87
  end
92
88
 
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
89
+ def launch
90
+ sm = ServiceManager.new(self)
91
+ sm.start
92
+ sm
103
93
  end
104
94
 
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
95
+ def shutdown_supported
96
+ self.class::SHUTDOWN_SUPPORTED
114
97
  end
115
98
 
116
- def uri
117
- @uri ||= URI.parse("http://#{@host}:#{@port}")
99
+ protected
100
+
101
+ def extract_service_args(driver_opts)
102
+ driver_opts.key?(:args) ? driver_opts.delete(:args) : []
118
103
  end
119
104
 
120
105
  private
@@ -128,85 +113,6 @@ module Selenium
128
113
  Platform.assert_executable path
129
114
  path
130
115
  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
116
  end # Service
211
117
  end # WebDriver
212
118
  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
@@ -0,0 +1,118 @@
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
+ Dir["#{__dir__}/devtools/*"].sort.each { |f| require f }
21
+
22
+ module Selenium
23
+ module WebDriver
24
+ class DevTools
25
+
26
+ def initialize(url)
27
+ @messages = []
28
+ @uri = URI("http://#{url}")
29
+
30
+ process_handshake
31
+ attach_socket_listener
32
+
33
+ target.attach_to_target(target_id: page_target['id'])
34
+ target.set_auto_attach(auto_attach: true, wait_for_debugger_on_start: false)
35
+ end
36
+
37
+ def callbacks
38
+ @callbacks ||= Hash.new { |callbacks, event| callbacks[event] = [] }
39
+ end
40
+
41
+ def send_cmd(method, **params)
42
+ id = next_id
43
+ data = JSON.generate(id: id, method: method, params: params.reject { |_, v| v.nil? })
44
+
45
+ out_frame = WebSocket::Frame::Outgoing::Client.new(version: ws.version, data: data, type: 'text')
46
+ socket.write(out_frame.to_s)
47
+
48
+ message = wait.until do
49
+ @messages.find { |m| m['id'] == id }
50
+ end
51
+
52
+ raise Error::WebDriverError, error_message(message['error']) if message['error']
53
+
54
+ message
55
+ end
56
+
57
+ private
58
+
59
+ def process_handshake
60
+ socket.print(ws.to_s)
61
+ ws << socket.readpartial(1024)
62
+ end
63
+
64
+ def attach_socket_listener
65
+ socket_listener = Thread.new do
66
+ until socket.eof?
67
+ incoming_frame << socket.readpartial(1024)
68
+
69
+ while (frame = incoming_frame.next)
70
+ message = JSON.parse(frame.to_s)
71
+ @messages << message
72
+ next unless message['method']
73
+
74
+ callbacks[message['method']].each do |callback|
75
+ callback.call(message['params'])
76
+ end
77
+ end
78
+ end
79
+ end
80
+ socket_listener.abort_on_exception = true
81
+ end
82
+
83
+ def incoming_frame
84
+ @incoming_frame ||= WebSocket::Frame::Incoming::Client.new(version: ws.version)
85
+ end
86
+
87
+ def wait
88
+ @wait ||= Wait.new(timeout: 10, interval: 0.1)
89
+ end
90
+
91
+ def socket
92
+ @socket ||= TCPSocket.new(ws.host, ws.port)
93
+ end
94
+
95
+ def ws
96
+ @ws ||= WebSocket::Handshake::Client.new(url: page_target['webSocketDebuggerUrl'])
97
+ end
98
+
99
+ def page_target
100
+ @page_target ||= begin
101
+ response = Net::HTTP.get(@uri.hostname, '/json', @uri.port)
102
+ targets = JSON.parse(response)
103
+ targets.find { |target| target['type'] == 'page' }
104
+ end
105
+ end
106
+
107
+ def next_id
108
+ @id ||= 0
109
+ @id += 1
110
+ end
111
+
112
+ def error_message(error)
113
+ [error['code'], error['message'], error['data']].join(': ')
114
+ end
115
+
116
+ end # DevTools
117
+ end # WebDriver
118
+ end # Selenium
@@ -0,0 +1,62 @@
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
+ # This file is automatically generated. Any changes will be lost!
21
+ module Selenium
22
+ module WebDriver
23
+ class DevTools
24
+ def accessibility
25
+ @accessibility ||= Accessibility.new(self)
26
+ end
27
+
28
+ class Accessibility
29
+
30
+ def initialize(devtools)
31
+ @devtools = devtools
32
+ end
33
+
34
+ def on(event, &block)
35
+ event = EVENTS[event] if event.is_a?(Symbol)
36
+ @devtools.callbacks["Accessibility.#{event}"] << block
37
+ end
38
+
39
+ def disable
40
+ @devtools.send_cmd('Accessibility.disable')
41
+ end
42
+
43
+ def enable
44
+ @devtools.send_cmd('Accessibility.enable')
45
+ end
46
+
47
+ def get_partial_axtree(node_id: nil, backend_node_id: nil, object_id: nil, fetch_relatives: nil)
48
+ @devtools.send_cmd('Accessibility.getPartialAXTree',
49
+ nodeId: node_id,
50
+ backendNodeId: backend_node_id,
51
+ objectId: object_id,
52
+ fetchRelatives: fetch_relatives)
53
+ end
54
+
55
+ def get_full_axtree
56
+ @devtools.send_cmd('Accessibility.getFullAXTree')
57
+ end
58
+
59
+ end # Accessibility
60
+ end # DevTools
61
+ end # WebDriver
62
+ end # Selenium