selenium-webdriver 4.0.0.alpha6 → 4.0.0.beta4

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +137 -4
  3. data/Gemfile +3 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/lib/selenium/server.rb +18 -26
  8. data/lib/selenium/webdriver.rb +1 -4
  9. data/lib/selenium/webdriver/atoms/findElements.js +93 -93
  10. data/lib/selenium/webdriver/atoms/getAttribute.js +75 -59
  11. data/lib/selenium/webdriver/atoms/isDisplayed.js +72 -72
  12. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  13. data/lib/selenium/webdriver/chrome.rb +1 -1
  14. data/lib/selenium/webdriver/chrome/driver.rb +25 -10
  15. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +3 -3
  16. data/lib/selenium/webdriver/chrome/options.rb +51 -39
  17. data/lib/selenium/webdriver/chrome/profile.rb +6 -3
  18. data/lib/selenium/webdriver/chrome/service.rb +4 -2
  19. data/lib/selenium/webdriver/common.rb +8 -2
  20. data/lib/selenium/webdriver/common/driver.rb +36 -8
  21. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  23. data/lib/selenium/webdriver/{edge_html/driver.rb → common/driver_extensions/has_cdp.rb} +12 -13
  24. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +6 -1
  25. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  26. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +149 -0
  27. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  29. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +67 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  32. data/lib/selenium/webdriver/common/element.rb +66 -12
  33. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  34. data/lib/selenium/webdriver/common/logger.rb +5 -2
  35. data/lib/selenium/webdriver/common/manager.rb +6 -1
  36. data/lib/selenium/webdriver/common/options.rb +76 -14
  37. data/lib/selenium/webdriver/common/platform.rb +3 -1
  38. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  39. data/lib/selenium/webdriver/common/search_context.rb +4 -1
  40. data/lib/selenium/webdriver/common/service.rb +1 -8
  41. data/lib/selenium/webdriver/common/service_manager.rb +1 -1
  42. data/lib/selenium/webdriver/common/socket_poller.rb +19 -30
  43. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  44. data/lib/selenium/webdriver/common/target_locator.rb +4 -4
  45. data/lib/selenium/webdriver/devtools.rb +44 -18
  46. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  47. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  48. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  49. data/lib/selenium/webdriver/devtools/{console.rb → request.rb} +22 -22
  50. data/lib/selenium/webdriver/edge.rb +7 -29
  51. data/lib/selenium/webdriver/{edge_chrome → edge}/driver.rb +8 -6
  52. data/lib/selenium/webdriver/{edge_chrome/bridge.rb → edge/features.rb} +9 -7
  53. data/lib/selenium/webdriver/{edge_chrome → edge}/options.rb +11 -4
  54. data/lib/selenium/webdriver/{edge_chrome → edge}/profile.rb +2 -2
  55. data/lib/selenium/webdriver/{edge_chrome → edge}/service.rb +2 -2
  56. data/lib/selenium/webdriver/firefox.rb +5 -1
  57. data/lib/selenium/webdriver/firefox/driver.rb +18 -5
  58. data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +9 -4
  59. data/lib/selenium/webdriver/firefox/options.rb +20 -21
  60. data/lib/selenium/webdriver/firefox/profile.rb +12 -2
  61. data/lib/selenium/webdriver/firefox/service.rb +1 -1
  62. data/lib/selenium/webdriver/ie/driver.rb +1 -2
  63. data/lib/selenium/webdriver/ie/options.rb +1 -11
  64. data/lib/selenium/webdriver/ie/service.rb +4 -2
  65. data/lib/selenium/webdriver/remote/bridge.rb +48 -30
  66. data/lib/selenium/webdriver/remote/capabilities.rb +105 -64
  67. data/lib/selenium/webdriver/remote/commands.rb +3 -0
  68. data/lib/selenium/webdriver/remote/driver.rb +10 -3
  69. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  70. data/lib/selenium/webdriver/remote/http/default.rb +8 -7
  71. data/lib/selenium/webdriver/remote/http/persistent.rb +6 -0
  72. data/lib/selenium/webdriver/safari.rb +8 -1
  73. data/lib/selenium/webdriver/safari/driver.rb +3 -8
  74. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  75. data/lib/selenium/webdriver/safari/options.rb +0 -25
  76. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  77. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  78. data/lib/selenium/webdriver/support/cdp_client_generator.rb +44 -13
  79. data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
  80. data/lib/selenium/webdriver/support/guards.rb +95 -0
  81. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  82. data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
  83. data/lib/selenium/webdriver/support/select.rb +2 -2
  84. data/lib/selenium/webdriver/version.rb +1 -1
  85. data/selenium-webdriver.gemspec +26 -12
  86. metadata +91 -108
  87. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -65
  88. data/lib/selenium/webdriver/devtools/accessibility.rb +0 -62
  89. data/lib/selenium/webdriver/devtools/animation.rb +0 -98
  90. data/lib/selenium/webdriver/devtools/application_cache.rb +0 -64
  91. data/lib/selenium/webdriver/devtools/audits.rb +0 -61
  92. data/lib/selenium/webdriver/devtools/background_service.rb +0 -67
  93. data/lib/selenium/webdriver/devtools/browser.rb +0 -123
  94. data/lib/selenium/webdriver/devtools/cache_storage.rb +0 -73
  95. data/lib/selenium/webdriver/devtools/cast.rb +0 -70
  96. data/lib/selenium/webdriver/devtools/css.rb +0 -165
  97. data/lib/selenium/webdriver/devtools/database.rb +0 -64
  98. data/lib/selenium/webdriver/devtools/debugger.rb +0 -229
  99. data/lib/selenium/webdriver/devtools/device_orientation.rb +0 -53
  100. data/lib/selenium/webdriver/devtools/dom.rb +0 -320
  101. data/lib/selenium/webdriver/devtools/domdebugger.rb +0 -93
  102. data/lib/selenium/webdriver/devtools/domsnapshot.rb +0 -65
  103. data/lib/selenium/webdriver/devtools/domstorage.rb +0 -79
  104. data/lib/selenium/webdriver/devtools/emulation.rb +0 -180
  105. data/lib/selenium/webdriver/devtools/fetch.rb +0 -97
  106. data/lib/selenium/webdriver/devtools/headless_experimental.rb +0 -61
  107. data/lib/selenium/webdriver/devtools/heap_profiler.rb +0 -107
  108. data/lib/selenium/webdriver/devtools/indexed_db.rb +0 -100
  109. data/lib/selenium/webdriver/devtools/input.rb +0 -140
  110. data/lib/selenium/webdriver/devtools/inspector.rb +0 -55
  111. data/lib/selenium/webdriver/devtools/io.rb +0 -59
  112. data/lib/selenium/webdriver/devtools/layer_tree.rb +0 -95
  113. data/lib/selenium/webdriver/devtools/log.rb +0 -66
  114. data/lib/selenium/webdriver/devtools/media.rb +0 -57
  115. data/lib/selenium/webdriver/devtools/memory.rb +0 -86
  116. data/lib/selenium/webdriver/devtools/network.rb +0 -228
  117. data/lib/selenium/webdriver/devtools/overlay.rb +0 -157
  118. data/lib/selenium/webdriver/devtools/page.rb +0 -374
  119. data/lib/selenium/webdriver/devtools/performance.rb +0 -63
  120. data/lib/selenium/webdriver/devtools/profiler.rb +0 -111
  121. data/lib/selenium/webdriver/devtools/runtime.rb +0 -193
  122. data/lib/selenium/webdriver/devtools/schema.rb +0 -46
  123. data/lib/selenium/webdriver/devtools/security.rb +0 -71
  124. data/lib/selenium/webdriver/devtools/service_worker.rb +0 -116
  125. data/lib/selenium/webdriver/devtools/storage.rb +0 -95
  126. data/lib/selenium/webdriver/devtools/system_info.rb +0 -50
  127. data/lib/selenium/webdriver/devtools/target.rb +0 -141
  128. data/lib/selenium/webdriver/devtools/tethering.rb +0 -55
  129. data/lib/selenium/webdriver/devtools/tracing.rb +0 -76
  130. data/lib/selenium/webdriver/devtools/web_audio.rb +0 -70
  131. data/lib/selenium/webdriver/devtools/web_authn.rb +0 -94
  132. data/lib/selenium/webdriver/edge_html/options.rb +0 -84
  133. data/lib/selenium/webdriver/edge_html/service.rb +0 -47
