selenium-webdriver 3.142.7 → 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 (188) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +685 -5
  3. data/Gemfile +6 -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 +93 -90
  11. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  12. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  13. data/lib/selenium/webdriver/atoms/isDisplayed.js +77 -78
  14. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -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/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 +48 -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 +7 -29
  32. data/lib/selenium/webdriver/chrome.rb +5 -20
  33. data/lib/selenium/webdriver/chromium/driver.rb +60 -0
  34. data/lib/selenium/webdriver/{chrome/bridge.rb → chromium/features.rb} +48 -17
  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 +126 -238
  39. data/lib/selenium/webdriver/common/child_process.rb +124 -0
  40. data/lib/selenium/webdriver/common/driver.rb +82 -43
  41. data/lib/selenium/webdriver/common/driver_extensions/downloads_files.rb +0 -2
  42. data/lib/selenium/webdriver/common/driver_extensions/{has_location.rb → full_page_screenshot.rb} +13 -11
  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 +49 -0
  45. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +87 -0
  46. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_bidi.rb} +9 -9
  47. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +86 -0
  48. data/lib/selenium/webdriver/common/driver_extensions/has_cdp.rb +36 -0
  49. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +42 -0
  50. data/lib/selenium/webdriver/common/driver_extensions/has_debugger.rb +0 -2
  51. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +41 -0
  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 +36 -0
  54. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +143 -0
  55. data/lib/selenium/webdriver/common/driver_extensions/{has_remote_status.rb → has_logs.rb} +4 -4
  56. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +16 -1
  57. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +69 -0
  58. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -13
  59. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +75 -0
  60. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  61. data/lib/selenium/webdriver/common/driver_finder.rb +45 -0
  62. data/lib/selenium/webdriver/common/element.rb +89 -29
  63. data/lib/selenium/webdriver/common/error.rb +53 -194
  64. data/lib/selenium/webdriver/common/html5/shared_web_storage.rb +2 -2
  65. data/lib/selenium/webdriver/common/interactions/input_device.rb +10 -4
  66. data/lib/selenium/webdriver/common/interactions/interaction.rb +12 -22
  67. data/lib/selenium/webdriver/common/interactions/interactions.rb +24 -4
  68. data/lib/selenium/webdriver/common/interactions/key_actions.rb +10 -6
  69. data/lib/selenium/webdriver/common/interactions/key_input.rb +11 -27
  70. data/lib/selenium/webdriver/common/interactions/none_input.rb +10 -8
  71. data/lib/selenium/webdriver/common/interactions/pause.rb +49 -0
  72. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +71 -82
  73. data/lib/selenium/webdriver/common/interactions/pointer_cancel.rb +45 -0
  74. data/lib/selenium/webdriver/common/interactions/pointer_event_properties.rb +63 -0
  75. data/lib/selenium/webdriver/common/interactions/pointer_input.rb +15 -84
  76. data/lib/selenium/webdriver/common/interactions/pointer_move.rb +60 -0
  77. data/lib/selenium/webdriver/common/interactions/pointer_press.rb +85 -0
  78. data/lib/selenium/webdriver/common/interactions/scroll.rb +59 -0
  79. data/lib/selenium/webdriver/common/interactions/scroll_origin.rb +48 -0
  80. data/lib/selenium/webdriver/common/interactions/typing_interaction.rb +54 -0
  81. data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +113 -0
  82. data/lib/selenium/webdriver/common/{w3c_manager.rb → interactions/wheel_input.rb} +14 -17
  83. data/lib/selenium/webdriver/common/keys.rb +1 -0
  84. data/lib/selenium/webdriver/common/local_driver.rb +46 -0
  85. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  86. data/lib/selenium/webdriver/common/logger.rb +119 -19
  87. data/lib/selenium/webdriver/common/manager.rb +11 -38
  88. data/lib/selenium/webdriver/common/options.rb +154 -23
  89. data/lib/selenium/webdriver/common/platform.rb +15 -52
  90. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  91. data/lib/selenium/webdriver/common/profile_helper.rb +11 -9
  92. data/lib/selenium/webdriver/common/proxy.rb +8 -5
  93. data/lib/selenium/webdriver/common/search_context.rb +7 -9
  94. data/lib/selenium/webdriver/common/selenium_manager.rb +140 -0
  95. data/lib/selenium/webdriver/common/service.rb +26 -143
  96. data/lib/selenium/webdriver/common/service_manager.rb +144 -0
  97. data/lib/selenium/webdriver/common/shadow_root.rb +86 -0
  98. data/lib/selenium/webdriver/common/socket_lock.rb +4 -4
  99. data/lib/selenium/webdriver/common/socket_poller.rb +4 -4
  100. data/lib/selenium/webdriver/common/takes_screenshot.rb +65 -0
  101. data/lib/selenium/webdriver/common/target_locator.rb +31 -4
  102. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  103. data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +85 -0
  104. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +72 -0
  105. data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
  106. data/lib/selenium/webdriver/common/wait.rb +1 -1
  107. data/lib/selenium/webdriver/common/websocket_connection.rb +164 -0
  108. data/lib/selenium/webdriver/common/window.rb +6 -10
  109. data/lib/selenium/webdriver/common/zipper.rb +4 -10
  110. data/lib/selenium/webdriver/common.rb +43 -20
  111. data/lib/selenium/webdriver/devtools/console_event.rb +36 -0
  112. data/lib/selenium/webdriver/devtools/exception_event.rb +34 -0
  113. data/lib/selenium/webdriver/devtools/mutation_event.rb +35 -0
  114. data/lib/selenium/webdriver/devtools/network_interceptor.rb +173 -0
  115. data/lib/selenium/webdriver/devtools/pinned_script.rb +57 -0
  116. data/lib/selenium/webdriver/devtools/request.rb +65 -0
  117. data/lib/selenium/webdriver/devtools/response.rb +64 -0
  118. data/lib/selenium/webdriver/devtools.rb +96 -0
  119. data/lib/selenium/webdriver/edge/driver.rb +11 -27
  120. data/lib/selenium/webdriver/edge/features.rb +48 -0
  121. data/lib/selenium/webdriver/edge/options.rb +18 -43
  122. data/lib/selenium/webdriver/edge/profile.rb +33 -0
  123. data/lib/selenium/webdriver/edge/service.rb +8 -23
  124. data/lib/selenium/webdriver/edge.rb +11 -16
  125. data/lib/selenium/webdriver/firefox/driver.rb +38 -19
  126. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  127. data/lib/selenium/webdriver/firefox/features.rb +70 -0
  128. data/lib/selenium/webdriver/firefox/options.rb +73 -61
  129. data/lib/selenium/webdriver/firefox/profile.rb +20 -72
  130. data/lib/selenium/webdriver/firefox/service.rb +3 -25
  131. data/lib/selenium/webdriver/firefox/util.rb +1 -1
  132. data/lib/selenium/webdriver/firefox.rb +17 -28
  133. data/lib/selenium/webdriver/ie/driver.rb +5 -45
  134. data/lib/selenium/webdriver/ie/features.rb +34 -0
  135. data/lib/selenium/webdriver/ie/options.rb +14 -44
  136. data/lib/selenium/webdriver/ie/service.rb +3 -27
  137. data/lib/selenium/webdriver/ie.rb +4 -16
  138. data/lib/selenium/webdriver/remote/bridge/commands.rb +164 -0
  139. data/lib/selenium/webdriver/remote/bridge.rb +574 -88
  140. data/lib/selenium/webdriver/remote/capabilities.rb +144 -158
  141. data/lib/selenium/webdriver/remote/driver.rb +45 -14
  142. data/lib/selenium/webdriver/remote/features.rb +75 -0
  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 +24 -33
  146. data/lib/selenium/webdriver/remote/response.rb +17 -49
  147. data/lib/selenium/webdriver/remote/server_error.rb +1 -1
  148. data/lib/selenium/webdriver/remote.rb +15 -12
  149. data/lib/selenium/webdriver/safari/driver.rb +7 -29
  150. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +7 -5
  151. data/lib/selenium/webdriver/safari/options.rb +12 -27
  152. data/lib/selenium/webdriver/safari/service.rb +13 -11
  153. data/lib/selenium/webdriver/safari.rb +14 -20
  154. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  155. data/lib/selenium/webdriver/support/color.rb +24 -24
  156. data/lib/selenium/webdriver/support/event_firing_bridge.rb +5 -5
  157. data/lib/selenium/webdriver/support/guards/guard.rb +90 -0
  158. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +21 -20
  159. data/lib/selenium/webdriver/support/guards.rb +95 -0
  160. data/lib/selenium/webdriver/support/relative_locator.rb +50 -0
  161. data/lib/selenium/webdriver/support/select.rb +6 -4
  162. data/lib/selenium/webdriver/support.rb +1 -0
  163. data/lib/selenium/webdriver/version.rb +1 -1
  164. data/lib/selenium/webdriver.rb +19 -17
  165. data/selenium-webdriver.gemspec +36 -18
  166. metadata +161 -91
  167. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  168. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +0 -58
  169. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  170. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  171. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  172. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  173. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  174. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  175. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  176. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  177. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  178. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  179. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  180. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  181. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  182. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  183. data/lib/selenium/webdriver/remote/http/persistent.rb +0 -60
  184. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  185. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  186. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  187. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  188. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -18,20 +18,21 @@
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'
29
+ require 'selenium/webdriver/common/service_manager'
26
30
  require 'selenium/webdriver/common/socket_lock'
