selenium-webdriver 3.142.7 → 4.10.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 (186) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +611 -5
  3. data/Gemfile +5 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  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 +94 -79
  11. data/lib/selenium/webdriver/atoms/findElements.js +121 -0
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
  14. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  15. data/lib/selenium/webdriver/atoms.rb +2 -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/bidi/log/filter_by.rb +40 -0
  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 +51 -0
  26. data/lib/selenium/webdriver/{common/keyboard.rb → bidi.rb} +21 -35
  27. data/lib/selenium/webdriver/chrome/driver.rb +9 -86
  28. data/lib/selenium/webdriver/chrome/features.rb +44 -0
  29. data/lib/selenium/webdriver/chrome/options.rb +9 -158
  30. data/lib/selenium/webdriver/chrome/profile.rb +3 -80
  31. data/lib/selenium/webdriver/chrome/service.rb +6 -33
  32. data/lib/selenium/webdriver/chrome.rb +5 -18
  33. data/lib/selenium/webdriver/chromium/driver.rb +61 -0
  34. data/lib/selenium/webdriver/{chrome/bridge.rb → chromium/features.rb} +51 -16
  35. data/lib/selenium/webdriver/chromium/options.rb +261 -0
  36. data/lib/selenium/webdriver/chromium/profile.rb +113 -0
  37. data/lib/selenium/webdriver/chromium/service.rb +42 -0
  38. data/lib/selenium/webdriver/chromium.rb +32 -0
  39. data/lib/selenium/webdriver/common/action_builder.rb +128 -238
  40. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  41. data/lib/selenium/webdriver/common/driver.rb +94 -43
  42. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  43. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +42 -0
  44. data/lib/selenium/webdriver/common/driver_extensions/has_addons.rb +0 -2
  45. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +49 -0
  46. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +87 -0
  47. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_bidi.rb} +9 -9
  48. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +86 -0
  49. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +36 -0
  50. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +42 -0
  51. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  52. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +41 -0
  53. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +36 -0
  54. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -9
  55. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +143 -0
  56. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_logs.rb} +4 -4
  57. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +16 -1
  58. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  59. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +69 -0
  60. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -13
  61. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +75 -0
  62. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  63. data/lib/selenium/webdriver/common/driver_finder.rb +47 -0
  64. data/lib/selenium/webdriver/common/element.rb +89 -29
  65. data/lib/selenium/webdriver/common/error.rb +53 -194
  66. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  67. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  68. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -22
  69. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  70. data/lib/selenium/webdriver/common/interactions/key_actions.rb +10 -6
  71. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  72. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  73. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  74. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +71 -82
  75. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  76. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  77. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  78. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  79. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  80. data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
  81. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  82. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  83. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  84. data/lib/selenium/webdriver/common/{w3c_manager.rb → interactions/wheel_input.rb} +14 -17
  85. data/lib/selenium/webdriver/common/keys.rb +1 -0
  86. data/lib/selenium/webdriver/common/local_driver.rb +55 -0
  87. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  88. data/lib/selenium/webdriver/common/logger.rb +119 -19
  89. data/lib/selenium/webdriver/common/manager.rb +11 -38
  90. data/lib/selenium/webdriver/common/options.rb +169 -23
  91. data/lib/selenium/webdriver/common/platform.rb +14 -6
  92. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  93. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  94. data/lib/selenium/webdriver/common/proxy.rb +8 -5
  95. data/lib/selenium/webdriver/common/search_context.rb +7 -9
  96. data/lib/selenium/webdriver/common/selenium_manager.rb +125 -0
  97. data/lib/selenium/webdriver/common/service.rb +26 -137
  98. data/lib/selenium/webdriver/common/service_manager.rb +144 -0
  99. data/lib/selenium/webdriver/common/shadow_root.rb +86 -0
  100. data/lib/selenium/webdriver/common/socket_lock.rb +4 -4
  101. data/lib/selenium/webdriver/common/socket_poller.rb +4 -4
  102. data/lib/selenium/webdriver/common/takes_screenshot.rb +65 -0
  103. data/lib/selenium/webdriver/common/target_locator.rb +31 -4
  104. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  105. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  106. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  107. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  108. data/lib/selenium/webdriver/common/wait.rb +1 -1
  109. data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
  110. data/lib/selenium/webdriver/common/window.rb +6 -10
  111. data/lib/selenium/webdriver/common/zipper.rb +4 -10
  112. data/lib/selenium/webdriver/common.rb +42 -18
  113. data/lib/selenium/webdriver/devtools/console_event.rb +36 -0
  114. data/lib/selenium/webdriver/devtools/exception_event.rb +34 -0
  115. data/lib/selenium/webdriver/devtools/mutation_event.rb +35 -0
  116. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  117. data/lib/selenium/webdriver/devtools/pinned_script.rb +57 -0
  118. data/lib/selenium/webdriver/devtools/request.rb +65 -0
  119. data/lib/selenium/webdriver/devtools/response.rb +64 -0
  120. data/lib/selenium/webdriver/devtools.rb +96 -0
  121. data/lib/selenium/webdriver/edge/driver.rb +11 -27
  122. data/lib/selenium/webdriver/edge/features.rb +44 -0
  123. data/lib/selenium/webdriver/edge/options.rb +18 -43
  124. data/lib/selenium/webdriver/edge/profile.rb +33 -0
  125. data/lib/selenium/webdriver/edge/service.rb +7 -27
  126. data/lib/selenium/webdriver/edge.rb +11 -14
  127. data/lib/selenium/webdriver/firefox/driver.rb +38 -19
  128. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  129. data/lib/selenium/webdriver/firefox/features.rb +66 -0
  130. data/lib/selenium/webdriver/firefox/options.rb +77 -50
  131. data/lib/selenium/webdriver/firefox/profile.rb +17 -71
  132. data/lib/selenium/webdriver/firefox/service.rb +3 -13
  133. data/lib/selenium/webdriver/firefox/util.rb +1 -1
  134. data/lib/selenium/webdriver/firefox.rb +17 -28
  135. data/lib/selenium/webdriver/ie/driver.rb +5 -45
  136. data/lib/selenium/webdriver/ie/options.rb +15 -46
  137. data/lib/selenium/webdriver/ie/service.rb +11 -19
  138. data/lib/selenium/webdriver/ie.rb +3 -16
  139. data/lib/selenium/webdriver/remote/bridge/commands.rb +170 -0
  140. data/lib/selenium/webdriver/remote/bridge.rb +592 -87
  141. data/lib/selenium/webdriver/remote/capabilities.rb +182 -124
  142. data/lib/selenium/webdriver/remote/driver.rb +30 -15
  143. data/lib/selenium/webdriver/remote/http/common.rb +3 -8
  144. data/lib/selenium/webdriver/remote/http/curb.rb +1 -3
  145. data/lib/selenium/webdriver/remote/http/default.rb +23 -31
  146. data/lib/selenium/webdriver/remote/response.rb +17 -49
  147. data/lib/selenium/webdriver/remote.rb +14 -12
  148. data/lib/selenium/webdriver/safari/driver.rb +7 -29
  149. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -5
  150. data/lib/selenium/webdriver/safari/options.rb +12 -27
  151. data/lib/selenium/webdriver/safari/service.rb +13 -11
  152. data/lib/selenium/webdriver/safari.rb +14 -20
  153. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  154. data/lib/selenium/webdriver/support/color.rb +24 -24
  155. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  156. data/lib/selenium/webdriver/support/guards/guard.rb +87 -0
  157. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +21 -20
  158. data/lib/selenium/webdriver/support/guards.rb +95 -0
  159. data/lib/selenium/webdriver/support/relative_locator.rb +50 -0
  160. data/lib/selenium/webdriver/support/select.rb +6 -4
  161. data/lib/selenium/webdriver/support.rb +1 -0
  162. data/lib/selenium/webdriver/version.rb +1 -1
  163. data/lib/selenium/webdriver.rb +18 -17
  164. data/selenium-webdriver.gemspec +36 -18
  165. metadata +159 -89
  166. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  167. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  168. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  169. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  170. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  171. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  172. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  173. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  174. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  175. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  176. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  177. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  178. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  179. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  180. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  181. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -60
  182. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  183. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  184. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  185. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  186. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -0,0 +1,36 @@
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 ConsoleEvent
24
+ attr_accessor :type, :timestamp, :args
25
+
26
+ def initialize(type:, timestamp:, args:)
27
+ @type = type.to_sym
28
+ @timestamp = Time.at(timestamp / 1000)
29
+ @args = args.map do |arg|
30
+ arg.key?('value') ? arg['value'] : arg
31
+ end
32
+ end
33
+ end # ConsoleEvent
34
+ end # DevTools
35
+ end # WebDriver
36
+ end # Selenium
@@ -0,0 +1,34 @@
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 ExceptionEvent
24
+ attr_accessor :description, :timestamp, :stacktrace
25
+
26
+ def initialize(description:, timestamp:, stacktrace:)
27
+ @description = description
28
+ @timestamp = Time.at(timestamp / 1000)
29
+ @stacktrace = stacktrace
30
+ end
31
+ end # ExceptionEvent
32
+ end # DevTools
33
+ end # WebDriver
34
+ end # Selenium
@@ -0,0 +1,35 @@
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 MutationEvent
24
+ attr_accessor :element, :attribute_name, :current_value, :old_value
25
+
26
+ def initialize(element:, attribute_name:, current_value:, old_value:)
27
+ @element = element
28
+ @attribute_name = attribute_name
29
+ @current_value = current_value
30
+ @old_value = old_value
31
+ end
32
+ end # MutationEvent
33
+ end # DevTools
34
+ end # WebDriver
35
+ end # Selenium
@@ -0,0 +1,173 @@
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
+ #
24
+ # Wraps the network request/response interception, providing
25
+ # thread-safety guarantees and handling special cases such as browser
26
+ # canceling requests midst interception.
27
+ #
28
+ # You should not be using this class directly, use Driver#intercept instead.
29
+ # @api private
30
+ #
31
+
32
+ class NetworkInterceptor
33
+ # CDP fails to get body on certain responses (301) and raises:
34
+ # "Can only get response body on requests captured after headers received."
35
+ CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE = '-32000'
36
+
37
+ # CDP fails to operate with intercepted requests.
38
+ # Typical reason is browser cancelling intercepted requests/responses.
39
+ INVALID_INTERCEPTION_ID_ERROR_CODE = '-32602'
40
+
41
+ def initialize(devtools)
42
+ @devtools = devtools
43
+ @lock = Mutex.new
44
+ end
45
+
46
+ def intercept(&block)
47
+ devtools.network.on(:loading_failed) { |params| track_cancelled_request(params) }
48
+ devtools.fetch.on(:request_paused) { |params| request_paused(params, &block) }
49
+
50
+ devtools.network.set_cache_disabled(cache_disabled: true)
51
+ devtools.network.enable
52
+ devtools.fetch.enable(patterns: [{requestStage: 'Request'}, {requestStage: 'Response'}])
53
+ end
54
+
55
+ private
56
+
57
+ attr_accessor :devtools, :lock
58
+
59
+ # We should be thread-safe to use the hash without synchronization
60
+ # because its keys are interception job identifiers and they should be
61
+ # unique within a devtools session.
62
+ def pending_response_requests
63
+ @pending_response_requests ||= {}
64
+ end
65
+
66
+ # Ensure usage of cancelled_requests is thread-safe via synchronization!
67
+ def cancelled_requests
68
+ @cancelled_requests ||= []
69
+ end
70
+
71
+ def track_cancelled_request(data)
72
+ return unless data['canceled']
73
+
74
+ lock.synchronize { cancelled_requests << data['requestId'] }
75
+ end
76
+
77
+ def request_paused(data, &block)
78
+ id = data['requestId']
79
+ network_id = data['networkId']
80
+
81
+ with_cancellable_request(network_id) do
82
+ if response?(data)
83
+ block = pending_response_requests.delete(id)
84
+ intercept_response(id, data, &block)
85
+ else
86
+ intercept_request(id, data, &block)
87
+ end
88
+ end
89
+ end
90
+
91
+ # The presence of any of these fields indicate we're at the response stage.
92
+ # @see https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#event-requestPaused
93
+ def response?(params)
94
+ params.key?('responseStatusCode') || params.key?('responseErrorReason')
95
+ end
96
+
97
+ def intercept_request(id, params, &block)
98
+ original = DevTools::Request.from(id, params)
99
+ mutable = DevTools::Request.from(id, params)
100
+
101
+ block.call(mutable) do |&continue| # rubocop:disable Performance/RedundantBlockCall
102
+ pending_response_requests[id] = continue
103
+
104
+ if original == mutable
105
+ continue_request(original.id)
106
+ else
107
+ mutate_request(mutable)
108
+ end
109
+ end
110
+ end
111
+
112
+ def intercept_response(id, params)
113
+ return continue_response(id) unless block_given?
114
+
115
+ body = fetch_response_body(id)
116
+ original = DevTools::Response.from(id, body, params)
117
+ mutable = DevTools::Response.from(id, body, params)
118
+ yield mutable
119
+
120
+ if original == mutable
121
+ continue_response(id)
122
+ else
123
+ mutate_response(mutable)
124
+ end
125
+ end
126
+
127
+ def continue_request(id)
128
+ devtools.fetch.continue_request(request_id: id)
129
+ end
130
+ alias continue_response continue_request
131
+
132
+ def mutate_request(request)
133
+ devtools.fetch.continue_request(
134
+ request_id: request.id,
135
+ url: request.url,
136
+ method: request.method,
137
+ post_data: (Base64.strict_encode64(request.post_data) if request.post_data),
138
+ headers: request.headers.map do |k, v|
139
+ {name: k, value: v}
140
+ end
141
+ )
142
+ end
143
+
144
+ def mutate_response(response)
145
+ devtools.fetch.fulfill_request(
146
+ request_id: response.id,
147
+ body: (Base64.strict_encode64(response.body) if response.body),
148
+ response_code: response.code,
149
+ response_headers: response.headers.map do |k, v|
150
+ {name: k, value: v}
151
+ end
152
+ )
153
+ end
154
+
155
+ def fetch_response_body(id)
156
+ devtools.fetch.get_response_body(request_id: id).dig('result', 'body')
157
+ rescue Error::WebDriverError => e
158
+ raise unless e.message.start_with?(CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE)
159
+ end
160
+
161
+ def with_cancellable_request(network_id)
162
+ yield
163
+ rescue Error::WebDriverError => e
164
+ raise if e.message.start_with?(INVALID_INTERCEPTION_ID_ERROR_CODE) && !cancelled?(network_id)
165
+ end
166
+
167
+ def cancelled?(network_id)
168
+ lock.synchronize { !!cancelled_requests.delete(network_id) }
169
+ end
170
+ end # NetworkInterceptor
171
+ end # DevTools
172
+ end # WebDriver
173
+ end # Selenium
@@ -0,0 +1,57 @@
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
+ attr_accessor :key, :devtools_identifier, :script
25
+
26
+ def initialize(script)
27
+ @key = SecureRandom.alphanumeric
28
+ @script = script
29
+ end
30
+
31
+ #
32
+ # @api private
33
+ #
34
+
35
+ def callable
36
+ "function __webdriver_#{key}(arguments) { #{script} }"
37
+ end
38
+
39
+ #
40
+ # @api private
41
+ #
42
+
43
+ def to_json(*)
44
+ %{"return __webdriver_#{key}(arguments)"}
45
+ end
46
+
47
+ #
48
+ # @api private
49
+ #
50
+
51
+ def remove
52
+ "__webdriver_#{key} = undefined"
53
+ end
54
+ end # PinnedScript
55
+ end # DevTools
56
+ end # WebDriver
57
+ end # Selenium
@@ -0,0 +1,65 @@
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
+ attr_accessor :url, :method, :headers, :post_data
25
+ attr_reader :id
26
+
27
+ #
28
+ # Creates request from DevTools message.
29
+ # @api private
30
+ #
31
+
32
+ def self.from(id, params)
33
+ new(
34
+ id: id,
35
+ url: params.dig('request', 'url'),
36
+ method: params.dig('request', 'method'),
37
+ headers: params.dig('request', 'headers').dup,
38
+ post_data: params.dig('request', 'postData')
39
+ )
40
+ end
41
+
42
+ def initialize(id:, url:, method:, headers:, post_data:)
43
+ @id = id
44
+ @url = url
45
+ @method = method
46
+ @headers = headers
47
+ @post_data = post_data
48
+ end
49
+
50
+ def ==(other)
51
+ self.class == other.class &&
52
+ id == other.id &&
53
+ url == other.url &&
54
+ method == other.method &&
55
+ headers == other.headers &&
56
+ post_data == other.post_data
57
+ end
58
+
59
+ def inspect
60
+ %(#<#{self.class.name} @id="#{id}" @method="#{method}" @url="#{url}")
61
+ end
62
+ end # Request
63
+ end # DevTools
64
+ end # WebDriver
65
+ end # Selenium
@@ -0,0 +1,64 @@
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
+ attr_accessor :code, :body, :headers
25
+ attr_reader :id
26
+
27
+ #
28
+ # Creates response from DevTools message.
29
+ # @api private
30
+ #
31
+
32
+ def self.from(id, encoded_body, params)
33
+ new(
34
+ id: id,
35
+ code: params['responseStatusCode'],
36
+ body: (Base64.strict_decode64(encoded_body) if encoded_body),
37
+ headers: params.fetch('responseHeaders', []).each_with_object({}) do |header, hash|
38
+ hash[header['name']] = header['value']
39
+ end
40
+ )
41
+ end
42
+
43
+ def initialize(id:, code:, body:, headers:)
44
+ @id = id
45
+ @code = code
46
+ @body = body
47
+ @headers = headers
48
+ end
49
+
50
+ def ==(other)
51
+ self.class == other.class &&
52
+ id == other.id &&
53
+ code == other.code &&
54
+ body == other.body &&
55
+ headers == other.headers
56
+ end
57
+
58
+ def inspect
59
+ %(#<#{self.class.name} @id="#{id}" @code="#{code}")
60
+ end
61
+ end # Response
62
+ end # DevTools
63
+ end # WebDriver
64
+ end # Selenium
@@ -0,0 +1,96 @@
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
+ autoload :ConsoleEvent, 'selenium/webdriver/devtools/console_event'
24
+ autoload :ExceptionEvent, 'selenium/webdriver/devtools/exception_event'
25
+ autoload :MutationEvent, 'selenium/webdriver/devtools/mutation_event'
26
+ autoload :NetworkInterceptor, 'selenium/webdriver/devtools/network_interceptor'
27
+ autoload :PinnedScript, 'selenium/webdriver/devtools/pinned_script'
28
+ autoload :Request, 'selenium/webdriver/devtools/request'
29
+ autoload :Response, 'selenium/webdriver/devtools/response'
30
+
31
+ def initialize(url:)
32
+ @ws = WebSocketConnection.new(url: url)
33
+ @session_id = nil
34
+ start_session
35
+ end
36
+
37
+ def close
38
+ @ws.close
39
+ end
40
+
41
+ def callbacks
42
+ @ws.callbacks
43
+ end
44
+
45
+ def send_cmd(method, **params)
46
+ data = {method: method, params: params.compact}
47
+ data[:sessionId] = @session_id if @session_id
48
+ message = @ws.send_cmd(**data)
49
+ raise Error::WebDriverError, error_message(message['error']) if message['error']
50
+
51
+ message
52
+ end
53
+
54
+ def method_missing(method, *_args)
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
+
66
+ return unless Object.const_defined?(desired_class)
67
+
68
+ self.class.class_eval do
69
+ define_method(method) do
70
+ Object.const_get(desired_class).new(self)
71
+ end
72
+ end
73
+
74
+ send(method)
75
+ end
76
+
77
+ def respond_to_missing?(method, *_args)
78
+ desired_class = "Selenium::DevTools::V#{Selenium::DevTools.version}::#{method.capitalize}"
79
+ Object.const_defined?(desired_class)
80
+ end
81
+
82
+ private
83
+
84
+ def start_session
85
+ targets = target.get_targets.dig('result', 'targetInfos')
86
+ page_target = targets.find { |target| target['type'] == 'page' }
87
+ session = target.attach_to_target(target_id: page_target['targetId'], flatten: true)
88
+ @session_id = session.dig('result', 'sessionId')
89
+ end
90
+
91
+ def error_message(error)
92
+ [error['code'], error['message'], error['data']].join(': ')
93
+ end
94
+ end # DevTools
95
+ end # WebDriver
96
+ end # Selenium
@@ -17,49 +17,33 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ require 'selenium/webdriver/chromium/driver'
21
+
20
22
  module Selenium
21
23
  module WebDriver
22
24
  module Edge
23
-
24
25
  #
25
26
  # Driver implementation for Microsoft Edge.
26
27
  # @api private
27
28
  #
28
29
 
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)
30
+ class Driver < Chromium::Driver
31
+ include LocalDriver
38
32
 
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)
33
+ def initialize(capabilities: nil, options: nil, service: nil, url: nil, **opts)
34
+ caps, url = initialize_local_driver(capabilities, options, service, url)
35
+ super(caps: caps, url: url, **opts)
51
36
  end