@@ -27,12 +27,11 @@ module Selenium
27
27
  class Profile
28
28
  include ProfileHelper
29
29
 
30
- attr_reader :directory
31
-
32
30
  def initialize(model = nil)
33
31
  @model = verify_model(model)
34
32
  @extensions = []
35
33
  @encoded_extensions = []
34
+ @directory = nil
36
35
  end
37
36
 
38
37
  def add_extension(path)
@@ -45,10 +44,14 @@ module Selenium
45
44
  @encoded_extensions << encoded
46
45
  end
47
46
 
47
+ def directory
48
+ @directory || layout_on_disk
49
+ end
50
+
48
51
  #
49
52
  # Set a preference in the profile.
50
53
  #
51
- # See https://src.chromium.org/svn/trunk/src/chrome/common/pref_names.cc
54
+ # See https://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/pref_names.cc
52
55
  #
53
56
 
54
57
  def []=(key, value)
@@ -32,14 +32,16 @@ module Selenium
32
32
 
33
33
  private
34
34
 
35
- # Note: This processing is deprecated
35
+ # NOTE: This processing is deprecated
36
36
  def extract_service_args(driver_opts)
37
37
  driver_args = super
38
38
  driver_opts = driver_opts.dup
39
39
  driver_args << "--log-path=#{driver_opts.delete(:log_path)}" if driver_opts.key?(:log_path)
