selenium-webdriver 4.0.0.alpha5 → 4.0.0.alpha6

Sign up to get free protection for your applications and to get access to all the features.
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