selenium-webdriver 4.5.0 → 4.16.0

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +219 -1
  3. data/Gemfile +3 -0
  4. data/LICENSE +1 -1
  5. data/NOTICE +1 -1
  6. data/README.md +2 -2
  7. data/bin/linux/selenium-manager +0 -0
  8. data/bin/macos/selenium-manager +0 -0
  9. data/bin/windows/selenium-manager.exe +0 -0
  10. data/lib/selenium/server.rb +8 -22
  11. data/lib/selenium/webdriver/atoms/findElements.js +5 -5
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +0 -0
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +2 -1
  14. data/lib/selenium/webdriver/atoms/mutationListener.js +0 -0
  15. data/lib/selenium/webdriver/atoms.rb +5 -3
  16. data/lib/selenium/webdriver/bidi/browsing_context.rb +88 -0
  17. data/lib/selenium/webdriver/bidi/browsing_context_info.rb +35 -0
  18. data/lib/selenium/webdriver/bidi/log/base_log_entry.rb +35 -0
  19. data/lib/selenium/webdriver/bidi/log/console_log_entry.rb +35 -0
  20. data/lib/selenium/webdriver/{common/driver_extensions/has_location.rb → bidi/log/filter_by.rb} +14 -11
  21. data/lib/selenium/webdriver/bidi/log/generic_log_entry.rb +33 -0
  22. data/lib/selenium/webdriver/bidi/log/javascript_log_entry.rb +33 -0
  23. data/lib/selenium/webdriver/bidi/log_inspector.rb +143 -0
  24. data/lib/selenium/webdriver/bidi/navigate_result.rb +33 -0
  25. data/lib/selenium/webdriver/bidi/session.rb +13 -0
  26. data/lib/selenium/webdriver/bidi.rb +3 -2
  27. data/lib/selenium/webdriver/chrome/driver.rb +9 -30
  28. data/lib/selenium/webdriver/chrome/features.rb +8 -71
  29. data/lib/selenium/webdriver/chrome/options.rb +3 -237
  30. data/lib/selenium/webdriver/chrome/profile.rb +3 -83
  31. data/lib/selenium/webdriver/chrome/service.rb +4 -19
  32. data/lib/selenium/webdriver/chrome.rb +0 -2
  33. data/lib/selenium/webdriver/chromium/driver.rb +60 -0
  34. data/lib/selenium/webdriver/chromium/features.rb +99 -0
  35. data/lib/selenium/webdriver/chromium/options.rb +243 -0
  36. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  37. data/lib/selenium/webdriver/chromium.rb +29 -0
  38. data/lib/selenium/webdriver/common/action_builder.rb +11 -58
  39. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  40. data/lib/selenium/webdriver/common/driver.rb +19 -36
  41. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  42. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +0 -1
  43. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  44. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +0 -2
  45. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +0 -2
  46. data/lib/selenium/webdriver/common/driver_extensions/has_bidi.rb +0 -2
  47. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +0 -1
  48. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +0 -2
  49. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +0 -2
  50. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  51. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +0 -2
  52. data/lib/selenium/webdriver/common/driver_extensions/has_file_downloads.rb +65 -0
  53. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +0 -2
  54. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +0 -1
  55. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +0 -2
  56. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +0 -2
  57. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +0 -2
  58. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +0 -2
  59. data/lib/selenium/webdriver/common/driver_finder.rb +45 -0
  60. data/lib/selenium/webdriver/common/element.rb +6 -6
  61. data/lib/selenium/webdriver/common/error.rb +27 -4
  62. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  63. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +3 -3
  64. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +2 -2
  65. data/lib/selenium/webdriver/common/interactions/scroll.rb +7 -5
  66. data/lib/selenium/webdriver/common/local_driver.rb +46 -0
  67. data/lib/selenium/webdriver/common/logger.rb +91 -26
  68. data/lib/selenium/webdriver/common/options.rb +15 -8
  69. data/lib/selenium/webdriver/common/platform.rb +8 -49
  70. data/lib/selenium/webdriver/common/port_prober.rb +1 -1
  71. data/lib/selenium/webdriver/common/profile_helper.rb +1 -1
  72. data/lib/selenium/webdriver/common/proxy.rb +2 -2
  73. data/lib/selenium/webdriver/common/selenium_manager.rb +140 -0
  74. data/lib/selenium/webdriver/common/service.rb +21 -30
  75. data/lib/selenium/webdriver/common/service_manager.rb +6 -12
  76. data/lib/selenium/webdriver/common/shadow_root.rb +1 -2
  77. data/lib/selenium/webdriver/common/socket_lock.rb +3 -3
  78. data/lib/selenium/webdriver/common/socket_poller.rb +1 -1
  79. data/lib/selenium/webdriver/common/takes_screenshot.rb +2 -3
  80. data/lib/selenium/webdriver/common/target_locator.rb +2 -3
  81. data/lib/selenium/webdriver/common/timeouts.rb +2 -2
  82. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +8 -6
  83. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +0 -1
  84. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +16 -16
  85. data/lib/selenium/webdriver/common/websocket_connection.rb +12 -4
  86. data/lib/selenium/webdriver/common.rb +5 -2
  87. data/lib/selenium/webdriver/devtools/console_event.rb +0 -2
  88. data/lib/selenium/webdriver/devtools/exception_event.rb +0 -2
  89. data/lib/selenium/webdriver/devtools/mutation_event.rb +0 -2
  90. data/lib/selenium/webdriver/devtools/network_interceptor.rb +4 -7
  91. data/lib/selenium/webdriver/devtools/pinned_script.rb +0 -2
  92. data/lib/selenium/webdriver/devtools/request.rb +0 -2
  93. data/lib/selenium/webdriver/devtools/response.rb +0 -2
  94. data/lib/selenium/webdriver/devtools.rb +11 -2
  95. data/lib/selenium/webdriver/edge/driver.rb +9 -3
  96. data/lib/selenium/webdriver/edge/features.rb +7 -4
  97. data/lib/selenium/webdriver/edge/options.rb +17 -5
  98. data/lib/selenium/webdriver/edge/profile.rb +2 -2
  99. data/lib/selenium/webdriver/edge/service.rb +8 -7
  100. data/lib/selenium/webdriver/edge.rb +0 -2
  101. data/lib/selenium/webdriver/firefox/driver.rb +8 -2
  102. data/lib/selenium/webdriver/firefox/features.rb +5 -2
  103. data/lib/selenium/webdriver/firefox/options.rb +2 -14
  104. data/lib/selenium/webdriver/firefox/profile.rb +10 -8
  105. data/lib/selenium/webdriver/firefox/service.rb +0 -18
  106. data/lib/selenium/webdriver/ie/driver.rb +7 -1
  107. data/lib/selenium/webdriver/{common/driver_extensions/has_network_connection.rb → ie/features.rb} +8 -11
  108. data/lib/selenium/webdriver/ie/options.rb +4 -3
  109. data/lib/selenium/webdriver/ie/service.rb +0 -22
  110. data/lib/selenium/webdriver/ie.rb +4 -3
  111. data/lib/selenium/webdriver/remote/{commands.rb → bridge/commands.rb} +0 -8
  112. data/lib/selenium/webdriver/remote/bridge.rb +13 -37
  113. data/lib/selenium/webdriver/remote/capabilities.rb +3 -53
  114. data/lib/selenium/webdriver/remote/driver.rb +35 -13
  115. data/lib/selenium/webdriver/remote/features.rb +75 -0
  116. data/lib/selenium/webdriver/remote/http/common.rb +3 -3
  117. data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
  118. data/lib/selenium/webdriver/remote/http/default.rb +2 -2
  119. data/lib/selenium/webdriver/remote/response.rb +0 -1
  120. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  121. data/lib/selenium/webdriver/remote.rb +1 -1
  122. data/lib/selenium/webdriver/safari/driver.rb +7 -1
  123. data/lib/selenium/webdriver/safari/features.rb +5 -3
  124. data/lib/selenium/webdriver/safari/options.rb +5 -1
  125. data/lib/selenium/webdriver/safari/service.rb +10 -4
  126. data/lib/selenium/webdriver/safari.rb +1 -1
  127. data/lib/selenium/webdriver/support/color.rb +17 -17
  128. data/lib/selenium/webdriver/support/event_firing_bridge.rb +2 -2
  129. data/lib/selenium/webdriver/support/guards/guard.rb +6 -5
  130. data/lib/selenium/webdriver/support/guards/guard_condition.rb +0 -2
  131. data/lib/selenium/webdriver/support/guards.rb +1 -1
  132. data/lib/selenium/webdriver/support/relative_locator.rb +0 -1
  133. data/lib/selenium/webdriver/support/select.rb +2 -5
  134. data/lib/selenium/webdriver/version.rb +1 -1
  135. data/lib/selenium/webdriver.rb +5 -4
  136. data/selenium-webdriver.gemspec +10 -11
  137. metadata +43 -84
  138. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +0 -63
  139. data/lib/selenium/webdriver/support/cdp_client_generator.rb +0 -108