40
40
  driver_args << "--url-base=#{driver_opts.delete(:url_base)}" if driver_opts.key?(:url_base)
41
41
  driver_args << "--port-server=#{driver_opts.delete(:port_server)}" if driver_opts.key?(:port_server)
42
- driver_args << "--whitelisted-ips=#{driver_opts.delete(:whitelisted_ips)}" if driver_opts.key?(:whitelisted_ips)
42
+ if driver_opts.key?(:whitelisted_ips)
43
+ driver_args << "--whitelisted-ips=#{driver_opts.delete(:whitelisted_ips)}"
44
+ end
43
45
  driver_args << "--verbose" if driver_opts.key?(:verbose)
44
46
  driver_args << "--silent" if driver_opts.key?(:silent)
45
47
  driver_args
@@ -50,8 +50,6 @@ require 'selenium/webdriver/common/action_builder'
50
50
  require 'selenium/webdriver/common/html5/shared_web_storage'
51
51
  require 'selenium/webdriver/common/html5/local_storage'
52
52
  require 'selenium/webdriver/common/html5/session_storage'
53
- require 'selenium/webdriver/common/driver_extensions/takes_screenshot'
54
- require 'selenium/webdriver/common/driver_extensions/rotatable'
55
53
  require 'selenium/webdriver/common/driver_extensions/has_web_storage'
56
54
  require 'selenium/webdriver/common/driver_extensions/downloads_files'
57
55
  require 'selenium/webdriver/common/driver_extensions/has_location'
@@ -59,13 +57,21 @@ require 'selenium/webdriver/common/driver_extensions/has_session_id'
59
57
  require 'selenium/webdriver/common/driver_extensions/has_remote_status'
60
58
  require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
