selenium-webdriver 3.142.1 → 4.1.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 (137) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +406 -4
  3. data/Gemfile +3 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/lib/selenium/server.rb +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 -70
  13. data/lib/selenium/webdriver/chrome/features.rb +106 -0
  14. data/lib/selenium/webdriver/chrome/options.rb +128 -53
  15. data/lib/selenium/webdriver/chrome/profile.rb +8 -5
  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 +184 -0
  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 +27 -122
  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 +24 -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/{chrome/bridge.rb → edge/features.rb} +16 -22
  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/{bridge.rb → features.rb} +23 -4
  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 +7 -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} +6 -6
  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 +29 -13
  116. metadata +125 -73
  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
@@ -20,12 +20,13 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Remote
23
+
24
+ #
23
25
  # @api private
24
- class Response
25
- STACKTRACE_KEY = 'stackTrace'
26
+ #
26
27
 
28
+ class Response
27
29
  attr_reader :code, :payload
28
- attr_writer :payload
29
30
 
30
31
  def initialize(code, payload = nil)
31
32
  @code = code
@@ -35,33 +36,16 @@ module Selenium
35
36
  end
36
37
 
37
38
  def error
38
- klass = Error.for_code(status) || return
39
+ error, message, backtrace = process_error
40
+ klass = Error.for_error(error) || return
39
41
 
40
- ex = klass.new(error_message)
42
+ ex = klass.new(message)
41
43
  ex.set_backtrace(caller)
42
- add_backtrace ex
44
+ add_backtrace ex, backtrace
43
45
 
44
46
  ex
45
47
  end
46
48
 
47
- def error_message
48
- val = value
49
-
50
- case val
51
- when Hash
52
- msg = val['message']
53
- return 'unknown error' unless msg
54
-
55
- msg << ": #{val['alert']['text'].inspect}" if val['alert'].is_a?(Hash) && val['alert']['text']
56
- msg << " (#{val['class']})" if val['class']
57
- msg
58
- when String
59
- val
60
- else
61
- "unknown error, status=#{status}: #{val.inspect}"
62
- end
63
- end
64
-
65
49
  def [](key)
66
50
  @payload[key]
67
51
  end
@@ -76,14 +60,7 @@ module Selenium
76
60
  raise Error::ServerError, self
77
61
  end
78
62
 
79
- def add_backtrace(ex)
80
- return unless error_payload.is_a?(Hash)
81
-
82
- # Legacy Firefox returns String in ['value'], while we expect Hash.
83
- # Use #dig when Firefox legacy is removed (4.0).
84
- server_trace = error_payload[STACKTRACE_KEY] ||
85
- error_payload[STACKTRACE_KEY.downcase] ||
86
- (error_payload['value'] && error_payload['value'][STACKTRACE_KEY])
63
+ def add_backtrace(ex, server_trace)
87
64
  return unless server_trace
88
65
 
89
66
  backtrace = case server_trace
@@ -113,22 +90,14 @@ module Selenium
113
90
  }.compact
114
91
  end
115
92
 
116
- def error_payload
117
- # Even errors are wrapped in 'value' for w3c
118
- # Grab 'value' key for error, leave original payload alone and let the bridge process
119
- @error_payload ||= !@payload.key?('sessionId') ? @payload['value'] : @payload
120
- end
121
-
122
- def status
123
- return unless error_payload.is_a? Hash
124
-
125
- @status ||= error_payload['status'] || error_payload['error']
126
- end
127
-
128
- def value
129
- return unless error_payload.is_a? Hash
93
+ def process_error
94
+ return unless self['value'].is_a?(Hash)
130
95
 
131
- @value ||= error_payload['value'] || error_payload['message']
96
+ [
97
+ self['value']['error'],
98
+ self['value']['message'],
99
+ self['value']['stacktrace']
100
+ ]
132
101
  end
133
102
  end # Response
134
103
  end # Remote
@@ -18,18 +18,21 @@
18
18
  # under the License.
19
19
 
20
20
  require 'uri'
21
-
22
- require 'selenium/webdriver/remote/bridge'
23
- require 'selenium/webdriver/remote/driver'
24
- require 'selenium/webdriver/remote/response'
25
21
  require 'selenium/webdriver/remote/server_error'
26
- require 'selenium/webdriver/remote/http/common'
27
- require 'selenium/webdriver/remote/http/default'
28
22
 