@@ -40,7 +40,8 @@ module Selenium
40
40
  @executable_path = config.executable_path
41
41
  @host = Platform.localhost
42
42
  @port = config.port
43
- @extra_args = config.extra_args
43
+ @io = config.log
44
+ @extra_args = config.args
44
45
  @shutdown_supported = config.shutdown_supported
45
46
 
46
47
  raise Error::WebDriverError, "invalid port: #{@port}" if @port < 1
@@ -64,7 +65,7 @@ module Selenium
64
65
 
65
66
  stop_server
66
67
  @process.poll_for_exit STOP_TIMEOUT
67
- rescue ChildProcess::TimeoutError
68
+ rescue ChildProcess::TimeoutError, Errno::ECONNREFUSED
68
69
  nil # noop
69
70
  ensure
70
71
  stop_process
@@ -77,14 +78,10 @@ module Selenium
77
78
  private
78
79
 
79
80
  def build_process(*command)
80
- WebDriver.logger.debug("Executing Process #{command}")
81
+ WebDriver.logger.debug("Executing Process #{command}", id: :driver_service)
81
82
  @process = ChildProcess.build(*command)
82
- if WebDriver.logger.debug?
83
- @process.io.stdout = @process.io.stderr = WebDriver.logger.io
84
- elsif Platform.jruby?
85
- # Apparently we need to read the output of drivers on JRuby.
86
- @process.io.stdout = @process.io.stderr = File.new(Platform.null_device, 'w')
87
- end
83
+ @io ||= WebDriver.logger.io if WebDriver.logger.debug?
84
+ @process.io = @io if @io
88
85
 