61
59
  require 'selenium/webdriver/common/driver_extensions/has_network_connection'
60
+ require 'selenium/webdriver/common/driver_extensions/has_network_interception'
62
61
  require 'selenium/webdriver/common/driver_extensions/has_permissions'
63
62
  require 'selenium/webdriver/common/driver_extensions/has_debugger'
63
+ require 'selenium/webdriver/common/driver_extensions/prints_page'
64
64
  require 'selenium/webdriver/common/driver_extensions/uploads_files'
65
+ require 'selenium/webdriver/common/driver_extensions/full_page_screenshot'
65
66
  require 'selenium/webdriver/common/driver_extensions/has_addons'
66
67
  require 'selenium/webdriver/common/driver_extensions/has_devtools'
68
+ require 'selenium/webdriver/common/driver_extensions/has_authentication'
69
+ require 'selenium/webdriver/common/driver_extensions/has_logs'
70
+ require 'selenium/webdriver/common/driver_extensions/has_log_events'
71
+ require 'selenium/webdriver/common/driver_extensions/has_cdp'
67
72
  require 'selenium/webdriver/common/keys'
68
73
  require 'selenium/webdriver/common/profile_helper'
69
74
  require 'selenium/webdriver/common/options'
75
+ require 'selenium/webdriver/common/takes_screenshot'
70
76
  require 'selenium/webdriver/common/driver'
71
77
  require 'selenium/webdriver/common/element'
@@ -30,6 +30,7 @@ module Selenium
30
30
 
31
31
  class Driver
32
32
  include SearchContext
33
+ include TakesScreenshot
33
34
 
34
35
  class << self
35
36
  #
@@ -52,10 +53,6 @@ module Selenium
52
53
  Firefox::Driver.new(**opts)
53
54
  when :edge
54
55
  Edge::Driver.new(**opts)
55
- when :edge_chrome
56
- EdgeChrome::Driver.new(**opts)
57
- when :edge_html
58
- EdgeHtml::Driver.new(**opts)
59
56
  when :remote
60
57
  Remote::Driver.new(**opts)
61
58
  else
@@ -74,11 +71,23 @@ module Selenium
74
71
  def initialize(bridge: nil, listener: nil, **opts)
75
72
  @service = nil
76
73
  bridge ||= create_bridge(**opts)
74
+ add_extensions(bridge.browser)
77
75
  @bridge = listener ? Support::EventFiringBridge.new(bridge, listener) : bridge
78
76
  end
79
77
 
80
78
  def inspect
81
- format '#<%<class>s:0x%<hash>x browser=%<browser>s>', class: self.class, hash: hash * 2, browser: bridge.browser.inspect
79
+ format '#<%<class>s:0x%<hash>x browser=%<browser>s>', class: self.class, hash: hash * 2,
80
+ browser: bridge.browser.inspect
81
+ end
82
+
83
+ #
84
+ # information about whether a remote end is in a state in which it can create new sessions,
85
+ # and may include additional meta information.
86
+ #
87
+ # @return [Hash]
88
+ #
89
+ def status
90
+ @bridge.status
82
91
  end
83
92
 
84
93
  #
@@ -297,7 +306,7 @@ module Selenium
297
306
  def create_bridge(**opts)
298
307
  opts[:url] ||= service_url(opts)
299
308
  caps = opts.delete(:capabilities)
300
- # Note: This is deprecated
309
+ # NOTE: This is deprecated
301
310
  cap_array = caps.is_a?(Hash) ? [caps] : Array(caps)
302
311
 
303
312
  desired_capabilities = opts.delete(:desired_capabilities)
@@ -322,7 +331,7 @@ module Selenium
322
331
  bridge_opts = {http_client: opts.delete(:http_client), url: opts.delete(:url)}
323
332
  raise ArgumentError, "Unable to create a driver with parameters: #{opts}" unless opts.empty?
324
333
 
