selenium-webdriver 4.0.0.alpha1 → 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.
- checksums.yaml +5 -5
- data/CHANGES +139 -1
- data/LICENSE +1 -1
- data/lib/selenium/server.rb +3 -3
- data/lib/selenium/webdriver.rb +11 -7
- 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 +10 -9
- data/lib/selenium/webdriver/chrome/bridge.rb +20 -4
- data/lib/selenium/webdriver/chrome/driver.rb +3 -52
- data/lib/selenium/webdriver/chrome/options.rb +97 -57
- data/lib/selenium/webdriver/chrome/profile.rb +2 -2
- data/lib/selenium/webdriver/chrome/service.rb +0 -4
- data/lib/selenium/webdriver/common.rb +3 -0
- data/lib/selenium/webdriver/common/driver.rb +76 -17
- data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_devtools.rb} +10 -8
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +2 -1
- data/lib/selenium/webdriver/common/logger.rb +48 -16
- data/lib/selenium/webdriver/common/manager.rb +5 -0
- data/lib/selenium/webdriver/common/options.rb +60 -121
- data/lib/selenium/webdriver/common/platform.rb +3 -0
- data/lib/selenium/webdriver/common/port_prober.rb +4 -6
- data/lib/selenium/webdriver/common/profile_helper.rb +10 -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 +30 -113
- data/lib/selenium/webdriver/common/service_manager.rb +151 -0
- data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
- data/lib/selenium/webdriver/common/wait.rb +1 -1
- data/lib/selenium/webdriver/devtools.rb +118 -0
- data/lib/selenium/webdriver/devtools/accessibility.rb +62 -0
- data/lib/selenium/webdriver/devtools/animation.rb +98 -0
- data/lib/selenium/webdriver/devtools/application_cache.rb +64 -0
- data/lib/selenium/webdriver/devtools/audits.rb +61 -0
- data/lib/selenium/webdriver/devtools/background_service.rb +67 -0
- data/lib/selenium/webdriver/devtools/browser.rb +123 -0
- data/lib/selenium/webdriver/devtools/cache_storage.rb +73 -0
- data/lib/selenium/webdriver/devtools/cast.rb +70 -0
- data/lib/selenium/webdriver/devtools/console.rb +57 -0
- data/lib/selenium/webdriver/devtools/css.rb +165 -0
- data/lib/selenium/webdriver/devtools/database.rb +64 -0
- data/lib/selenium/webdriver/devtools/debugger.rb +229 -0
- data/lib/selenium/webdriver/devtools/device_orientation.rb +53 -0
- data/lib/selenium/webdriver/devtools/dom.rb +320 -0
- data/lib/selenium/webdriver/devtools/domdebugger.rb +93 -0
- data/lib/selenium/webdriver/devtools/domsnapshot.rb +65 -0
- data/lib/selenium/webdriver/devtools/domstorage.rb +79 -0
- data/lib/selenium/webdriver/devtools/emulation.rb +180 -0
- data/lib/selenium/webdriver/devtools/fetch.rb +97 -0
- data/lib/selenium/webdriver/devtools/headless_experimental.rb +61 -0
- data/lib/selenium/webdriver/devtools/heap_profiler.rb +107 -0
- data/lib/selenium/webdriver/devtools/indexed_db.rb +100 -0
- data/lib/selenium/webdriver/devtools/input.rb +140 -0
- data/lib/selenium/webdriver/devtools/inspector.rb +55 -0
- data/lib/selenium/webdriver/devtools/io.rb +59 -0
- data/lib/selenium/webdriver/devtools/layer_tree.rb +95 -0
- data/lib/selenium/webdriver/devtools/log.rb +66 -0
- data/lib/selenium/webdriver/devtools/media.rb +57 -0
- data/lib/selenium/webdriver/devtools/memory.rb +86 -0
- data/lib/selenium/webdriver/devtools/network.rb +228 -0
- data/lib/selenium/webdriver/devtools/overlay.rb +157 -0
- data/lib/selenium/webdriver/devtools/page.rb +374 -0
- data/lib/selenium/webdriver/devtools/performance.rb +63 -0
- data/lib/selenium/webdriver/devtools/profiler.rb +111 -0
- data/lib/selenium/webdriver/devtools/runtime.rb +193 -0
- data/lib/selenium/webdriver/devtools/schema.rb +46 -0
- data/lib/selenium/webdriver/devtools/security.rb +71 -0
- data/lib/selenium/webdriver/devtools/service_worker.rb +116 -0
- data/lib/selenium/webdriver/devtools/storage.rb +95 -0
- data/lib/selenium/webdriver/devtools/system_info.rb +50 -0
- data/lib/selenium/webdriver/devtools/target.rb +141 -0
- data/lib/selenium/webdriver/devtools/tethering.rb +55 -0
- data/lib/selenium/webdriver/devtools/tracing.rb +76 -0
- data/lib/selenium/webdriver/devtools/web_audio.rb +70 -0
- data/lib/selenium/webdriver/devtools/web_authn.rb +94 -0
- data/lib/selenium/webdriver/edge.rb +29 -9
- data/lib/selenium/webdriver/{firefox/util.rb → edge_chrome/bridge.rb} +11 -20
- data/lib/selenium/webdriver/{common/w3c_options.rb → edge_chrome/driver.rb} +14 -17
- data/lib/selenium/webdriver/edge_chrome/options.rb +36 -0
- data/lib/selenium/webdriver/edge_chrome/profile.rb +33 -0
- data/lib/selenium/webdriver/edge_chrome/service.rb +36 -0
- data/lib/selenium/webdriver/{common/w3c_manager.rb → edge_html/driver.rb} +11 -17
- data/lib/selenium/webdriver/{edge → edge_html}/options.rb +26 -22
- data/lib/selenium/webdriver/{edge → edge_html}/service.rb +2 -6
- data/lib/selenium/webdriver/firefox.rb +18 -15
- data/lib/selenium/webdriver/firefox/bridge.rb +1 -1
- data/lib/selenium/webdriver/firefox/driver.rb +2 -30
- data/lib/selenium/webdriver/firefox/extension.rb +8 -0
- data/lib/selenium/webdriver/firefox/options.rb +47 -52
- data/lib/selenium/webdriver/firefox/profile.rb +7 -78
- data/lib/selenium/webdriver/firefox/service.rb +0 -4
- data/lib/selenium/webdriver/ie.rb +8 -7
- data/lib/selenium/webdriver/ie/driver.rb +0 -32
- data/lib/selenium/webdriver/ie/options.rb +10 -33
- data/lib/selenium/webdriver/ie/service.rb +5 -9
- data/lib/selenium/webdriver/remote.rb +16 -10
- data/lib/selenium/webdriver/remote/bridge.rb +34 -42
- data/lib/selenium/webdriver/remote/capabilities.rb +22 -6
- data/lib/selenium/webdriver/remote/driver.rb +6 -12
- data/lib/selenium/webdriver/remote/http/default.rb +9 -4
- data/lib/selenium/webdriver/remote/http/persistent.rb +5 -6
- data/lib/selenium/webdriver/safari.rb +9 -8
- data/lib/selenium/webdriver/safari/bridge.rb +4 -4
- data/lib/selenium/webdriver/safari/driver.rb +3 -29
- data/lib/selenium/webdriver/safari/options.rb +18 -19
- data/lib/selenium/webdriver/safari/service.rb +0 -4
- data/lib/selenium/webdriver/support.rb +1 -0
- data/lib/selenium/webdriver/support/cdp_client_generator.rb +77 -0
- data/lib/selenium/webdriver/support/color.rb +2 -2
- 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 +5 -4
- metadata +81 -42
- data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
- data/lib/selenium/webdriver/common/keyboard.rb +0 -70
- data/lib/selenium/webdriver/common/mouse.rb +0 -89
- data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
- data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
- data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
- data/lib/selenium/webdriver/edge/bridge.rb +0 -76
- data/lib/selenium/webdriver/edge/driver.rb +0 -70
- data/lib/selenium/webdriver/firefox/binary.rb +0 -110
- data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
- data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
- data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
- data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
- data/lib/selenium/webdriver/firefox/marionette/bridge.rb +0 -49
- data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
- data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
- data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
- data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
- data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
- data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
- data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
- data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
|
@@ -21,36 +21,40 @@ module Selenium
|
|
|
21
21
|
module WebDriver
|
|
22
22
|
#
|
|
23
23
|
# Base class implementing default behavior of service object,
|
|
24
|
-
# responsible for
|
|
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
|
|
|
35
|
-
def chrome(
|
|
36
|
-
Chrome::Service.new(
|
|
31
|
+
def chrome(**opts)
|
|
32
|
+
Chrome::Service.new(**opts)
|
|
37
33
|
end
|
|
38
34
|
|
|
39
|
-
def firefox(
|
|
40
|
-
Firefox::Service.new(
|
|
35
|
+
def firefox(**opts)
|
|
36
|
+
Firefox::Service.new(**opts)
|
|
41
37
|
end
|
|
42
38
|
|
|
43
|
-
def ie(
|
|
44
|
-
IE::Service.new(
|
|
39
|
+
def ie(**opts)
|
|
40
|
+
IE::Service.new(**opts)
|
|
45
41
|
end
|
|
46
42
|
alias_method :internet_explorer, :ie
|
|
47
43
|
|
|
48
|
-
def edge(
|
|
49
|
-
Edge::Service.new(
|
|
44
|
+
def edge(**opts)
|
|
45
|
+
Edge::Service.new(**opts)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def edge_chrome(**opts)
|
|
49
|
+
EdgeChrome::Service.new(**opts)
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def
|
|
53
|
-
|
|
52
|
+
def edge_html(**opts)
|
|
53
|
+
EdgeHtml::Service.new(**opts)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def safari(**opts)
|
|
57
|
+
Safari::Service.new(**opts)
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
def driver_path=(path)
|
|
@@ -60,7 +64,7 @@ module Selenium
|
|
|
60
64
|
end
|
|
61
65
|
|
|
62
66
|
attr_accessor :host
|
|
63
|
-
attr_reader :executable_path
|
|
67
|
+
attr_reader :executable_path, :port, :extra_args
|
|
64
68
|
|
|
65
69
|
#
|
|
66
70
|
# End users should use a class method for the desired driver, rather than using this directly.
|
|
@@ -82,31 +86,20 @@ module Selenium
|
|
|
82
86
|
raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
|
|
83
87
|
end
|
|
84
88
|
|
|
85
|
-
def
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
socket_lock.locked do
|
|
91
|
-
find_free_port
|
|
92
|
-
start_process
|
|
93
|
-
connect_until_stable
|
|
94
|
-
end
|
|
89
|
+
def launch
|
|
90
|
+
sm = ServiceManager.new(self)
|
|
91
|
+
sm.start
|
|
92
|
+
sm
|
|
95
93
|
end
|
|
96
94
|
|
|
97
|
-
def
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
stop_server
|
|
101
|
-
@process.poll_for_exit STOP_TIMEOUT
|
|
102
|
-
rescue ChildProcess::TimeoutError
|
|
103
|
-
nil # noop
|
|
104
|
-
ensure
|
|
105
|
-
stop_process
|
|
95
|
+
def shutdown_supported
|
|
96
|
+
self.class::SHUTDOWN_SUPPORTED
|
|
106
97
|
end
|
|
107
98
|
|
|
108
|
-
|
|
109
|
-
|
|
99
|
+
protected
|
|
100
|
+
|
|
101
|
+
def extract_service_args(driver_opts)
|
|
102
|
+
driver_opts.key?(:args) ? driver_opts.delete(:args) : []
|
|
110
103
|
end
|
|
111
104
|
|
|
112
105
|
private
|
|
@@ -120,82 +113,6 @@ module Selenium
|
|
|
120
113
|
Platform.assert_executable path
|
|
121
114
|
path
|
|
122
115
|
end
|
|
123
|
-
|
|
124
|
-
def build_process(*command)
|
|
125
|
-
WebDriver.logger.debug("Executing Process #{command}")
|
|
126
|
-
@process = ChildProcess.build(*command)
|
|
127
|
-
if WebDriver.logger.debug?
|
|
128
|
-
@process.io.stdout = @process.io.stderr = WebDriver.logger.io
|
|
129
|
-
elsif Platform.jruby?
|
|
130
|
-
# Apparently we need to read the output of drivers on JRuby.
|
|
131
|
-
@process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
@process
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def connect_to_server
|
|
138
|
-
Net::HTTP.start(@host, @port) do |http|
|
|
139
|
-
http.open_timeout = STOP_TIMEOUT / 2
|
|
140
|
-
http.read_timeout = STOP_TIMEOUT / 2
|
|
141
|
-
|
|
142
|
-
yield http
|
|
143
|
-
end
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
def find_free_port
|
|
147
|
-
@port = PortProber.above(@port)
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def start_process
|
|
151
|
-
@process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
|
|
152
|
-
# Note: this is a bug only in Windows 7
|
|
153
|
-
@process.leader = true unless Platform.windows?
|
|
154
|
-
@process.start
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
def stop_process
|
|
158
|
-
return if process_exited?
|
|
159
|
-
|
|
160
|
-
@process.stop STOP_TIMEOUT
|
|
161
|
-
@process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def stop_server
|
|
165
|
-
return if process_exited?
|
|
166
|
-
|
|
167
|
-
connect_to_server { |http| http.get('/shutdown') }
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
def process_running?
|
|
171
|
-
defined?(@process) && @process&.alive?
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def process_exited?
|
|
175
|
-
@process.nil? || @process.exited?
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def connect_until_stable
|
|
179
|
-
socket_poller = SocketPoller.new @host, @port, START_TIMEOUT
|
|
180
|
-
return if socket_poller.connected?
|
|
181
|
-
|
|
182
|
-
raise Error::WebDriverError, cannot_connect_error_text
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
def cannot_connect_error_text
|
|
186
|
-
"unable to connect to #{self.class::EXECUTABLE} #{@host}:#{@port}"
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
def socket_lock
|
|
190
|
-
@socket_lock ||= SocketLock.new(@port - 1, SOCKET_LOCK_TIMEOUT)
|
|
191
|
-
end
|
|
192
|
-
|
|
193
|
-
protected
|
|
194
|
-
|
|
195
|
-
def extract_service_args(driver_opts)
|
|
196
|
-
driver_opts.key?(:args) ? driver_opts.delete(:args) : []
|
|
197
|
-
end
|
|
198
|
-
|
|
199
116
|
end # Service
|
|
200
117
|
end # WebDriver
|
|
201
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
|
|
@@ -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
|
|
|
@@ -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
|