27
31
  require 'selenium/webdriver/common/socket_poller'
28
32
  require 'selenium/webdriver/common/port_prober'
29
33
  require 'selenium/webdriver/common/zipper'
30
34
  require 'selenium/webdriver/common/wait'
31
35
  require 'selenium/webdriver/common/alert'
32
- require 'selenium/webdriver/common/mouse'
33
- require 'selenium/webdriver/common/keyboard'
34
- require 'selenium/webdriver/common/touch_screen'
35
36
  require 'selenium/webdriver/common/target_locator'
36
37
  require 'selenium/webdriver/common/navigation'
37
38
  require 'selenium/webdriver/common/timeouts'
@@ -39,39 +40,61 @@ require 'selenium/webdriver/common/window'
39
40
  require 'selenium/webdriver/common/logger'
40
41
  require 'selenium/webdriver/common/logs'
41
42
  require 'selenium/webdriver/common/manager'
42
- require 'selenium/webdriver/common/w3c_manager'
43
43
  require 'selenium/webdriver/common/search_context'
44
- require 'selenium/webdriver/common/action_builder'
44
+ require 'selenium/webdriver/common/interactions/interaction'
45
+ require 'selenium/webdriver/common/interactions/interactions'
46
+ require 'selenium/webdriver/common/interactions/pointer_event_properties'
47
+ require 'selenium/webdriver/common/interactions/pointer_cancel'
48
+ require 'selenium/webdriver/common/interactions/pointer_move'
49
+ require 'selenium/webdriver/common/interactions/pointer_press'
50
+ require 'selenium/webdriver/common/interactions/typing_interaction'
51
+ require 'selenium/webdriver/common/interactions/pause'
45
52
  require 'selenium/webdriver/common/interactions/key_actions'