325
- bridge = (respond_to?(:bridge_class) ? bridge_class : Remote::Bridge).new(**bridge_opts)
334
+ bridge = Remote::Bridge.new(**bridge_opts)
326
335
 
327
336
  bridge.create_session(capabilities)
328
337
  bridge
@@ -333,8 +342,9 @@ module Selenium
333
342
  if cap.is_a? Symbol
334
343
  cap = Remote::Capabilities.send(cap)
335
344
  elsif cap.is_a? Hash
345
+ new_message = 'Capabilities instance initialized with the Hash, or build values with Options class'
336
346
  WebDriver.logger.deprecate("passing a Hash value to :capabilities",
337
- 'Capabilities instance initialized with the Hash, or build values with Options class',
347
+ new_message,
338
348
  id: :capabilities_hash)
339
349
  cap = Remote::Capabilities.new(cap)
340
350
  elsif !cap.respond_to? :as_json
@@ -360,6 +370,24 @@ module Selenium
360
370
  @service = service_config.launch
361
371
  @service.uri
362
372
  end
373
+
374
+ def screenshot
375
+ bridge.screenshot
376
+ end
377
+
378
+ def add_extensions(browser)
379
+ extensions = case browser
380
+ when :chrome, :msedge
381
+ Chrome::Driver::EXTENSIONS
382
+ when :firefox
383
+ Firefox::Driver::EXTENSIONS
384
+ when :safari, :safari_technology_preview
385
+ Safari::Driver::EXTENSIONS
386
+ else
387
+ []
388
+ end
389
+ extensions.each { |extension| extend extension }
390
+ end
363
391
  end # Driver
364
392
  end # WebDriver
365
393
  end # Selenium