52
37
 
53
38
  def browser
54
39
  :edge
55
40
  end
56
41
 
57
- def quit
58
- super
59
- ensure
60
- @service&.stop
61
- end
42
+ private
62
43
 
44
+ def devtools_address
45
+ "http://#{capabilities['ms:edgeOptions']['debuggerAddress']}"
46
+ end
63
47
  end # Driver
64
48
  end # Edge
65
49
  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/chromium/features'
21
+
22
+ module Selenium
23
+ module WebDriver
24
+ module Edge
25
+ module Features
26
+ include WebDriver::Chromium::Features
27
+
28
+ EDGE_COMMANDS = {
29
+ get_cast_sinks: [:get, 'session/:session_id/ms/cast/get_sinks'],
30
+ set_cast_sink_to_use: [:post, 'session/:session_id/ms/cast/set_sink_to_use'],
31
+ start_cast_tab_mirroring: [:post, 'session/:session_id/ms/cast/start_tab_mirroring'],
32
+ start_cast_desktop_mirroring: [:post, 'session/:session_id/ms/cast/start_desktop_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] || CHROMIUM_COMMANDS[command] || self.class::COMMANDS[command]
40
+ end
41
+ end # Bridge
42
+ end # Edge
43
+ end # WebDriver
44
+ end # Selenium