46
53
  require 'selenium/webdriver/common/interactions/pointer_actions'
47
- require 'selenium/webdriver/common/w3c_action_builder'
48
- require 'selenium/webdriver/common/touch_action_builder'
54
+ require 'selenium/webdriver/common/interactions/input_device'
55
+ require 'selenium/webdriver/common/interactions/none_input'
56
+ require 'selenium/webdriver/common/interactions/key_input'
57
+ require 'selenium/webdriver/common/interactions/pointer_input'
58
+ require 'selenium/webdriver/common/interactions/scroll'
59
+ require 'selenium/webdriver/common/interactions/wheel_input'
60
+ require 'selenium/webdriver/common/interactions/scroll_origin'
61
+ require 'selenium/webdriver/common/interactions/wheel_actions'
62
+ require 'selenium/webdriver/common/action_builder'
63
+ require 'selenium/webdriver/common/virtual_authenticator/credential'
64
+ require 'selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options'
65
+ require 'selenium/webdriver/common/virtual_authenticator/virtual_authenticator'
49
66
  require 'selenium/webdriver/common/html5/shared_web_storage'
50
67
  require 'selenium/webdriver/common/html5/local_storage'
51
68
  require 'selenium/webdriver/common/html5/session_storage'
52
- require 'selenium/webdriver/common/driver_extensions/takes_screenshot'
53
- require 'selenium/webdriver/common/driver_extensions/rotatable'
54
69
  require 'selenium/webdriver/common/driver_extensions/has_web_storage'