89
86
  @process
90
87
  end
@@ -104,8 +101,6 @@ module Selenium
104
101
 
105
102
  def start_process
106
103
  @process = build_process(@executable_path, "--port=#{@port}", *@extra_args)
107
- # NOTE: this is a bug only in Windows 7
108
- @process.leader = true unless Platform.windows?
109
104
  @process.start
110
105
  end
111
106
 
@@ -113,7 +108,6 @@ module Selenium
113
108
  return if process_exited?
114
109
 
115
110
  @process.stop STOP_TIMEOUT
116
- @process.io.stdout.close if Platform.jruby? && !WebDriver.logger.debug?
117
111
  end
118
112
 
119
113
  def stop_server
@@ -42,7 +42,7 @@ module Selenium
42
42
  def ==(other)
43
43
  other.is_a?(self.class) && ref == other.ref
44
44
  end
45
- alias_method :eql?, :==
45
+ alias eql? ==
46
46
 
47
47
  def hash
48
48
  [@id, @bridge].hash
@@ -81,7 +81,6 @@ module Selenium
81
81
  private
82
82
 
83
83
  attr_reader :bridge
84
-
85
84
  end # ShadowRoot
86
85
  end # WebDriver
87
86
  end # Selenium
@@ -26,6 +26,7 @@ module Selenium
26
26
  class SocketLock
27
27
  def initialize(port, timeout)
28
28
  @port = port
29
+ @server = nil
29
30
  @timeout = timeout
30
31
  end
31
32
 
@@ -66,11 +67,10 @@ module Selenium
66
67
 
67
68
  def can_lock?
68
69
  @server = TCPServer.new(Platform.localhost, @port)
69
- ChildProcess.close_on_exec @server
70
-
70
+ @server.close_on_exec = true
71
71
  true
72
72
  rescue SocketError, Errno::EADDRINUSE, Errno::EBADF => e
73
- WebDriver.logger.debug("#{self}: #{e.message}")
73
+ WebDriver.logger.debug("#{self}: #{e.message}", id: :driver_service)
74
74
  false
75
75
  end
76
76
 
@@ -93,7 +93,7 @@ module Selenium
93
93
  true
94
94
  rescue *NOT_CONNECTED_ERRORS
95
95
  sock&.close
