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.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +139 -1
  3. data/LICENSE +1 -1
  4. data/lib/selenium/server.rb +3 -3
  5. data/lib/selenium/webdriver.rb +11 -7
  6. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  7. data/lib/selenium/webdriver/atoms/getAttribute.js +84 -7
  8. data/lib/selenium/webdriver/atoms/isDisplayed.js +75 -77
  9. data/lib/selenium/webdriver/chrome.rb +10 -9
  10. data/lib/selenium/webdriver/chrome/bridge.rb +20 -4
  11. data/lib/selenium/webdriver/chrome/driver.rb +3 -52
  12. data/lib/selenium/webdriver/chrome/options.rb +97 -57
  13. data/lib/selenium/webdriver/chrome/profile.rb +2 -2
  14. data/lib/selenium/webdriver/chrome/service.rb +0 -4
  15. data/lib/selenium/webdriver/common.rb +3 -0
  16. data/lib/selenium/webdriver/common/driver.rb +76 -17
  17. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_devtools.rb} +10 -8
  18. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +2 -1
  19. data/lib/selenium/webdriver/common/logger.rb +48 -16
  20. data/lib/selenium/webdriver/common/manager.rb +5 -0
  21. data/lib/selenium/webdriver/common/options.rb +60 -121
  22. data/lib/selenium/webdriver/common/platform.rb +3 -0
  23. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  24. data/lib/selenium/webdriver/common/profile_helper.rb +10 -2
  25. data/lib/selenium/webdriver/common/proxy.rb +0 -0
  26. data/lib/selenium/webdriver/common/search_context.rb +3 -2
  27. data/lib/selenium/webdriver/common/service.rb +30 -113
  28. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  29. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  30. data/lib/selenium/webdriver/common/wait.rb +1 -1
  31. data/lib/selenium/webdriver/devtools.rb +118 -0
  32. data/lib/selenium/webdriver/devtools/accessibility.rb +62 -0
  33. data/lib/selenium/webdriver/devtools/animation.rb +98 -0
  34. data/lib/selenium/webdriver/devtools/application_cache.rb +64 -0
  35. data/lib/selenium/webdriver/devtools/audits.rb +61 -0
  36. data/lib/selenium/webdriver/devtools/background_service.rb +67 -0
  37. data/lib/selenium/webdriver/devtools/browser.rb +123 -0
  38. data/lib/selenium/webdriver/devtools/cache_storage.rb +73 -0
  39. data/lib/selenium/webdriver/devtools/cast.rb +70 -0
  40. data/lib/selenium/webdriver/devtools/console.rb +57 -0
  41. data/lib/selenium/webdriver/devtools/css.rb +165 -0
  42. data/lib/selenium/webdriver/devtools/database.rb +64 -0
  43. data/lib/selenium/webdriver/devtools/debugger.rb +229 -0
  44. data/lib/selenium/webdriver/devtools/device_orientation.rb +53 -0
  45. data/lib/selenium/webdriver/devtools/dom.rb +320 -0
  46. data/lib/selenium/webdriver/devtools/domdebugger.rb +93 -0
  47. data/lib/selenium/webdriver/devtools/domsnapshot.rb +65 -0
  48. data/lib/selenium/webdriver/devtools/domstorage.rb +79 -0
  49. data/lib/selenium/webdriver/devtools/emulation.rb +180 -0
  50. data/lib/selenium/webdriver/devtools/fetch.rb +97 -0
  51. data/lib/selenium/webdriver/devtools/headless_experimental.rb +61 -0
  52. data/lib/selenium/webdriver/devtools/heap_profiler.rb +107 -0
  53. data/lib/selenium/webdriver/devtools/indexed_db.rb +100 -0
  54. data/lib/selenium/webdriver/devtools/input.rb +140 -0
  55. data/lib/selenium/webdriver/devtools/inspector.rb +55 -0
  56. data/lib/selenium/webdriver/devtools/io.rb +59 -0
  57. data/lib/selenium/webdriver/devtools/layer_tree.rb +95 -0
  58. data/lib/selenium/webdriver/devtools/log.rb +66 -0
  59. data/lib/selenium/webdriver/devtools/media.rb +57 -0
  60. data/lib/selenium/webdriver/devtools/memory.rb +86 -0
  61. data/lib/selenium/webdriver/devtools/network.rb +228 -0
  62. data/lib/selenium/webdriver/devtools/overlay.rb +157 -0
  63. data/lib/selenium/webdriver/devtools/page.rb +374 -0
  64. data/lib/selenium/webdriver/devtools/performance.rb +63 -0
  65. data/lib/selenium/webdriver/devtools/profiler.rb +111 -0
  66. data/lib/selenium/webdriver/devtools/runtime.rb +193 -0
  67. data/lib/selenium/webdriver/devtools/schema.rb +46 -0
  68. data/lib/selenium/webdriver/devtools/security.rb +71 -0
  69. data/lib/selenium/webdriver/devtools/service_worker.rb +116 -0
  70. data/lib/selenium/webdriver/devtools/storage.rb +95 -0
  71. data/lib/selenium/webdriver/devtools/system_info.rb +50 -0
  72. data/lib/selenium/webdriver/devtools/target.rb +141 -0
  73. data/lib/selenium/webdriver/devtools/tethering.rb +55 -0
  74. data/lib/selenium/webdriver/devtools/tracing.rb +76 -0
  75. data/lib/selenium/webdriver/devtools/web_audio.rb +70 -0
  76. data/lib/selenium/webdriver/devtools/web_authn.rb +94 -0
  77. data/lib/selenium/webdriver/edge.rb +29 -9
  78. data/lib/selenium/webdriver/{firefox/util.rb → edge_chrome/bridge.rb} +11 -20
  79. data/lib/selenium/webdriver/{common/w3c_options.rb → edge_chrome/driver.rb} +14 -17
  80. data/lib/selenium/webdriver/edge_chrome/options.rb +36 -0
  81. data/lib/selenium/webdriver/edge_chrome/profile.rb +33 -0
  82. data/lib/selenium/webdriver/edge_chrome/service.rb +36 -0
  83. data/lib/selenium/webdriver/{common/w3c_manager.rb → edge_html/driver.rb} +11 -17
  84. data/lib/selenium/webdriver/{edge → edge_html}/options.rb +26 -22
  85. data/lib/selenium/webdriver/{edge → edge_html}/service.rb +2 -6
  86. data/lib/selenium/webdriver/firefox.rb +18 -15
  87. data/lib/selenium/webdriver/firefox/bridge.rb +1 -1
  88. data/lib/selenium/webdriver/firefox/driver.rb +2 -30
  89. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  90. data/lib/selenium/webdriver/firefox/options.rb +47 -52
  91. data/lib/selenium/webdriver/firefox/profile.rb +7 -78
  92. data/lib/selenium/webdriver/firefox/service.rb +0 -4
  93. data/lib/selenium/webdriver/ie.rb +8 -7
  94. data/lib/selenium/webdriver/ie/driver.rb +0 -32
  95. data/lib/selenium/webdriver/ie/options.rb +10 -33
  96. data/lib/selenium/webdriver/ie/service.rb +5 -9
  97. data/lib/selenium/webdriver/remote.rb +16 -10
  98. data/lib/selenium/webdriver/remote/bridge.rb +34 -42
  99. data/lib/selenium/webdriver/remote/capabilities.rb +22 -6
  100. data/lib/selenium/webdriver/remote/driver.rb +6 -12
  101. data/lib/selenium/webdriver/remote/http/default.rb +9 -4
  102. data/lib/selenium/webdriver/remote/http/persistent.rb +5 -6
  103. data/lib/selenium/webdriver/safari.rb +9 -8
  104. data/lib/selenium/webdriver/safari/bridge.rb +4 -4
  105. data/lib/selenium/webdriver/safari/driver.rb +3 -29
  106. data/lib/selenium/webdriver/safari/options.rb +18 -19
  107. data/lib/selenium/webdriver/safari/service.rb +0 -4
  108. data/lib/selenium/webdriver/support.rb +1 -0
  109. data/lib/selenium/webdriver/support/cdp_client_generator.rb +77 -0
  110. data/lib/selenium/webdriver/support/color.rb +2 -2
  111. data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
  112. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  113. data/lib/selenium/webdriver/version.rb +1 -1
  114. data/selenium-webdriver.gemspec +5 -4
  115. metadata +81 -42
  116. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  117. data/lib/selenium/webdriver/common/keyboard.rb +0 -70
  118. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  119. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  120. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  121. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  122. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  123. data/lib/selenium/webdriver/edge/driver.rb +0 -70
  124. data/lib/selenium/webdriver/firefox/binary.rb +0 -110
  125. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  126. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  127. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  128. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  129. data/lib/selenium/webdriver/firefox/marionette/bridge.rb +0 -49
  130. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  131. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  132. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  133. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  134. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  135. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  136. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  137. 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 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
 
35
- def chrome(*args)
36
- Chrome::Service.new(*args)
31
+ def chrome(**opts)
32
+ Chrome::Service.new(**opts)
37
33
  end
38
34
 
39
- def firefox(*args)
40
- Firefox::Service.new(*args)
35
+ def firefox(**opts)
36
+ Firefox::Service.new(**opts)
41
37
  end
42
38
 
43
- def ie(*args)
44
- IE::Service.new(*args)
39
+ def ie(**opts)
40
+ IE::Service.new(**opts)
45
41
  end
46
42
  alias_method :internet_explorer, :ie
47
43
 
48
- def edge(*args)
49
- Edge::Service.new(*args)
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 safari(*args)
53
- Safari::Service.new(*args)
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 start
86
- raise "already started: #{uri.inspect} #{@executable_path.inspect}" if process_running?
87
-
88
- Platform.exit_hook(&method(:stop)) # make sure we don't leave the server running
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 stop
98
- return unless self.class::SHUTDOWN_SUPPORTED
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
- def uri
109
- @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) : []
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 => 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
 
@@ -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