55
70
  require 'selenium/webdriver/common/driver_extensions/downloads_files'
56
- require 'selenium/webdriver/common/driver_extensions/has_location'
57
71
  require 'selenium/webdriver/common/driver_extensions/has_session_id'
58
- require 'selenium/webdriver/common/driver_extensions/has_touch_screen'
59
- require 'selenium/webdriver/common/driver_extensions/has_remote_status'
60
72
  require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
61
- require 'selenium/webdriver/common/driver_extensions/has_network_connection'
73
+ require 'selenium/webdriver/common/driver_extensions/has_network_interception'
74
+ require 'selenium/webdriver/common/driver_extensions/has_apple_permissions'
62
75
  require 'selenium/webdriver/common/driver_extensions/has_permissions'
63
76
  require 'selenium/webdriver/common/driver_extensions/has_debugger'
77
+ require 'selenium/webdriver/common/driver_extensions/has_context'
78
+ require 'selenium/webdriver/common/driver_extensions/prints_page'
64
79
  require 'selenium/webdriver/common/driver_extensions/uploads_files'
80
+ require 'selenium/webdriver/common/driver_extensions/full_page_screenshot'
65
81
  require 'selenium/webdriver/common/driver_extensions/has_addons'
66
- require 'selenium/webdriver/common/interactions/interactions'
67
- require 'selenium/webdriver/common/interactions/input_device'
68
- require 'selenium/webdriver/common/interactions/interaction'
69
- require 'selenium/webdriver/common/interactions/none_input'
70
- require 'selenium/webdriver/common/interactions/key_input'
71
- require 'selenium/webdriver/common/interactions/pointer_input'
82
+ require 'selenium/webdriver/common/driver_extensions/has_bidi'
83
+ require 'selenium/webdriver/common/driver_extensions/has_devtools'
84
+ require 'selenium/webdriver/common/driver_extensions/has_file_downloads'
85
+ require 'selenium/webdriver/common/driver_extensions/has_authentication'
86
+ require 'selenium/webdriver/common/driver_extensions/has_logs'
87
+ require 'selenium/webdriver/common/driver_extensions/has_log_events'
88
+ require 'selenium/webdriver/common/driver_extensions/has_pinned_scripts'
89
+ require 'selenium/webdriver/common/driver_extensions/has_cdp'
90
+ require 'selenium/webdriver/common/driver_extensions/has_casting'
91
+ require 'selenium/webdriver/common/driver_extensions/has_launching'
72
92
  require 'selenium/webdriver/common/keys'
73
- require 'selenium/webdriver/common/bridge_helper'
74
93
  require 'selenium/webdriver/common/profile_helper'
75
94
  require 'selenium/webdriver/common/options'
95
+ require 'selenium/webdriver/common/takes_screenshot'
76
96
  require 'selenium/webdriver/common/driver'
77
97
  require 'selenium/webdriver/common/element'
98
+ require 'selenium/webdriver/common/shadow_root'
99
+ require 'selenium/webdriver/common/websocket_connection'
100
+ require 'selenium/webdriver/common/child_process'
@@ -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