96
- WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}")
96
+ WebDriver.logger.debug("polling for socket on #{[@host, @port].inspect}", id: :driver_service)
97
97
  false
98
98
  end
99
99
  end
@@ -32,8 +32,8 @@ module Selenium
32
32
  def save_screenshot(png_path, full_page: false)
33
33
  extension = File.extname(png_path).downcase
34
34
  if extension != '.png'
35
- WebDriver.logger.warn "name used for saved screenshot does not match file type. " \
36
- "It should end with .png extension",
35
+ WebDriver.logger.warn 'name used for saved screenshot does not match file type. ' \
36
+ 'It should end with .png extension',
37
37
  id: :screenshot
38
38
  end
39
39
  File.open(png_path, 'wb') { |f| f << screenshot_as(:png, full_page: full_page) }
@@ -60,7 +60,6 @@ module Selenium
60
60
  rescue NameError
61
61
  raise Error::UnsupportedOperationError, "Full Page Screenshots are not supported for #{inspect}"
62
62
  end
63
-
64
63
  end # TakesScreenshot
65
64
  end # WebDriver
66
65
  end # Selenium
@@ -51,9 +51,8 @@ module Selenium
51
51
  #
52
52
 
53
53
  def new_window(type = :window)
54
- unless %i[window tab].include?(type)
55
- raise ArgumentError, "Valid types are :tab and :window, received: #{type.inspect}"
56
- end
54
+ raise ArgumentError, "Valid types are :tab and :window, received: #{type.inspect}" unless %i[window
55
+ tab].include?(type)
57
56
 
58
57
  handle = @bridge.new_window(type)['handle']
59
58
 
@@ -48,7 +48,7 @@ module Selenium
48
48
  def script
49
49
  Float(@bridge.timeouts['script']) / 1000
50
50
  end
51
- alias_method :script_timeout, :script
51
+ alias script_timeout script
52
52
 
53
53
  #
54
54
  # Sets the amount of time to wait for an asynchronous script to finish
@@ -59,7 +59,7 @@ module Selenium
59
59
  def script=(seconds)
60
60
  @bridge.timeouts = {'script' => Integer(seconds * 1000)}
61
61
  end
62
- alias_method :script_timeout=, :script=
62
+ alias script_timeout= script=
63
63
 
64
64
  #
65
65
  # Gets the amount of time to wait for a page load to complete before throwing an error.
@@ -44,8 +44,8 @@ module Selenium
44
44
 
45
45
  def from_json(opts)
46
46
  user_handle = opts['userHandle'] ? decode(opts['userHandle']) : nil
