selenium-webdriver 3.142.7 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +324 -5
  3. data/Gemfile +3 -1
  4. data/LICENSE +1 -1
  5. data/NOTICE +2 -0
  6. data/README.md +4 -5
  7. data/lib/selenium/server.rb +21 -29
  8. data/lib/selenium/webdriver/atoms/findElements.js +122 -0
  9. data/lib/selenium/webdriver/atoms/getAttribute.js +100 -7
  10. data/lib/selenium/webdriver/atoms/isDisplayed.js +76 -78
  11. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  12. data/lib/selenium/webdriver/chrome/driver.rb +26 -83
  13. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +50 -12
  14. data/lib/selenium/webdriver/chrome/options.rb +129 -58
  15. data/lib/selenium/webdriver/chrome/profile.rb +6 -3
  16. data/lib/selenium/webdriver/chrome/service.rb +8 -15
  17. data/lib/selenium/webdriver/chrome.rb +10 -9
  18. data/lib/selenium/webdriver/common/action_builder.rb +97 -249
  19. data/lib/selenium/webdriver/common/driver.rb +112 -23
  20. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  21. data/lib/selenium/webdriver/common/driver_extensions/has_apple_permissions.rb +51 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  23. data/lib/selenium/webdriver/common/driver_extensions/has_casting.rb +77 -0
  24. data/lib/selenium/webdriver/common/driver_extensions/{has_touch_screen.rb → has_cdp.rb} +10 -8
  25. data/lib/selenium/webdriver/common/driver_extensions/has_context.rb +45 -0
  26. data/lib/selenium/webdriver/{firefox/util.rb → common/driver_extensions/has_devtools.rb} +16 -19
  27. data/lib/selenium/webdriver/common/driver_extensions/has_launching.rb +38 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  29. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +144 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/has_network_conditions.rb +17 -0
  32. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  33. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +136 -0
  34. data/lib/selenium/webdriver/common/driver_extensions/has_permissions.rb +11 -11
  35. data/lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb +77 -0
  36. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  37. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  38. data/lib/selenium/webdriver/common/element.rb +82 -22
  39. data/lib/selenium/webdriver/common/error.rb +32 -196
  40. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  41. data/lib/selenium/webdriver/common/interactions/key_actions.rb +5 -5
  42. data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +13 -13
  43. data/lib/selenium/webdriver/common/log_entry.rb +2 -2
  44. data/lib/selenium/webdriver/common/logger.rb +50 -15
  45. data/lib/selenium/webdriver/common/manager.rb +15 -15
  46. data/lib/selenium/webdriver/common/options.rb +156 -23
  47. data/lib/selenium/webdriver/common/platform.rb +6 -1
  48. data/lib/selenium/webdriver/common/port_prober.rb +4 -6
  49. data/lib/selenium/webdriver/common/profile_helper.rb +10 -2
  50. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  51. data/lib/selenium/webdriver/common/search_context.rb +7 -3
  52. data/lib/selenium/webdriver/common/service.rb +17 -125
  53. data/lib/selenium/webdriver/common/service_manager.rb +151 -0
  54. data/lib/selenium/webdriver/common/shadow_root.rb +87 -0
  55. data/lib/selenium/webdriver/common/socket_lock.rb +2 -2
  56. data/lib/selenium/webdriver/common/socket_poller.rb +2 -2
  57. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  58. data/lib/selenium/webdriver/common/target_locator.rb +32 -4
  59. data/lib/selenium/webdriver/common/timeouts.rb +31 -4
  60. data/lib/selenium/webdriver/common/wait.rb +1 -1
  61. data/lib/selenium/webdriver/common/window.rb +0 -4
  62. data/lib/selenium/webdriver/common.rb +23 -17
  63. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  64. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  65. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  66. data/lib/selenium/webdriver/devtools/pinned_script.rb +59 -0
  67. data/lib/selenium/webdriver/devtools/request.rb +67 -0
  68. data/lib/selenium/webdriver/devtools/response.rb +66 -0
  69. data/lib/selenium/webdriver/devtools.rb +182 -0
  70. data/lib/selenium/webdriver/edge/driver.rb +7 -29
  71. data/lib/selenium/webdriver/edge/features.rb +44 -0
  72. data/lib/selenium/webdriver/edge/options.rb +11 -48
  73. data/lib/selenium/webdriver/{common/w3c_manager.rb → edge/profile.rb} +7 -19
  74. data/lib/selenium/webdriver/edge/service.rb +10 -26
  75. data/lib/selenium/webdriver/edge.rb +11 -14
  76. data/lib/selenium/webdriver/firefox/driver.rb +31 -19
  77. data/lib/selenium/webdriver/firefox/extension.rb +8 -0
  78. data/lib/selenium/webdriver/firefox/features.rb +66 -0
  79. data/lib/selenium/webdriver/firefox/options.rb +70 -49
  80. data/lib/selenium/webdriver/firefox/profile.rb +21 -71
  81. data/lib/selenium/webdriver/firefox/service.rb +5 -9
  82. data/lib/selenium/webdriver/firefox.rb +22 -20
  83. data/lib/selenium/webdriver/ie/driver.rb +1 -47
  84. data/lib/selenium/webdriver/ie/options.rb +13 -44
  85. data/lib/selenium/webdriver/ie/service.rb +13 -15
  86. data/lib/selenium/webdriver/ie.rb +8 -7
  87. data/lib/selenium/webdriver/remote/bridge.rb +558 -86
  88. data/lib/selenium/webdriver/remote/capabilities.rb +159 -123
  89. data/lib/selenium/webdriver/remote/commands.rb +163 -0
  90. data/lib/selenium/webdriver/remote/driver.rb +22 -12
  91. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  92. data/lib/selenium/webdriver/remote/http/default.rb +17 -20
  93. data/lib/selenium/webdriver/remote/http/persistent.rb +11 -6
  94. data/lib/selenium/webdriver/remote/response.rb +16 -47
  95. data/lib/selenium/webdriver/remote.rb +15 -13
  96. data/lib/selenium/webdriver/safari/driver.rb +3 -31
  97. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  98. data/lib/selenium/webdriver/safari/options.rb +10 -29
  99. data/lib/selenium/webdriver/safari/service.rb +4 -8
  100. data/lib/selenium/webdriver/safari.rb +17 -9
  101. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  102. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  103. data/lib/selenium/webdriver/support/cdp_client_generator.rb +108 -0
  104. data/lib/selenium/webdriver/support/color.rb +2 -2
  105. data/lib/selenium/webdriver/support/event_firing_bridge.rb +4 -4
  106. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  107. data/lib/selenium/webdriver/{firefox/marionette/bridge.rb → support/guards/guard_condition.rb} +22 -19
  108. data/lib/selenium/webdriver/support/guards.rb +95 -0
  109. data/lib/selenium/webdriver/support/relative_locator.rb +51 -0
  110. data/lib/selenium/webdriver/support/select.rb +3 -3
  111. data/lib/selenium/webdriver/support.rb +1 -0
  112. data/lib/selenium/webdriver/version.rb +1 -1
  113. data/lib/selenium/webdriver.rb +12 -12
  114. data/selenium-webdriver.gemspec +28 -12
  115. metadata +128 -69
  116. data/lib/selenium/webdriver/common/bridge_helper.rb +0 -82
  117. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -64
  118. data/lib/selenium/webdriver/common/keyboard.rb +0 -70
  119. data/lib/selenium/webdriver/common/mouse.rb +0 -89
  120. data/lib/selenium/webdriver/common/touch_action_builder.rb +0 -78
  121. data/lib/selenium/webdriver/common/touch_screen.rb +0 -123
  122. data/lib/selenium/webdriver/common/w3c_action_builder.rb +0 -212
  123. data/lib/selenium/webdriver/edge/bridge.rb +0 -76
  124. data/lib/selenium/webdriver/firefox/binary.rb +0 -187
  125. data/lib/selenium/webdriver/firefox/extension/prefs.json +0 -69
  126. data/lib/selenium/webdriver/firefox/extension/webdriver.xpi +0 -0
  127. data/lib/selenium/webdriver/firefox/launcher.rb +0 -111
  128. data/lib/selenium/webdriver/firefox/legacy/driver.rb +0 -83
  129. data/lib/selenium/webdriver/firefox/marionette/driver.rb +0 -90
  130. data/lib/selenium/webdriver/firefox/native/linux/amd64/x_ignore_nofocus.so +0 -0
  131. data/lib/selenium/webdriver/firefox/native/linux/x86/x_ignore_nofocus.so +0 -0
  132. data/lib/selenium/webdriver/remote/oss/bridge.rb +0 -594
  133. data/lib/selenium/webdriver/remote/oss/commands.rb +0 -223
  134. data/lib/selenium/webdriver/remote/w3c/bridge.rb +0 -605
  135. data/lib/selenium/webdriver/remote/w3c/capabilities.rb +0 -310
  136. data/lib/selenium/webdriver/remote/w3c/commands.rb +0 -157
