selenium-webdriver 3.142.7 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +363 -5
  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 +69 -63
  8. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  10. data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
  11. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  12. data/lib/selenium/webdriver/chrome/driver.rb +26 -83
  13. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +50 -12
  14. data/lib/selenium/webdriver/chrome/options.rb +130 -59
  15. data/lib/selenium/webdriver/chrome/profile.rb +6 -3
  16. data/lib/selenium/webdriver/chrome/service.rb +8 -15
  17. data/lib/selenium/webdriver/chrome.rb +10 -9
  18. data/lib/selenium/webdriver/common/action_builder.rb +97 -249
  19. data/lib/selenium/webdriver/common/driver.rb +112 -23
  20. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  21. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_cdp.rb} +10 -8
  25. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
  26. data/lib/selenium/webdriver/{firefox/util.rb → common/driver_extensions/has_devtools.rb} +16 -19
  27. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  29. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
  32. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  33. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
  34. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
  35. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
  36. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  37. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  38. data/lib/selenium/webdriver/common/element.rb +82 -22
  39. data/lib/selenium/webdriver/common/error.rb +32 -196
  40. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  41. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -5
  42. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +13 -13
  43. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  44. data/lib/selenium/webdriver/common/logger.rb +50 -15
  45. data/lib/selenium/webdriver/common/manager.rb +15 -15
  46. data/lib/selenium/webdriver/common/options.rb +154 -23
  47. data/lib/selenium/webdriver/common/platform.rb +6 -1
  48. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  49. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  50. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  51. data/lib/selenium/webdriver/common/search_context.rb +7 -3
  52. data/lib/selenium/webdriver/common/service.rb +17 -125
  53. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  54. data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
  55. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  56. data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
  57. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  58. data/lib/selenium/webdriver/common/target_locator.rb +32 -4
  59. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  60. data/lib/selenium/webdriver/common/wait.rb +1 -1
  61. data/lib/selenium/webdriver/common/window.rb +0 -4
  62. data/lib/selenium/webdriver/common/zipper.rb +3 -9
  63. data/lib/selenium/webdriver/common.rb +23 -17
  64. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  65. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  66. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  67. data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
  68. data/lib/selenium/webdriver/devtools/request.rb +67 -0
  69. data/lib/selenium/webdriver/devtools/response.rb +66 -0
  70. data/lib/selenium/webdriver/devtools.rb +193 -0
  71. data/lib/selenium/webdriver/edge/driver.rb +7 -29
  72. data/lib/selenium/webdriver/edge/features.rb +44 -0
  73. data/lib/selenium/webdriver/edge/options.rb +11 -48
  74. data/lib/selenium/webdriver/{common/w3c_manager.rb → edge/profile.rb} +7 -19
  75. data/lib/selenium/webdriver/edge/service.rb +10 -26
  76. data/lib/selenium/webdriver/edge.rb +11 -14
  77. data/lib/selenium/webdriver/firefox/driver.rb +31 -19
  78. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  79. data/lib/selenium/webdriver/firefox/features.rb +66 -0
  80. data/lib/selenium/webdriver/firefox/options.rb +71 -50
  81. data/lib/selenium/webdriver/firefox/profile.rb +21 -71
  82. data/lib/selenium/webdriver/firefox/service.rb +5 -9
  83. data/lib/selenium/webdriver/firefox.rb +22 -20
  84. data/lib/selenium/webdriver/ie/driver.rb +1 -47
  85. data/lib/selenium/webdriver/ie/options.rb +15 -46
  86. data/lib/selenium/webdriver/ie/service.rb +13 -15
  87. data/lib/selenium/webdriver/ie.rb +8 -7
  88. data/lib/selenium/webdriver/remote/bridge.rb +561 -86
  89. data/lib/selenium/webdriver/remote/capabilities.rb +159 -123
  90. data/lib/selenium/webdriver/remote/commands.rb +163 -0
  91. data/lib/selenium/webdriver/remote/driver.rb +22 -12
  92. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  93. data/lib/selenium/webdriver/remote/http/default.rb +17 -20
  94. data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
  95. data/lib/selenium/webdriver/remote/response.rb +16 -47
  96. data/lib/selenium/webdriver/remote.rb +15 -12
  97. data/lib/selenium/webdriver/safari/driver.rb +3 -31
  98. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  99. data/lib/selenium/webdriver/safari/options.rb +10 -29
  100. data/lib/selenium/webdriver/safari/service.rb +4 -8
  101. data/lib/selenium/webdriver/safari.rb +17 -9
  102. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  103. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  104. data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
  105. data/lib/selenium/webdriver/support/color.rb +2 -2
  106. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  107. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  108. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +22 -19
  109. data/lib/selenium/webdriver/support/guards.rb +95 -0
  110. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  111. data/lib/selenium/webdriver/support/select.rb +3 -3
  112. data/lib/selenium/webdriver/support.rb +1 -0
  113. data/lib/selenium/webdriver/version.rb +1 -1
  114. data/lib/selenium/webdriver.rb +13 -13
  115. data/selenium-webdriver.gemspec +28 -12
  116. metadata +128 -69
  117. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  118. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  119. data/lib/selenium/webdriver/common/keyboard.rb +0 -70
  120. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  121. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  122. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  123. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  124. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  125. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  126. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  127. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  128. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  129. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  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