@@ -0,0 +1,43 @@
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
+ module DriverExtensions
23
+ module FullPageScreenshot
24
+ #
25
+ # Save a PNG screenshot of the full page to the given path
26
+ #
27
+ # @api public
28
+ #
29
+
30
+ def save_full_page_screenshot(path)
31
+ save_screenshot(path, full_page: true)
32
+ end
33
+
34
+ private
35
+
36
+ def full_screenshot
37
+ @bridge.full_screenshot
38
+ end
39
+
40
+ end # FullPageScreenshot
41
+ end # DriverExtensions
42
+ end # WebDriver
43
+ end # Selenium
@@ -0,0 +1,89 @@
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
+ module DriverExtensions
23
+ module HasAuthentication
24
+
25
+ #
26
+ # Registers basic authentication handler which is automatically
27
+ # used whenever browser gets an authentication required response.
28
+ # This currently relies on DevTools so is only supported in
29
+ # Chromium browsers.
30
+ #
31
+ # @example Authenticate any request
32
+ # driver.register(username: 'admin', password: '123456')
33
+ #
34
+ # @example Authenticate based on URL
35
+ # driver.register(username: 'admin1', password: '123456', uri: /mysite1\.com/)
36
+ # driver.register(username: 'admin2', password: '123456', uri: /mysite2\.com/)
37
+ #
38
+ # @param [String] username
39
+ # @param [String] password
40
+ # @param [Regexp] uri to associate the credentials with
41
+ #
42
+
43
+ def register(username:, password:, uri: //)
44
+ auth_handlers << {username: username, password: password, uri: uri}
45
+
46
+ devtools.network.set_cache_disabled(cache_disabled: true)
47
+ devtools.fetch.on(:auth_required) do |params|
48
+ authenticate(params['requestId'], params.dig('request', 'url'))
49
+ end
50
+ devtools.fetch.on(:request_paused) do |params|
51
+ devtools.fetch.continue_request(request_id: params['requestId'])
52
+ end
53
+ devtools.fetch.enable(handle_auth_requests: true)
54
+ end
55
+
56
+ private
57
+
58
+ def auth_handlers
59
+ @auth_handlers ||= []
60
+ end
61
+
62
+ def authenticate(request_id, url)
63
+ credentials = auth_handlers.find do |handler|
64
+ url.match?(handler[:uri])
65
+ end
66
+
67
+ if credentials
68
+ devtools.fetch.continue_with_auth(
69
+ request_id: request_id,
70
+ auth_challenge_response: {
71
+ response: 'ProvideCredentials',
72
+ username: credentials[:username],
73
+ password: credentials[:password]
74
+ }
75
+ )
76
+ else
77
+ devtools.fetch.continue_with_auth(
78
+ request_id: request_id,
79
+ auth_challenge_response: {
80
+ response: 'CancelAuth'
81
+ }
82
+ )
83
+ end
84
+ end
85
+
86
+ end # HasAuthentication
87
+ end # DriverExtensions
88
+ end # WebDriver
89
+ end # Selenium
@@ -19,21 +19,20 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- module EdgeHtml
22
+ module DriverExtensions
23
+ module HasCDP
23
24
 
24
- #
25
- # Driver implementation for Microsoft Edge.
26
- # @api private
27
- #
25
+ #
26
+ # Returns network conditions.
27
+ #
28
+ # @return [Hash]
29
+ #
28
30
 
29
- class Driver < WebDriver::Driver
30
- include DriverExtensions::HasWebStorage
31
- include DriverExtensions::TakesScreenshot
32
-
33
- def browser
34
- :edge
31
+ def execute_cdp(cmd, **params)
32
+ @bridge.send_command(cmd: cmd, params: params)
35
33
  end
36
- end # Driver
37
- end # EdgeHtml
34
+
35
+ end # HasCDP
36
+ end # DriverExtensions
38
37
  end # WebDriver
39
38
  end # Selenium
@@ -29,7 +29,12 @@ module Selenium
29
29
  #
30
30
 
31
31
  def devtools
32
- @devtools ||= DevTools.new(capabilities['goog:chromeOptions']['debuggerAddress'])
32
+ @devtools ||= begin
33
+ require 'selenium/devtools'
34
+ Selenium::DevTools.version ||= devtools_version
35
+ Selenium::DevTools.load_version
36
+ Selenium::WebDriver::DevTools.new(url: devtools_url)
37
+ end
33
38
  end
34
39
 
35
40
  end # HasDevTools
@@ -17,23 +17,20 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ # TODO: Deprecated; Delete after 4.0 release
20
21
  module Selenium
21
22
  module WebDriver
22
23
  module DriverExtensions
23
24
  module HasLocation
24
25
  def location
25
- @bridge.location
26
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support getting location'
26
27
  end
27
28
 
28
- def location=(loc)
29
- raise TypeError, "expected #{Location}, got #{loc.inspect}:#{loc.class}" unless loc.is_a?(Location)
30
-
31
- @bridge.set_location loc.latitude, loc.longitude, loc.altitude
29
+ def location=(*)
30
+ raise Error::UnsupportedOperationError, 'The W3C standard does not currently support setting location'
32
31
  end
32
+ alias_method :set_location, :location
33
33
 
34
- def set_location(lat, lon, alt)
35
- self.location = Location.new(Float(lat), Float(lon), Float(alt))
36
- end
37
34
  end # HasLocation
38
35
  end # DriverExtensions
39
36
  end # WebDriver
@@ -0,0 +1,149 @@
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
+ module DriverExtensions
23
+ module HasLogEvents
24
+ include Atoms
25
+
26
+ KINDS = %i[console exception mutation].freeze
27
+
28
+ #
29
+ # Registers listener to be called whenever browser receives
30
+ # a new Console API message such as console.log() or an unhandled
31
+ # exception.
32
+ #
33
+ # This currently relies on DevTools so is only supported in
34
+ # Chromium browsers.
35
+ #
36
+ # @example Collect console messages
37
+ # logs = []
38
+ # driver.on_log_event(:console) do |event|
39
+ # logs.push(event)
40
+ # end
41
+ #
42
+ # @example Collect JavaScript exceptions
43
+ # exceptions = []
44
+ # driver.on_log_event(:exception) do |event|
45
+ # exceptions.push(event)
46
+ # end
47
+ #
48
+ # @example Collect DOM mutations
49
+ # mutations = []
50
+ # driver.on_log_event(:mutation) do |event|
51
+ # mutations.push(event)
52
+ # end
53
+ #
54
+ # @param [Symbol] kind :console, :exception or :mutation
55
+ # @param [#call] block which is called when event happens
56
+ # @yieldparam [DevTools::ConsoleEvent, DevTools::ExceptionEvent, DevTools::MutationEvent]
57
+ #
58
+
59
+ def on_log_event(kind, &block)
60
+ raise Error::WebDriverError, "Don't know how to handle #{kind} events" unless KINDS.include?(kind)
61
+
62
+ enabled = log_listeners[kind].any?
63
+ log_listeners[kind] << block
64
+ return if enabled
65
+
66
+ devtools.runtime.enable
67
+ __send__("log_#{kind}_events")
68
+ end
69
+
70
+ private
71
+
72
+ def log_listeners
73
+ @log_listeners ||= Hash.new { |listeners, kind| listeners[kind] = [] }
74
+ end
75
+
76
+ def log_console_events
77
+ devtools.runtime.on(:console_api_called) do |params|
78
+ event = DevTools::ConsoleEvent.new(
79
+ type: params['type'],
80
+ timestamp: params['timestamp'],
81
+ args: params['args']
82
+ )
83
+
84
+ log_listeners[:console].each do |listener|
85
+ listener.call(event)
86
+ end
87
+ end
88
+ end
89
+
90
+ def log_exception_events
91
+ devtools.runtime.on(:exception_thrown) do |params|
92
+ description = if params.dig('exceptionDetails', 'exception')
93
+ params.dig('exceptionDetails', 'exception', 'description')
94
+ else
95
+ params.dig('exceptionDetails', 'text')
96
+ end
97
+
98
+ event = DevTools::ExceptionEvent.new(
99
+ description: description,
100
+ timestamp: params['timestamp'],
101
+ stacktrace: params.dig('exceptionDetails', 'stackTrace', 'callFrames')
102
+ )
103
+
104
+ log_listeners[:exception].each do |listener|
105
+ listener.call(event)
106
+ end
107
+ end
108
+ end
109
+
110
+ def log_mutation_events
111
+ devtools.page.enable
112
+
113
+ devtools.runtime.add_binding(name: '__webdriver_attribute')
114
+ execute_script(mutation_listener)
115
+ script = devtools.page.add_script_to_evaluate_on_new_document(source: mutation_listener)
116
+ pinned_scripts[mutation_listener] = script['identifier']
117
+
118
+ devtools.runtime.on(:binding_called, &method(:log_mutation_event))
119
+ end
120
+
121
+ def log_mutation_event(params)
122
+ payload = JSON.parse(params['payload'])
123
+ elements = find_elements(css: "*[data-__webdriver_id='#{payload['target']}']")
124
+ return if elements.empty?
125
+
126
+ event = DevTools::MutationEvent.new(
127
+ element: elements.first,
128
+ attribute_name: payload['name'],
129
+ current_value: payload['value'],
130
+ old_value: payload['oldValue']
131
+ )
132
+
133
+ log_listeners[:mutation].each do |log_listener|
134
+ log_listener.call(event)
135
+ end
136
+ end
137
+
138
+ def mutation_listener
139
+ @mutation_listener ||= read_atom(:mutationListener)
140
+ end
141
+
142
+ def pinned_scripts
143
+ @pinned_scripts ||= {}
144
+ end
145
+
146
+ end # HasLogEvents
147
+ end # DriverExtensions
148
+ end # WebDriver
149
+ end # Selenium