@@ -28,8 +28,7 @@ module Selenium
28
28
  class Default < Common
29
29
  attr_writer :proxy
30
30
 
31
- attr_accessor :open_timeout
32
- attr_accessor :read_timeout
31
+ attr_accessor :open_timeout, :read_timeout
33
32
 
34
33
  # Initializes object.
35
34
  # Warning: Setting {#open_timeout} to non-nil values will cause a separate thread to spawn.
@@ -39,15 +38,7 @@ module Selenium
39
38
  def initialize(open_timeout: nil, read_timeout: nil)
40
39
  @open_timeout = open_timeout
41
40
  @read_timeout = read_timeout
42
- end
43
-
44
- # Maintaining backward compatibility.
45
- # @param [Numeric] value - Timeout in seconds to apply to both open timeout and read timeouts.
46
- # @deprecated Please set the specific desired timeout {#read_timeout} or {#open_timeout} directly.
47
- def timeout=(value)
48
- WebDriver.logger.deprecate ':timeout=', '#read_timeout= and #open_timeout='
49
- self.open_timeout = value
50
- self.read_timeout = value
41
+ super()
51
42
  end
52
43
 
53
44
  def close
@@ -64,14 +55,18 @@ module Selenium
64
55
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
65
56
  end
66
57
 
67
- # Defaulting open_timeout to nil to be consistent with Ruby 2.2 and earlier.
68
- http.open_timeout = open_timeout
58
+ http.open_timeout = open_timeout if open_timeout
69
59
  http.read_timeout = read_timeout if read_timeout