29
- require 'selenium/webdriver/remote/capabilities'
30
- require 'selenium/webdriver/remote/oss/bridge'
31
- require 'selenium/webdriver/remote/oss/commands'
23
+ module Selenium
24
+ module WebDriver
25
+ module Remote
26
+ autoload :Bridge, 'selenium/webdriver/remote/bridge'
27
+ autoload :Driver, 'selenium/webdriver/remote/driver'
28
+ autoload :Response, 'selenium/webdriver/remote/response'
29
+ autoload :Capabilities, 'selenium/webdriver/remote/capabilities'
30
+ autoload :COMMANDS, 'selenium/webdriver/remote/commands'
32
31
 
33
- require 'selenium/webdriver/remote/w3c/bridge'
34
- require 'selenium/webdriver/remote/w3c/capabilities'
35
- require 'selenium/webdriver/remote/w3c/commands'
32
+ module Http
33
+ autoload :Common, 'selenium/webdriver/remote/http/common'
34
+ autoload :Default, 'selenium/webdriver/remote/http/default'
35
+ end
36
+ end
37
+ end
38
+ end
@@ -27,41 +27,13 @@ module Selenium
27
27
  #
28
28
 
29
29
  class Driver < WebDriver::Driver
30
- include DriverExtensions::HasDebugger
31
- include DriverExtensions::HasPermissions
32
- include DriverExtensions::TakesScreenshot
33
-
34
- def initialize(opts = {})
35
- opts[:desired_capabilities] = create_capabilities(opts)
36
-
37
- opts[:url] ||= service_url(opts)
38
-
39
- listener = opts.delete(:listener)
40
- @bridge = Remote::Bridge.handshake(opts)
41
- @bridge.extend Bridge
42
-
43
- super(@bridge, listener: listener)
44
- end
30
+ EXTENSIONS = [DriverExtensions::HasDebugger,
31
+ DriverExtensions::HasApplePermissions,
32
+ DriverExtensions::HasWebStorage].freeze
45
33
 
46
34
  def browser
47
35
  :safari
48
36
  end
49
-
50
- def quit
51
- super
52
- ensure
53
- @service&.stop
54
- end
55
-
56
- private
57
-
58
- def create_capabilities(opts = {})
59
- caps = opts.delete(:desired_capabilities) { Remote::Capabilities.safari }
60
- options = opts.delete(:options) { Options.new }
61
- caps.merge!(options.as_json)
62
- caps
63
- end
64
-
65
37
  end # Driver
66
38
  end # Safari
67
39
  end # WebDriver
@@ -20,17 +20,17 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Safari
23
- module Bridge
23
+ module Features
24
24
 
25
25
  # https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/WebDriverEndpointDoc/Commands/Commands.html