47
- new(id: decode(opts["credentialId"]),
48
- resident_credential: opts["isResidentCredential"],
47
+ new(id: decode(opts['credentialId']),
48
+ resident_credential: opts['isResidentCredential'],
49
49
  rp_id: opts['rpId'],
50
50
  private_key: opts['privateKey'],
51
51
  sign_count: opts['signCount'],
@@ -54,15 +54,17 @@ module Selenium
54
54
  end
55
55
 
56
56
  attr_reader :id, :resident_credential, :rp_id, :user_handle, :private_key, :sign_count
57
- alias_method :resident_credential?, :resident_credential
57
+ alias resident_credential? resident_credential
58
58
 
59
- def initialize(id:, resident_credential:, rp_id:, private_key:, user_handle: nil, sign_count: 0)
59
+ def initialize(id:, resident_credential:, rp_id:, private_key:, **opts)
60
60
  @id = id
61
61
  @resident_credential = resident_credential
62
62
  @rp_id = rp_id
63
- @user_handle = user_handle
63
+ @user_handle = opts.delete(:user_handle) { nil }
64
64
  @private_key = private_key
65
- @sign_count = sign_count
65
+ @sign_count = opts.delete(:sign_count) { 0 }
66
+
67
+ raise ArgumentError, "Invalid arguments: #{opts.keys}" unless opts.empty?
66
68
  end
67
69
 
68
70
  #
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  class VirtualAuthenticator
23
-
24
23
  attr_reader :options
25
24
 
26
25
  #
@@ -25,24 +25,24 @@
25
25
  module Selenium
26
26
  module WebDriver
27
27
  class VirtualAuthenticatorOptions
28
-
29
- PROTOCOL = {ctap2: "ctap2", u2f: "ctap1/u2f"}.freeze
30
- TRANSPORT = {ble: "ble", usb: "usb", nfc: "nfc", internal: "internal"}.freeze
28
+ PROTOCOL = {ctap2: 'ctap2', u2f: 'ctap1/u2f'}.freeze
29
+ TRANSPORT = {ble: 'ble', usb: 'usb', nfc: 'nfc', internal: 'internal'}.freeze
31
30
 
32
31
  attr_accessor :protocol, :transport, :resident_key, :user_verification, :user_consenting, :user_verified
33
- alias_method :resident_key?, :resident_key
34
- alias_method :user_verification?, :user_verification
35
- alias_method :user_consenting?, :user_consenting
36
- alias_method :user_verified?, :user_verified
37
-
38
- def initialize(protocol: :ctap2, transport: :usb, resident_key: false,
39
- user_verification: false, user_consenting: true, user_verified: false)
40
- @protocol = protocol
41
- @transport = transport
42
- @resident_key = resident_key
43
- @user_verification = user_verification
44
- @user_consenting = user_consenting
45
- @user_verified = user_verified
32
+ alias resident_key? resident_key
33
+ alias user_verification? user_verification
34
+ alias user_consenting? user_consenting
35
+ alias user_verified? user_verified
36
+
37
+ def initialize(**opts)
38
+ @protocol = opts.delete(:protocol) { :ctap2 }
39
+ @transport = opts.delete(:transport) { :usb }
40
+ @resident_key = opts.delete(:resident_key) { false }
41
+ @user_verification = opts.delete(:user_verification) { false }
42
+ @user_consenting = opts.delete(:user_consenting) { true }
43
+ @user_verified = opts.delete(:user_verified) { false }
44
+
45
+ raise ArgumentError, "Invalid arguments: #{opts.keys}" unless opts.empty?
46
46
  end
47
47
 
48
48
  #
@@ -22,6 +22,11 @@ require 'websocket'
22
22
  module Selenium
23
23
  module WebDriver
24
24
  class WebSocketConnection
25
+ CONNECTION_ERRORS = [
26
+ Errno::ECONNRESET, # connection is aborted (browser process was killed)
27
+ Errno::EPIPE # broken pipe (browser process was killed)
28
+ ].freeze
29
+
25
30
  RESPONSE_WAIT_TIMEOUT = 30
26
31
  RESPONSE_WAIT_INTERVAL = 0.1
27
32
 
@@ -50,7 +55,7 @@ module Selenium
50
55
  def send_cmd(**payload)
51
56
  id = next_id
52
57
  data = payload.merge(id: id)
53
- WebDriver.logger.debug "WebSocket -> #{data}"[...MAX_LOG_MESSAGE_SIZE]
58
+ WebDriver.logger.debug "WebSocket -> #{data}"[...MAX_LOG_MESSAGE_SIZE], id: :bidi
54
59
  data = JSON.generate(data)
55
60
  out_frame = WebSocket::Frame::Outgoing::Client.new(version: ws.version, data: data, type: 'text')
56
61
  socket.write(out_frame.to_s)
@@ -90,6 +95,8 @@ module Selenium
90
95
  end
91
96
  end
92
97
  end
98
+ rescue *CONNECTION_ERRORS
99
+ Thread.stop
93
100
  end
94
101
  end
95
102
 
@@ -104,8 +111,8 @@ module Selenium
104
111
  return {} if message.empty?
105
112
 
106
113
  message = JSON.parse(message)
107
- messages[message["id"]] = message
108
- WebDriver.logger.debug "WebSocket <- #{message}"[...MAX_LOG_MESSAGE_SIZE]
114
+ messages[message['id']] = message
115
+ WebDriver.logger.debug "WebSocket <- #{message}"[...MAX_LOG_MESSAGE_SIZE], id: :bidi
109
116
 
110
117
  message
111
118
  end
@@ -122,6 +129,8 @@ module Selenium
122
129
  Thread.current.report_on_exception = true
123
130
 
124
131
  yield params
132
+ rescue Error::WebDriverError, *CONNECTION_ERRORS
133
+ Thread.stop
125
134
  end
126
135
  end
127
136
 
@@ -150,7 +159,6 @@ module Selenium
150
159
  @id ||= 0
151
160
  @id += 1
152
161
  end
153
-
154
162
  end # BiDi
155
163
  end # WebDriver
156
164
  end # Selenium
@@ -18,10 +18,13 @@
18
18
  # under the License.
19
19
 
20
20
  require 'selenium/webdriver/common/error'
21
+ require 'selenium/webdriver/common/local_driver'
22
+ require 'selenium/webdriver/common/driver_finder'
21
23
  require 'selenium/webdriver/common/platform'
22
24
  require 'selenium/webdriver/common/proxy'
23
25
  require 'selenium/webdriver/common/log_entry'
24
26
  require 'selenium/webdriver/common/file_reaper'
27
+ require 'selenium/webdriver/common/selenium_manager'
25
28
  require 'selenium/webdriver/common/service'
26
29
  require 'selenium/webdriver/common/service_manager'
27
30
  require 'selenium/webdriver/common/socket_lock'
@@ -65,10 +68,8 @@ require 'selenium/webdriver/common/html5/local_storage'
65
68
  require 'selenium/webdriver/common/html5/session_storage'
66
69
  require 'selenium/webdriver/common/driver_extensions/has_web_storage'
67
70
  require 'selenium/webdriver/common/driver_extensions/downloads_files'
68
- require 'selenium/webdriver/common/driver_extensions/has_location'
69
71
  require 'selenium/webdriver/common/driver_extensions/has_session_id'
70
72
  require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
71
- require 'selenium/webdriver/common/driver_extensions/has_network_connection'
72
73
  require 'selenium/webdriver/common/driver_extensions/has_network_interception'
73
74
  require 'selenium/webdriver/common/driver_extensions/has_apple_permissions'
74
75
  require 'selenium/webdriver/common/driver_extensions/has_permissions'
@@ -80,6 +81,7 @@ require 'selenium/webdriver/common/driver_extensions/full_page_screenshot'
80
81
  require 'selenium/webdriver/common/driver_extensions/has_addons'
81
82
  require 'selenium/webdriver/common/driver_extensions/has_bidi'
82
83
  require 'selenium/webdriver/common/driver_extensions/has_devtools'
84
+ require 'selenium/webdriver/common/driver_extensions/has_file_downloads'
83
85
  require 'selenium/webdriver/common/driver_extensions/has_authentication'
84
86
  require 'selenium/webdriver/common/driver_extensions/has_logs'
85
87
  require 'selenium/webdriver/common/driver_extensions/has_log_events'
@@ -95,3 +97,4 @@ require 'selenium/webdriver/common/driver'
95
97
  require 'selenium/webdriver/common/element'
96
98
  require 'selenium/webdriver/common/shadow_root'
97
99
  require 'selenium/webdriver/common/websocket_connection'
100
+ require 'selenium/webdriver/common/child_process'
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class ConsoleEvent
24
-
25
24
  attr_accessor :type, :timestamp, :args
26
25
 
27
26
  def initialize(type:, timestamp:, args:)
@@ -31,7 +30,6 @@ module Selenium
31
30
  arg.key?('value') ? arg['value'] : arg
32
31
  end
33
32
  end
34
-
35
33
  end # ConsoleEvent
36
34
  end # DevTools
37
35
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class ExceptionEvent
24
-
25
24
  attr_accessor :description, :timestamp, :stacktrace
26
25
 
27
26
  def initialize(description:, timestamp:, stacktrace:)
@@ -29,7 +28,6 @@ module Selenium
29
28
  @timestamp = Time.at(timestamp / 1000)
30
29
  @stacktrace = stacktrace
31
30
  end
32
-
33
31
  end # ExceptionEvent
34
32
  end # DevTools
35
33
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class MutationEvent
24
-
25
24
  attr_accessor :element, :attribute_name, :current_value, :old_value
26
25
 
27
26
  def initialize(element:, attribute_name:, current_value:, old_value:)
@@ -30,7 +29,6 @@ module Selenium
30
29
  @current_value = current_value
31
30
  @old_value = old_value
32
31
  end
33
-
34
32
  end # MutationEvent
35
33
  end # DevTools
36
34
  end # WebDriver
@@ -20,7 +20,6 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
-
24
23
  #
25
24
  # Wraps the network request/response interception, providing
26
25
  # thread-safety guarantees and handling special cases such as browser
@@ -31,14 +30,13 @@ module Selenium
31
30
  #
32
31
 
33
32
  class NetworkInterceptor
34
-
35
33
  # CDP fails to get body on certain responses (301) and raises:
36
34
  # "Can only get response body on requests captured after headers received."
37
- CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE = "-32000"
35
+ CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE = '-32000'
38
36
 
39
37
  # CDP fails to operate with intercepted requests.
40
38
  # Typical reason is browser cancelling intercepted requests/responses.
41
- INVALID_INTERCEPTION_ID_ERROR_CODE = "-32602"
39
+ INVALID_INTERCEPTION_ID_ERROR_CODE = '-32602'
42
40
 
43
41
  def initialize(devtools)
44
42
  @devtools = devtools
@@ -129,14 +127,14 @@ module Selenium
129
127
  def continue_request(id)
130
128
  devtools.fetch.continue_request(request_id: id)
131
129
  end
132
- alias_method :continue_response, :continue_request
130
+ alias continue_response continue_request
133
131
 
134
132
  def mutate_request(request)
135
133
  devtools.fetch.continue_request(
136
134
  request_id: request.id,
137
135
  url: request.url,
138
136
  method: request.method,
139
- post_data: request.post_data,
137
+ post_data: (Base64.strict_encode64(request.post_data) if request.post_data),
140
138
  headers: request.headers.map do |k, v|
141
139
  {name: k, value: v}
142
140
  end
@@ -169,7 +167,6 @@ module Selenium
169
167
  def cancelled?(network_id)
170
168
  lock.synchronize { !!cancelled_requests.delete(network_id) }
171
169
  end
172
-
173
170
  end # NetworkInterceptor
174
171
  end # DevTools
175
172
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class PinnedScript
24
-
25
24
  attr_accessor :key, :devtools_identifier, :script
26
25
 
27
26
  def initialize(script)
@@ -52,7 +51,6 @@ module Selenium
52
51
  def remove
53
52
  "__webdriver_#{key} = undefined"
54
53
  end
55
-
56
54
  end # PinnedScript
57
55
  end # DevTools
58
56
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class Request
24
-
25
24
  attr_accessor :url, :method, :headers, :post_data
26
25
  attr_reader :id
27
26
 
@@ -60,7 +59,6 @@ module Selenium
60
59
  def inspect
61
60
  %(#<#{self.class.name} @id="#{id}" @method="#{method}" @url="#{url}")
62
61
  end
63
-
64
62
  end # Request
65
63
  end # DevTools
66
64
  end # WebDriver
@@ -21,7 +21,6 @@ module Selenium
21
21
  module WebDriver
22
22
  class DevTools
23
23
  class Response
24
-
25
24
  attr_accessor :code, :body, :headers
26
25
  attr_reader :id
27
26
 
@@ -59,7 +58,6 @@ module Selenium
59
58
  def inspect
60
59
  %(#<#{self.class.name} @id="#{id}" @code="#{code}")
61
60
  end
62
-
63
61
  end # Response
64
62
  end # DevTools
65
63
  end # WebDriver
@@ -52,7 +52,17 @@ module Selenium
52
52
  end
53
53
 
54
54
  def method_missing(method, *_args)
55
- desired_class = "Selenium::DevTools::V#{Selenium::DevTools.version}::#{method.capitalize}"
55
+ namespace = "Selenium::DevTools::V#{Selenium::DevTools.version}"
56
+ methods_to_classes = "#{namespace}::METHODS_TO_CLASSES"
57
+
58
+ desired_class = if Object.const_defined?(methods_to_classes)
59
+ # selenium-devtools 0.113 and newer
60
+ "#{namespace}::#{Object.const_get(methods_to_classes)[method]}"
61
+ else
62
+ # selenium-devtools 0.112 and older
63
+ "#{namespace}::#{method.capitalize}"
64
+ end
65
+
56
66
  return unless Object.const_defined?(desired_class)
57
67
 
58
68
  self.class.class_eval do
@@ -81,7 +91,6 @@ module Selenium
81
91
  def error_message(error)
82
92
  [error['code'], error['message'], error['data']].join(': ')
83
93
  end
84
-
85
94
  end # DevTools
86
95
  end # WebDriver
87
96
  end # Selenium
@@ -17,18 +17,24 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/chrome/driver'
20
+ require 'selenium/webdriver/chromium/driver'
21
21
 
22
22
  module Selenium
23
23
  module WebDriver
24
24
  module Edge
25
-
26
25
  #
27
26
  # Driver implementation for Microsoft Edge.
28
27
  # @api private
29
28
  #
30
29
 
31
- class Driver < Selenium::WebDriver::Chrome::Driver
30
+ class Driver < Chromium::Driver
31
+ include LocalDriver
32
+
33
+ def initialize(options: nil, service: nil, url: nil, **opts)
34
+ caps, url = initialize_local_driver(options, service, url)
35
+ super(caps: caps, url: url, **opts)
36
+ end
37
+
32
38
  def browser
33
39
  :edge
34
40
  end
@@ -17,14 +17,13 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/chrome/features'
20
+ require 'selenium/webdriver/chromium/features'
21
21
 
22
22
  module Selenium
23
23
  module WebDriver
24
24
  module Edge
25
25
  module Features
26
-
27
- include WebDriver::Chrome::Features
26
+ include WebDriver::Chromium::Features
28
27
 
29
28
  EDGE_COMMANDS = {
30
29
  get_cast_sinks: [:get, 'session/:session_id/ms/cast/get_sinks'],
@@ -36,8 +35,12 @@ module Selenium
36
35
  send_command: [:post, 'session/:session_id/ms/cdp/execute']
37
36
  }.freeze
38
37
 
38
+ def command_list
39
+ EDGE_COMMANDS.merge(CHROMIUM_COMMANDS).merge(self.class::COMMANDS)
40
+ end
41
+
39
42
  def commands(command)
40
- EDGE_COMMANDS[command] || Chrome::Features::CHROME_COMMANDS[command] || self.class::COMMANDS[command]
43
+ command_list[command]
41
44
  end
42
45
  end # Bridge
43
46
  end # Edge
@@ -17,23 +17,35 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/chrome/options'
20
+ require 'selenium/webdriver/chromium/options'
21
21
 
22
22
  module Selenium
23
23
  module WebDriver
24
24
  module Edge
25
- class Options < Selenium::WebDriver::Chrome::Options
25
+ class Options < Chromium::Options
26
26
  KEY = 'ms:edgeOptions'
27
27
  BROWSER = 'MicrosoftEdge'
28
28
 
29
- protected
29
+ #
30
+ # Changes the browser name enable webview2
31
+ # see: https://learn.microsoft.com/en-us/microsoft-edge/webview2/how-to/webdriver
32
+ # Automation of WebView2 apps with Microsoft Edge WebDriver
33
+ #
34
+ # @example Enable webview2
35
+ # options = Selenium::WebDriver::Edge::Options.new
36
+ # options.webview2!
37
+ #
30
38
 
31
- def enable_logging(browser_options)
32
- browser_options['ms:loggingPrefs'] = @logging_prefs
39
+ def webview2!
40
+ @options[:browser_name] = 'webview2'
33
41
  end
34
42
 
35
43
  private
36
44
 
45
+ def enable_logging(browser_options)
46
+ browser_options['ms:loggingPrefs'] = @logging_prefs
47
+ end
48
+
37
49
  def binary_path
38
50
  Edge.path
39
51
  end
@@ -17,7 +17,7 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/chrome/profile'
20
+ require 'selenium/webdriver/chromium/profile'
21
21
 
22
22
  module Selenium
23
23
  module WebDriver
@@ -26,7 +26,7 @@ module Selenium
26
26
  # @private
27
27
  #
28
28
 
29
- class Profile < Selenium::WebDriver::Chrome::Profile
29
+ class Profile < Chromium::Profile
30
30
  end # Profile
31
31
  end # Edge
32
32
  end # WebDriver
@@ -17,19 +17,20 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/chrome/service'
21
-
22
20
  module Selenium
23
21
  module WebDriver
24
22
  module Edge
25
- class Service < Selenium::WebDriver::Chrome::Service
23
+ class Service < WebDriver::Service
26
24
  DEFAULT_PORT = 9515
27
25
  EXECUTABLE = 'msedgedriver'
28
- MISSING_TEXT = <<~ERROR
29
- Unable to find msedgedriver. Please download the server from
30
- https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ and place it somewhere on your PATH.
31
- ERROR
32
26
  SHUTDOWN_SUPPORTED = true
27
+
28
+ def log
29
+ return @log unless @log.is_a? String
30
+
31
+ @args << "--log-path=#{@log}"
32
+ @log = nil
33
+ end
33
34
  end # Service
34
35
  end # Edge
35
36
  end # WebDriver