70
60
 
71
- http.start
61
+ start(http)
62
+ http
72
63
  end
73
64
  end
74
65
 
66
+ def start(http)
67
+ http.start
68
+ end
69
+
75
70
  MAX_RETRIES = 3
76
71
 
77
72
  def request(verb, url, headers, payload, redirects = 0)
@@ -93,15 +88,15 @@ module Selenium
93
88
  retries += 1
94
89
  sleep 2
95
90
  retry
96
- rescue Errno::EADDRNOTAVAIL => ex
91
+ rescue Errno::EADDRNOTAVAIL => e
97
92
  # a retry is sometimes needed when the port becomes temporarily unavailable
98
93
  raise if retries >= MAX_RETRIES
99
94
 
100
95
  retries += 1
101
96
  sleep 2
102
97
  retry
103
- rescue Errno::ECONNREFUSED => ex
104
- raise ex.class, "using proxy: #{proxy.http}" if use_proxy?
98
+ rescue Errno::ECONNREFUSED => e
99
+ raise e.class, "using proxy: #{proxy.http}" if use_proxy?
105
100
 
106
101
  raise
107
102
  end
@@ -132,12 +127,14 @@ module Selenium
132
127
  def new_http_client
133
128
  if use_proxy?
134
129
  url = @proxy.http
135
- raise Error::WebDriverError, "expected HTTP proxy, got #{@proxy.inspect}" unless proxy.respond_to?(:http) && url
130
+ unless proxy.respond_to?(:http) && url
131
+ raise Error::WebDriverError,
132
+ "expected HTTP proxy, got #{@proxy.inspect}"
133
+ end
136
134
 
137
135
  proxy = URI.parse(url)
138
136
 
139
- clazz = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password)
140
- clazz.new(server_url.host, server_url.port)
137
+ Net::HTTP.new(server_url.host, server_url.port, proxy.host, proxy.port, proxy.user, proxy.password)
141
138
  else
142
139
  Net::HTTP.new server_url.host, server_url.port
143
140
  end
@@ -25,12 +25,22 @@ module Selenium
25
25
  module Http
26
26
  # @api private
27
27
  class Persistent < Default
28
+ def initialize(open_timeout: nil, read_timeout: nil)
29
+ WebDriver.logger.deprecate("Selenium::WebDriver::Remote::Http::Persistent",
30
+ id: :http_persistent) { "The default HTTP client now uses persistence." }
31
+ super
32
+ end
33
+
28
34
  def close
29
35
  @http&.shutdown
30
36
  end
31
37
 
32
38
  private
33
39
 
40
+ def start(*)
41
+ # no need to explicitly start connection
42
+ end
43
+
34
44
  def new_http_client
35
45
  proxy = nil
36
46
 
@@ -42,12 +52,7 @@ module Selenium
42
52
  proxy = URI.parse(url)
43
53
  end
44
54
 
45
- if Net::HTTP::Persistent::VERSION >= '3'
46
- Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
47
- else
48
- WebDriver.logger.warn 'Support for this version of net-http-persistent is deprecated. Please upgrade.'
49
- Net::HTTP::Persistent.new 'webdriver', proxy
50
- end
55
+ Net::HTTP::Persistent.new name: 'webdriver', proxy: proxy
51
56
  end
52
57
 
53
58
  def response_for(request)
@@ -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,20 @@
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
-
29
- require 'selenium/webdriver/remote/capabilities'
30
- require 'selenium/webdriver/remote/oss/bridge'
31
- require 'selenium/webdriver/remote/oss/commands'
32
22
 
33
- require 'selenium/webdriver/remote/w3c/bridge'
34
- require 'selenium/webdriver/remote/w3c/capabilities'
35
- require 'selenium/webdriver/remote/w3c/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'
31
+ module Http
32
+ autoload :Common, 'selenium/webdriver/remote/http/common'
33
+ autoload :Default, 'selenium/webdriver/remote/http/default'
34
+ end
35
+ end
36
+ end
37
+ 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 = {
26
+ SAFARI_COMMANDS = {
27
27
  get_permissions: [:get, 'session/:session_id/apple/permissions'],
28
28
  set_permissions: [:post, 'session/:session_id/apple/permissions'],
29
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