@@ -0,0 +1,59 @@
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
+ class DevTools
23
+ class PinnedScript
24
+
25
+ attr_accessor :key, :devtools_identifier, :script
26
+
27
+ def initialize(script)
28
+ @key = SecureRandom.alphanumeric
29
+ @script = script
30
+ end
31
+
32
+ #
33
+ # @api private
34
+ #
35
+
36
+ def callable
37
+ "function __webdriver_#{key}(arguments) { #{script} }"
38
+ end
39
+
40
+ #
41
+ # @api private
42
+ #
43
+
44
+ def to_json(*)
45
+ %{"return __webdriver_#{key}(arguments)"}
46
+ end
47
+
48
+ #
49
+ # @api private
50
+ #
51
+
52
+ def remove
53
+ "__webdriver_#{key} = undefined"
54
+ end
55
+
56
+ end # PinnedScript
57
+ end # DevTools
58
+ end # WebDriver
59
+ end # Selenium
@@ -0,0 +1,67 @@
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
+ class DevTools
23
+ class Request
24
+
25
+ attr_accessor :url, :method, :headers, :post_data
26
+ attr_reader :id
27
+
28
+ #
29
+ # Creates request from DevTools message.
30
+ # @api private
31
+ #
32
+
33
+ def self.from(id, params)
34
+ new(
35
+ id: id,
36
+ url: params.dig('request', 'url'),
37
+ method: params.dig('request', 'method'),
38
+ headers: params.dig('request', 'headers'),
39
+ post_data: params.dig('request', 'postData')
40
+ )
41
+ end
42
+
43
+ def initialize(id:, url:, method:, headers:, post_data:)
44
+ @id = id
45
+ @url = url
46
+ @method = method
47
+ @headers = headers
48
+ @post_data = post_data
49
+ end
50
+
51
+ def ==(other)
52
+ self.class == other.class &&
53
+ id == other.id &&
54
+ url == other.url &&
55
+ method == other.method &&
56
+ headers == other.headers &&
57
+ post_data == other.post_data
58
+ end
59
+
60
+ def inspect
61
+ %(#<#{self.class.name} @id="#{id}" @method="#{method}" @url="#{url}")
62
+ end
63
+
64
+ end # Request
65
+ end # DevTools
66
+ end # WebDriver
67
+ end # Selenium
@@ -0,0 +1,66 @@
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
+ class DevTools
23
+ class Response
24
+
25
+ attr_accessor :code, :body, :headers
26
+ attr_reader :id
27
+
28
+ #
29
+ # Creates response from DevTools message.
30
+ # @api private
31
+ #
32
+
33
+ def self.from(id, encoded_body, params)
34
+ new(
35
+ id: id,
36
+ code: params['responseStatusCode'],
37
+ body: (Base64.strict_decode64(encoded_body) if encoded_body),
38
+ headers: params['responseHeaders'].each_with_object({}) do |header, hash|
39
+ hash[header['name']] = header['value']
40
+ end
41
+ )
42
+ end
43
+
44
+ def initialize(id:, code:, body:, headers:)
45
+ @id = id
46
+ @code = code
47
+ @body = body
48
+ @headers = headers
49
+ end
50
+
51
+ def ==(other)
52
+ self.class == other.class &&
53
+ id == other.id &&
54
+ code == other.code &&
55
+ body == other.body &&
56
+ headers == other.headers
57
+ end
58
+
59
+ def inspect
60
+ %(#<#{self.class.name} @id="#{id}" @code="#{code}")
61
+ end
62
+
63
+ end # Response
64
+ end # DevTools
65
+ end # WebDriver
66
+ end # Selenium
@@ -0,0 +1,193 @@
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
+ class DevTools
23
+ RESPONSE_WAIT_TIMEOUT = 30
24
+ RESPONSE_WAIT_INTERVAL = 0.1
25
+
26
+ autoload :ConsoleEvent, 'selenium/webdriver/devtools/console_event'
27
+ autoload :ExceptionEvent, 'selenium/webdriver/devtools/exception_event'
28
+ autoload :MutationEvent, 'selenium/webdriver/devtools/mutation_event'
29
+ autoload :PinnedScript, 'selenium/webdriver/devtools/pinned_script'
30
+ autoload :Request, 'selenium/webdriver/devtools/request'
31
+ autoload :Response, 'selenium/webdriver/devtools/response'
32
+
33
+ def initialize(url:)
34
+ @callback_threads = ThreadGroup.new
35
+
36
+ @messages = []
37
+ @session_id = nil
38
+ @url = url
39
+
40
+ process_handshake
41
+ @socket_thread = attach_socket_listener
42
+ start_session
43
+ end
44
+
45
+ def close
46
+ @callback_threads.list.each(&:exit)
47
+ @socket_thread.exit
48
+ socket.close
49
+ end
50
+
51
+ def callbacks
52
+ @callbacks ||= Hash.new { |callbacks, event| callbacks[event] = [] }
53
+ end
54
+
55
+ def send_cmd(method, **params)
56
+ id = next_id
57
+ data = {id: id, method: method, params: params.reject { |_, v| v.nil? }}
58
+ data[:sessionId] = @session_id if @session_id
59
+ data = JSON.generate(data)
60
+ WebDriver.logger.debug "DevTools -> #{data}"
61
+
62
+ out_frame = WebSocket::Frame::Outgoing::Client.new(version: ws.version, data: data, type: 'text')
63
+ socket.write(out_frame.to_s)
64
+
65
+ message = wait.until do
66
+ @messages.find { |m| m['id'] == id }
67
+ end
68
+
69
+ raise Error::WebDriverError, error_message(message['error']) if message['error']
70
+
71
+ message
72
+ end
73
+
74
+ def method_missing(method, *_args)
75
+ desired_class = "Selenium::DevTools::V#{Selenium::DevTools.version}::#{method.capitalize}"
76
+ return unless Object.const_defined?(desired_class)
77
+
78
+ self.class.class_eval do
79
+ define_method(method) do
80
+ Object.const_get(desired_class).new(self)
81
+ end
82
+ end
83
+
84
+ send(method)
85
+ end
86
+
87
+ def respond_to_missing?(method, *_args)
88
+ desired_class = "Selenium::DevTools::V#{Selenium::DevTools.version}::#{method.capitalize}"
89
+ Object.const_defined?(desired_class)
90
+ end
91
+
92
+ private
93
+
94
+ def process_handshake
95
+ socket.print(ws.to_s)
96
+ ws << socket.readpartial(1024)
97
+ end
98
+
99
+ def attach_socket_listener
100
+ Thread.new do
101
+ Thread.current.abort_on_exception = true
102
+ Thread.current.report_on_exception = false
103
+
104
+ until socket.eof?
105
+ incoming_frame << socket.readpartial(1024)
106
+
107
+ while (frame = incoming_frame.next)
108
+ message = process_frame(frame)
109
+ next unless message['method']
110
+
111
+ params = message['params']
112
+ callbacks[message['method']].each do |callback|
113
+ @callback_threads.add(callback_thread(params, &callback))
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ def start_session
121
+ targets = target.get_targets.dig('result', 'targetInfos')
122
+ page_target = targets.find { |target| target['type'] == 'page' }
123
+ session = target.attach_to_target(target_id: page_target['targetId'], flatten: true)
124
+ @session_id = session.dig('result', 'sessionId')
125
+ end
126
+
127
+ def incoming_frame
128
+ @incoming_frame ||= WebSocket::Frame::Incoming::Client.new(version: ws.version)
129
+ end
130
+
131
+ def process_frame(frame)
132
+ message = frame.to_s
133
+
134
+ # Firefox will periodically fail on unparsable empty frame
135
+ return {} if message.empty?
136
+
137
+ message = JSON.parse(message)
138
+ @messages << message
139
+ WebDriver.logger.debug "DevTools <- #{message}"
140
+
141
+ message
142
+ end
143
+
144
+ def callback_thread(params)
145
+ Thread.new do
146
+ Thread.current.abort_on_exception = true
147
+
148
+ # We might end up blocked forever when we have an error in event.
149
+ # For example, if network interception event raises error,
150
+ # the browser will keep waiting for the request to be proceeded
151
+ # before returning back to the original thread. In this case,
152
+ # we should at least print the error.
153
+ Thread.current.report_on_exception = true
154
+
155
+ yield params
156
+ end
157
+ end
158
+
159
+ def wait
160
+ @wait ||= Wait.new(timeout: RESPONSE_WAIT_TIMEOUT, interval: RESPONSE_WAIT_INTERVAL)
161
+ end
162
+
163
+ def socket
164
+ @socket ||= begin
165
+ if URI(@url).scheme == 'wss'
166
+ socket = TCPSocket.new(ws.host, ws.port)
167
+ socket = OpenSSL::SSL::SSLSocket.new(socket, OpenSSL::SSL::SSLContext.new)
168
+ socket.sync_close = true
169
+ socket.connect
170
+
171
+ socket
172
+ else
173
+ TCPSocket.new(ws.host, ws.port)
174
+ end
175
+ end
176
+ end
177
+
178
+ def ws
179
+ @ws ||= WebSocket::Handshake::Client.new(url: @url)
180
+ end
181
+
182
+ def next_id
183
+ @id ||= 0
184
+ @id += 1
185
+ end
186
+
187
+ def error_message(error)
188
+ [error['code'], error['message'], error['data']].join(': ')
189
+ end
190
+
191
+ end # DevTools
192
+ end # WebDriver
193
+ end # Selenium
@@ -17,6 +17,8 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chrome/driver'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
24
  module Edge
@@ -26,40 +28,16 @@ module Selenium
26
28
  # @api private
27
29
  #
28
30
 
29
- class Driver < WebDriver::Driver
30
- include DriverExtensions::TakesScreenshot
31
-
32
- def initialize(opts = {})
33
- opts[:desired_capabilities] ||= Remote::Capabilities.edge
34
-
35
- opts[:url] ||= service_url(opts)
36
-
37
- listener = opts.delete(:listener)
38
-
39
- # Edge is mostly using W3C dialect, but a request to
40
- # create session responds with OSS-like body,
41
- # so we need to force W3C implementation.
42
- desired_capabilities = opts.delete(:desired_capabilities)
43
- bridge = Remote::Bridge.new(opts)
44
- capabilities = bridge.create_session(desired_capabilities)
45
-
46
- WebDriver.logger.info 'Forcing W3C dialect.'
47
- @bridge = Remote::W3C::Bridge.new(capabilities, bridge.session_id, **opts)
48
- @bridge.extend Edge::Bridge
49
-
50
- super(@bridge, listener: listener)
51
- end
52
-
31
+ class Driver < Selenium::WebDriver::Chrome::Driver
53
32
  def browser
54
33
  :edge
55
34
  end
56
35
 
57
- def quit
58
- super
59
- ensure
60
- @service&.stop
61
- end
36
+ private
62
37
 
38
+ def devtools_address
39
+ "http://#{capabilities['ms:edgeOptions']['debuggerAddress']}"
40
+ end
63
41
  end # Driver
64
42
  end # Edge
65
43
  end # WebDriver
@@ -0,0 +1,44 @@
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
+ require 'selenium/webdriver/chrome/features'
21
+
22
+ module Selenium
23
+ module WebDriver
24
+ module Edge
25
+ module Features
26
+
27
+ include WebDriver::Chrome::Features
28
+
29
+ EDGE_COMMANDS = {
30
+ get_cast_sinks: [:get, 'session/:session_id/ms/cast/get_sinks'],
31
+ set_cast_sink_to_use: [:post, 'session/:session_id/ms/cast/set_sink_to_use'],
32
+ start_cast_tab_mirroring: [:post, 'session/:session_id/ms/cast/start_tab_mirroring'],
33
+ get_cast_issue_message: [:get, 'session/:session_id/ms/cast/get_issue_message'],
34
+ stop_casting: [:post, 'session/:session_id/ms/cast/stop_casting'],
35
+ send_command: [:post, 'session/:session_id/ms/cdp/execute']
36
+ }.freeze
37
+
38
+ def commands(command)
39
+ EDGE_COMMANDS[command] || Chrome::Features::CHROME_COMMANDS[command] || self.class::COMMANDS[command]
40
+ end
41
+ end # Bridge
42
+ end # Edge
43
+ end # WebDriver
44
+ end # Selenium
@@ -17,62 +17,25 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chrome/options'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
24
  module Edge
23
- class Options
24
- attr_accessor :in_private, :start_page
25
- attr_reader :extension_paths
25
+ class Options < Selenium::WebDriver::Chrome::Options
26
+ KEY = 'ms:edgeOptions'
27
+ BROWSER = 'MicrosoftEdge'
26
28
 
27
- #
28
- # Create a new Options instance for Edge.
29
- #
30
- # @example
31
- # options = Selenium::WebDriver::Edge::Options.new(in_private: true)
32
- # driver = Selenium::WebDriver.for :edge, options: options
33
- #
34
- # @param [Hash] opts the pre-defined options to create the Edge::Options with
35
- # @option opts [Boolean] :in_private Start in private mode. Default is false
36
- # @option opts [Array<String>] :extension_paths A list of full paths to extensions to install on startup
37
- # @option opts [String] :start_page Default page to start with
38
- #
39
- # @see https://docs.microsoft.com/en-us/microsoft-edge/webdriver
40
- #
29
+ protected
41
30
 
42
- def initialize(**opts)
43
- @in_private = opts.delete(:in_private) || false
44
- @extension_paths = opts.delete(:extension_paths) || []
45
- @start_page = opts.delete(:start_page)
31
+ def enable_logging(browser_options)
32
+ browser_options['ms:loggingPrefs'] = @logging_prefs
46
33
  end
47
34
 
48
- #
49
- # Add an extension by local path.
50
- #
51
- # @example
52
- # options = Selenium::WebDriver::Edge::Options.new
53
- # options.add_extension_path('C:\path\to\extension')
54
- #
55
- # @param [String] path The local path to the extension folder
56
- #
57
-
58
- def add_extension_path(path)
59
- raise Error::WebDriverError, "could not find extension at #{path.inspect}" unless File.directory?(path)
60
-
61
- @extension_paths << path
62
- end
63
-
64
- #
65
- # @api private
66
- #
67
-
68
- def as_json(*)
69
- opts = {}
70
-
71
- opts['ms:inPrivate'] = true if @in_private
72
- opts['ms:extensionPaths'] = @extension_paths if @extension_paths.any?
73
- opts['ms:startPage'] = @start_page if @start_page
35
+ private
74
36
 
75
- opts
37
+ def binary_path
38
+ Edge.path
76
39
  end
77
40
  end # Options
78
41
  end # Edge
@@ -17,29 +17,17 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chrome/profile'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
- class W3CManager < Manager
23
-
24
- #
25
- # Get the cookie with the given name
26
- #
27
- # @param [String] name the name of the cookie
28
- # @return [Hash, nil] the cookie, or nil if it wasn't found.
24
+ module Edge
29
25
  #
30
-
31
- def cookie_named(name)
32
- convert_cookie(@bridge.cookie(name))
33
- end
34
-
26
+ # @private
35
27
  #
36
- # Delete all cookies
37
- #
38
-
39
- def delete_all_cookies
40
- @bridge.delete_all_cookies
41
- end
42
28
 
43
- end # WC3Options
29
+ class Profile < Selenium::WebDriver::Chrome::Profile
30
+ end # Profile
31
+ end # Edge
44
32
  end # WebDriver
45
33
  end # Selenium
@@ -17,36 +17,20 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chrome/service'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
24
  module Edge
23
- #
24
- # @api private
25
- #
26
-
27
- class Service < WebDriver::Service
28
- @default_port = 17556
29
- @executable = 'MicrosoftWebDriver'
30
- @missing_text = <<~ERROR
31
- Unable to find MicrosoftWebDriver. Please download the server from
32
- https://www.microsoft.com/en-us/download/details.aspx?id=48212 and place it somewhere on your PATH.
33
- More info at https://github.com/SeleniumHQ/selenium/wiki/MicrosoftWebDriver.
25
+ class Service < Selenium::WebDriver::Chrome::Service
26
+ DEFAULT_PORT = 9515
27
+ 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.
34
31
  ERROR
35
- @shutdown_supported = true
36
-
37
- private
38
-
39
- # Note: This processing is deprecated
40
- def extract_service_args(driver_opts)
41
- driver_args = super
42
- driver_opts = driver_opts.dup
43
- driver_args << "--host=#{driver_opts[:host]}" if driver_opts.key? :host
44
- driver_args << "--package=#{driver_opts[:package]}" if driver_opts.key? :package
45
- driver_args << "--silent" if driver_opts[:silent] == true
46
- driver_args << "--verbose" if driver_opts[:verbose] == true
47
- driver_args
48
- end
32
+ SHUTDOWN_SUPPORTED = true
49
33
  end # Service
50
34
  end # Edge
51
35
  end # WebDriver
52
- end # Service
36
+ end # Selenium
@@ -19,26 +19,23 @@
19
19
 
20
20
  require 'net/http'
21
21
 
22
- require 'selenium/webdriver/edge/bridge'
23
- require 'selenium/webdriver/edge/driver'
24
- require 'selenium/webdriver/edge/options'
25
-
26
22
  module Selenium
27
23
  module WebDriver
28
24
  module Edge
29
- def self.driver_path=(path)
30
- WebDriver.logger.deprecate 'Selenium::WebDriver::Edge#driver_path=',
31
- 'Selenium::WebDriver::Edge::Service#driver_path='
32
- Selenium::WebDriver::Edge::Service.driver_path = path
25
+ autoload :Features, 'selenium/webdriver/edge/features'
26
+ autoload :Driver, 'selenium/webdriver/edge/driver'
27
+ autoload :Profile, 'selenium/webdriver/edge/profile'
28
+ autoload :Options, 'selenium/webdriver/edge/options'
29
+ autoload :Service, 'selenium/webdriver/edge/service'
30
+
31
+ def self.path=(path)
32
+ Platform.assert_executable path
33
+ @path = path
33
34
  end
34
35
 
35
- def self.driver_path
36
- WebDriver.logger.deprecate 'Selenium::WebDriver::Edge#driver_path',
37
- 'Selenium::WebDriver::Edge::Service#driver_path'
38
- Selenium::WebDriver::Edge::Service.driver_path
36
+ def self.path
37
+ @path ||= nil
39
38
  end
40
39
  end # Edge
41
40
  end # WebDriver
42
41
  end # Selenium
43
-
44
- require 'selenium/webdriver/edge/service'