26
- COMMANDS = {
27
- get_permissions: [:get, '/session/:session_id/apple/permissions'],
28
- set_permissions: [:post, '/session/:session_id/apple/permissions'],
29
- attach_debugger: [:post, '/session/:session_id/apple/attach_debugger']
26
+ SAFARI_COMMANDS = {
27
+ get_permissions: [:get, 'session/:session_id/apple/permissions'],
28
+ set_permissions: [:post, 'session/:session_id/apple/permissions'],
29
+ attach_debugger: [:post, 'session/:session_id/apple/attach_debugger']
30
30
  }.freeze
31
31
 
32
32
  def commands(command)
33
- COMMANDS[command] || super
33
+ SAFARI_COMMANDS[command] || self.class::COMMANDS[command]
34
34
  end
35
35
 
36
36
  def permissions
@@ -20,40 +20,21 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Safari
23
- class Options
24
- attr_accessor :automatic_inspection, :automatic_profiling
23
+ class Options < WebDriver::Options
24
+ attr_accessor :options
25
25
 
26
- #
27
- # Create a new Options instance for W3C-capable versions of Safari.
28
- #
29
- # @example
30
- # options = Selenium::WebDriver::Safari::Options.new(automatic_inspection: true)
31
- # driver = Selenium::WebDriver.for :safari, options: options
32
- #
33
- # @param [Hash] opts the pre-defined options to create the Safari::Options with
34
- # @option opts [Boolean] :automatic_inspection Preloads Web Inspector and JavaScript debugger. Default is false
35
- # @option opts [Boolean] :automatic_profiling Preloads Web Inspector and starts a timeline recording. Default is false
36
- #
37
26
  # @see https://developer.apple.com/documentation/webkit/about_webdriver_for_safari
38
- #
27
+ CAPABILITIES = {automatic_inspection: 'safari:automaticInspection',
28
+ automatic_profiling: 'safari:automaticProfiling'}.freeze
29
+ BROWSER = 'safari'
39
30
 
40
- def initialize(**opts)
41
- @automatic_inspection = opts.delete(:automatic_inspection) || false
42
- @automatic_profiling = opts.delete(:automatic_profiling) || false
43
- end
44
-
45
- #
46
- # @api private
47
- #
48
-
49
- def as_json(*)
50
- opts = {}
31
+ def add_option(name, value = nil)
32
+ key = name.is_a?(Hash) ? name.keys.first : name
33
+ raise ArgumentError, 'Safari does not support options that are not namespaced' unless key.to_s.include?(':')
51
34
 
52
- opts['safari:automaticInspection'] = true if @automatic_inspection
53
- opts['safari:automaticProfiling'] = true if @automatic_profiling
54
-
55
- opts
35
+ super
56
36
  end
37
+
57
38
  end # Options
58
39
  end # Safari
59
40
  end # WebDriver
@@ -20,18 +20,14 @@
20
20
  module Selenium
21
21
  module WebDriver
22
22
  module Safari
23
- #
24
- # @api private
25
- #
26
-
27
23
  class Service < WebDriver::Service
28
- @default_port = 7050
29
- @executable = 'safaridriver'
30
- @missing_text = <<~ERROR
24
+ DEFAULT_PORT = 7050
25
+ EXECUTABLE = 'safaridriver'
26
+ MISSING_TEXT = <<~ERROR
31
27
  Unable to find Apple's safaridriver which comes with Safari 10.
32
28
  More info at https://webkit.org/blog/6900/webdriver-support-in-safari-10/
33
29
  ERROR
34
- @shutdown_supported = false
30
+ SHUTDOWN_SUPPORTED = false
35
31
  end # Service
36
32
  end # Safari
37
33
  end # WebDriver
@@ -17,20 +17,28 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
- require 'selenium/webdriver/safari/bridge'
21
- require 'selenium/webdriver/safari/driver'
22
- require 'selenium/webdriver/safari/options'
23
-
24
20
  module Selenium
25
21
  module WebDriver
26
22
  module Safari
23
+ autoload :Features, 'selenium/webdriver/safari/features'
24
+ autoload :Driver, 'selenium/webdriver/safari/driver'
25
+ autoload :Options, 'selenium/webdriver/safari/options'
26
+ autoload :Service, 'selenium/webdriver/safari/service'
27
+
27
28
  class << self
29
+ attr_accessor :use_technology_preview
30
+
28
31
  def technology_preview
29
32
  "/Applications/Safari\ Technology\ Preview.app/Contents/MacOS/safaridriver"
30
33
  end
31
34
 
32
35
  def technology_preview!
33
- self.driver_path = technology_preview
36
+ Service.driver_path = technology_preview
37
+ @use_technology_preview = true
38
+ end
39
+
40
+ def technology_preview?
41
+ use_technology_preview
34
42
  end
35
43
 
36
44
  def path=(path)
@@ -48,18 +56,18 @@ module Selenium
48
56
 
49
57
  def driver_path=(path)
50
58
  WebDriver.logger.deprecate 'Selenium::WebDriver::Safari#driver_path=',
51
- 'Selenium::WebDriver::Safari::Service#driver_path='
59
+ 'Selenium::WebDriver::Safari::Service#driver_path=',
60
+ id: :driver_path
52
61
  Selenium::WebDriver::Safari::Service.driver_path = path
53
62
  end
54
63
 
55
64
  def driver_path
56
65
  WebDriver.logger.deprecate 'Selenium::WebDriver::Safari#driver_path',
57
- 'Selenium::WebDriver::Safari::Service#driver_path'
66
+ 'Selenium::WebDriver::Safari::Service#driver_path',
67
+ id: :driver_path
58
68
  Selenium::WebDriver::Safari::Service.driver_path
59
69
  end
60
70
  end
61
71
  end # Safari
62
72
  end # WebDriver
63
73
  end # Selenium
64
-
65
- require 'selenium/webdriver/safari/service'
@@ -25,7 +25,7 @@ module Selenium
25
25
  @callback = callback
26
26
  end
27
27
 
28
- def method_missing(meth, *args) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
28
+ def method_missing(meth, *args) # rubocop:disable Style/MissingRespondToMissing
29
29
  @callback.call meth, *args
30
30
  end
31
31
  end # BlockEventListener
@@ -0,0 +1,63 @@
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
+ # This file is automatically generated. Any changes will be lost!
21
+ module Selenium
22
+ module DevTools
23
+ module <%= version %>
24
+ class <%= domain[:domain] %>
25
+ <% if domain[:events] %>
26
+ EVENTS = {
27
+ <% domain[:events].each do |event| %>
28
+ <%= h.snake_case(event[:name]) %>: '<%= event[:name] %>',
29
+ <% end %>
30
+ }.freeze
31
+ <% end %>
32
+
33
+ def initialize(devtools)
34
+ @devtools = devtools
35
+ end
36
+
37
+ def on(event, &block)
38
+ event = EVENTS[event] if event.is_a?(Symbol)
39
+ @devtools.callbacks["<%= domain[:domain] %>.#{event}"] << block
40
+ end
41
+
42
+ <% domain[:commands].each do |command| %>
43
+ <% if command[:parameters] %>
44
+ def <%= h.snake_case(command[:name]) %>(<%= h.kwargs(command[:parameters]) %>)
45
+ <% else %>
46
+ def <%= h.snake_case(command[:name]) %>
47
+ <% end %>
48
+ <% if command[:parameters] %>
49
+ @devtools.send_cmd('<%= domain[:domain] %>.<%= command[:name] %>',
50
+ <% until command[:parameters].empty? %>
51
+ <% parameter = command[:parameters].shift %>
52
+ <%= parameter[:name] %>: <%= h.snake_case(parameter[:name]) %><%= command[:parameters].empty? ? ')' : ',' %>
53
+ <% end %>
54
+ <% else %>
55
+ @devtools.send_cmd('<%= domain[:domain] %>.<%= command[:name] %>')
56
+ <% end %>
57
+ end
58
+
59
+ <% end %>
60
+ end # <%= domain[:domain] %>
61
+ end # <%= version %>
62
+ end # DevTools
63
+ end # Selenium
@@ -0,0 +1,108 @@
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 'erb'
21
+ require 'fileutils'
22
+ require 'json'
23
+
24
+ module Selenium
25
+ module WebDriver
26
+ module Support
27
+ class CDPClientGenerator
28
+ # Input JSON files are generated from PDL tasks.
29
+ TEMPLATE_PATH = File.expand_path('cdp/domain.rb.erb', __dir__)
30
+
31
+ RESERVED_KEYWORDS = %w[end].freeze
32
+
33
+ def call(output_dir:, version:, browser_protocol_path: nil, js_protocol_path: nil, loader_path: nil, **)
34
+ @template = ERB.new(File.read(TEMPLATE_PATH))
35
+ @output_dir = output_dir
36
+ @loader_path = loader_path || "#{@output_dir}.rb"
37
+ @version = version
38
+
39
+ browser_protocol_path ||= File.expand_path('cdp/browser_protocol.json', __dir__)
40
+ js_protocol_path ||= File.expand_path('cdp/js_protocol.json', __dir__)
41
+
42
+ browser_protocol = JSON.parse(File.read(browser_protocol_path), symbolize_names: true)
43
+ js_protocol = JSON.parse(File.read(js_protocol_path), symbolize_names: true)
44
+
45
+ FileUtils.mkdir_p(@output_dir)
46
+
47
+ browser_protocol[:domains].each(&method(:process_domain))
48
+ js_protocol[:domains].each(&method(:process_domain))
49
+ require_file
50
+ end
51
+
52
+ def process_domain(domain)
53
+ result = @template.result_with_hash(domain: domain, version: @version.upcase, h: self)
54
+ filename = File.join(@output_dir, "#{snake_case(domain[:domain])}.rb")
55
+ File.write(filename, remove_empty_lines(result))
56
+ end
57
+
58
+ def snake_case(string)
59
+ name = string.gsub('JavaScript', 'Javascript')
60
+ .gsub(/([A-Z]+)([A-Z][a-z]{2,})/, '\1_\2')
61
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
62
+ .downcase
63
+ # Certain CDP parameters conflict with Ruby keywords
64
+ # so we prefix the name with underscore.
65
+ name = "_#{name}" if RESERVED_KEYWORDS.include?(name)
66
+
67
+ name
68
+ end
69
+
70
+ def kwargs(parameters)
71
+ parameters = parameters.map do |parameter|
72
+ if parameter[:optional]
73
+ "#{snake_case(parameter[:name])}: nil"
74
+ else
75
+ "#{snake_case(parameter[:name])}:"
76
+ end
77
+ end
78
+ parameters.join(', ')
79
+ end
80
+
81
+ def remove_empty_lines(string)
82
+ string.split("\n").reject { |l| l =~ /^\s+$/ }.join("\n")
83
+ end
84
+
85
+ def require_file
86
+ # rubocop:disable Lint/InterpolationCheck
87
+ dynamic_location = '#{File.dirname(File.absolute_path(__FILE__))}'
88
+ # rubocop:enable Lint/InterpolationCheck
89
+
90
+ require_all = "Dir.glob(\"#{dynamic_location}/#{@version}/*\", &method(:require))"
91
+ File.open(@loader_path, 'w') { |file| file.write(require_all) }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ if $PROGRAM_NAME == __FILE__
99
+ browser_protocol_path, js_protocol_path, output_dir, loader_path, version = *ARGV
100
+
101
+ Selenium::WebDriver::Support::CDPClientGenerator.new.call(
102
+ browser_protocol_path: browser_protocol_path,
103
+ js_protocol_path: js_protocol_path,
104
+ output_dir: output_dir,
105
+ loader_path: loader_path,
106
+ version: version
107
+ )
108
+ end
@@ -72,7 +72,7 @@ module Selenium
72
72
  end
73
73
  end
74
74
 
75
- def self.from_hsl(h, s, l, a) # rubocop:disable Naming/UncommunicativeMethodParamName
75
+ def self.from_hsl(h, s, l, a) # rubocop:disable Naming/MethodParameterName
76
76
  h = Float(h) / 360
77
77
  s = Float(s) / 100
78
78
  l = Float(l) / 100
@@ -138,7 +138,7 @@ module Selenium
138
138
  end
139
139
 
140
140
  def hex
141
- format '#%02x%02x%02x', red, green, blue
141
+ format '#%<red>02x%<green>02x%<blue>02x', red: red, green: green, blue: blue
142
142
  end
143
143
  end # Color
144
144
  end # Support
@@ -76,7 +76,7 @@ module Selenium
76
76
  @delegate.find_element_by how, what, parent
77
77
  end
78
78
 
79
- Element.new self, e.ref
79
+ Element.new self, e.ref.last
80
80
  end
81
81
 
82
82
  def find_elements_by(how, what, parent = nil)
@@ -84,7 +84,7 @@ module Selenium
84
84
  @delegate.find_elements_by(how, what, parent)
85
85
  end
86
86
 
87
- es.map { |e| Element.new self, e.ref }
87
+ es.map { |e| Element.new self, e.ref.last }
88
88
  end
89
89
 
90
90
  def execute_script(script, *args)
@@ -109,7 +109,7 @@ module Selenium
109
109
  end
110
110
 
111
111
  def driver
112
- @driver ||= Driver.new(self)
112
+ @driver ||= Driver.new(bridge: self)
113
113
  end
114
114
 
115
115
  def dispatch(name, *args)
@@ -120,7 +120,7 @@ module Selenium
120
120
  returned
121
121
  end
122
122
 
123
- def method_missing(meth, *args, &blk) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
123
+ def method_missing(meth, *args, &blk) # rubocop:disable Style/MissingRespondToMissing
124
124
  @delegate.__send__(meth, *args, &blk)
125
125
  end
126
126
  end # EventFiringBridge
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Licensed to the Software Freedom Conservancy (SFC) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The SFC licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ module Selenium
21
+ module WebDriver
22
+ module Support
23
+ class Guards
24
+
25
+ #
26
+ # Guard derived from RSpec example metadata.
27
+ # @api private
28
+ #
29
+
30
+ class Guard
31
+
32
+ attr_reader :guarded, :type, :messages, :reason
33
+
34
+ def initialize(guarded, type, guards = nil)
35
+ @guarded = guarded
36
+ @tracker = guards&.bug_tracker || ''
37
+ @messages = guards&.messages || {}
38
+ @messages[:unknown] = 'TODO: Investigate why this is failing and file a bug report'
39
+ @type = type
40
+
41
+ @reason = @guarded.delete(:reason)
42
+ end
43
+
44
+ def message
45
+ details = case @reason
46
+ when Integer
47
+ "Bug Filed: #{@tracker}/#{@reason}"
48
+ when Symbol
49
+ @messages[@reason]
50
+ when String
51
+ @reason
52
+ else
53
+ 'no reason given'
54
+ end
55
+
56
+ case @type
57
+ when :exclude
58
+ "Test not guarded because it breaks test run; #{details}"
59
+ when :exclusive
60
+ "Test does not apply to this configuration; #{details}"
61
+ else
62
+ "Test guarded; #{details}"
63
+ end
64
+ end
65
+
66
+ # Bug is present on all configurations specified
67
+ def except?
68
+ @type == :except
69
+ end
70
+
71
+ # Bug is present on all configurations not specified
72
+ def only?
73
+ @type == :only
74
+ end
75
+
76
+ # Bug is present on all configurations specified, but test can not be run because it breaks other tests
77
+ def exclude?
78
+ @type == :exclude
79
+ end
80
+
81
+ # Test only applies to configurations specified
82
+ def exclusive?
83
+ @type == :exclusive
84
+ end
85
+ end # Guard
86
+ end # Guards
87
+ end # Support
88
+ end # WebDriver
89
+ end # Selenium