selenium-webdriver 4.0.0.alpha6 → 4.0.0.beta4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +137 -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 +18 -26
  8. data/lib/selenium/webdriver.rb +1 -4
  9. data/lib/selenium/webdriver/atoms/findElements.js +93 -93
  10. data/lib/selenium/webdriver/atoms/getAttribute.js +75 -59
  11. data/lib/selenium/webdriver/atoms/isDisplayed.js +72 -72
  12. data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
  13. data/lib/selenium/webdriver/chrome.rb +1 -1
  14. data/lib/selenium/webdriver/chrome/driver.rb +25 -10
  15. data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +3 -3
  16. data/lib/selenium/webdriver/chrome/options.rb +51 -39
  17. data/lib/selenium/webdriver/chrome/profile.rb +6 -3
  18. data/lib/selenium/webdriver/chrome/service.rb +4 -2
  19. data/lib/selenium/webdriver/common.rb +8 -2
  20. data/lib/selenium/webdriver/common/driver.rb +36 -8
  21. data/lib/selenium/webdriver/common/driver_extensions/full_page_screenshot.rb +43 -0
  22. data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
  23. data/lib/selenium/webdriver/{edge_html/driver.rb → common/driver_extensions/has_cdp.rb} +12 -13
  24. data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +6 -1
  25. data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
  26. data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +149 -0
  27. data/lib/selenium/webdriver/common/driver_extensions/has_logs.rb +30 -0
  28. data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
  29. data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +67 -0
  30. data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
  31. data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
  32. data/lib/selenium/webdriver/common/element.rb +66 -12
  33. data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
  34. data/lib/selenium/webdriver/common/logger.rb +5 -2
  35. data/lib/selenium/webdriver/common/manager.rb +6 -1
  36. data/lib/selenium/webdriver/common/options.rb +76 -14
  37. data/lib/selenium/webdriver/common/platform.rb +3 -1
  38. data/lib/selenium/webdriver/common/proxy.rb +6 -3
  39. data/lib/selenium/webdriver/common/search_context.rb +4 -1
  40. data/lib/selenium/webdriver/common/service.rb +1 -8
  41. data/lib/selenium/webdriver/common/service_manager.rb +1 -1
  42. data/lib/selenium/webdriver/common/socket_poller.rb +19 -30
  43. data/lib/selenium/webdriver/common/takes_screenshot.rb +66 -0
  44. data/lib/selenium/webdriver/common/target_locator.rb +4 -4
  45. data/lib/selenium/webdriver/devtools.rb +44 -18
  46. data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
  47. data/lib/selenium/webdriver/devtools/exception_event.rb +36 -0
  48. data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
  49. data/lib/selenium/webdriver/devtools/{console.rb → request.rb} +22 -22
  50. data/lib/selenium/webdriver/edge.rb +7 -29
  51. data/lib/selenium/webdriver/{edge_chrome → edge}/driver.rb +8 -6
  52. data/lib/selenium/webdriver/{edge_chrome/bridge.rb → edge/features.rb} +9 -7
  53. data/lib/selenium/webdriver/{edge_chrome → edge}/options.rb +11 -4
  54. data/lib/selenium/webdriver/{edge_chrome → edge}/profile.rb +2 -2
  55. data/lib/selenium/webdriver/{edge_chrome → edge}/service.rb +2 -2
  56. data/lib/selenium/webdriver/firefox.rb +5 -1
  57. data/lib/selenium/webdriver/firefox/driver.rb +18 -5
  58. data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +9 -4
  59. data/lib/selenium/webdriver/firefox/options.rb +20 -21
  60. data/lib/selenium/webdriver/firefox/profile.rb +12 -2
  61. data/lib/selenium/webdriver/firefox/service.rb +1 -1
  62. data/lib/selenium/webdriver/ie/driver.rb +1 -2
  63. data/lib/selenium/webdriver/ie/options.rb +1 -11
  64. data/lib/selenium/webdriver/ie/service.rb +4 -2
  65. data/lib/selenium/webdriver/remote/bridge.rb +48 -30
  66. data/lib/selenium/webdriver/remote/capabilities.rb +105 -64
  67. data/lib/selenium/webdriver/remote/commands.rb +3 -0
  68. data/lib/selenium/webdriver/remote/driver.rb +10 -3
  69. data/lib/selenium/webdriver/remote/http/common.rb +0 -5
  70. data/lib/selenium/webdriver/remote/http/default.rb +8 -7
  71. data/lib/selenium/webdriver/remote/http/persistent.rb +6 -0
  72. data/lib/selenium/webdriver/safari.rb +8 -1
  73. data/lib/selenium/webdriver/safari/driver.rb +3 -8
  74. data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
  75. data/lib/selenium/webdriver/safari/options.rb +0 -25
  76. data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
  77. data/lib/selenium/webdriver/support/cdp/domain.rb.erb +63 -0
  78. data/lib/selenium/webdriver/support/cdp_client_generator.rb +44 -13
  79. data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
  80. data/lib/selenium/webdriver/support/guards.rb +95 -0
  81. data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
  82. data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
  83. data/lib/selenium/webdriver/support/select.rb +2 -2
  84. data/lib/selenium/webdriver/version.rb +1 -1
  85. data/selenium-webdriver.gemspec +26 -12
  86. metadata +91 -108
  87. data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -65
  88. data/lib/selenium/webdriver/devtools/accessibility.rb +0 -62
  89. data/lib/selenium/webdriver/devtools/animation.rb +0 -98
  90. data/lib/selenium/webdriver/devtools/application_cache.rb +0 -64
  91. data/lib/selenium/webdriver/devtools/audits.rb +0 -61
  92. data/lib/selenium/webdriver/devtools/background_service.rb +0 -67
  93. data/lib/selenium/webdriver/devtools/browser.rb +0 -123
  94. data/lib/selenium/webdriver/devtools/cache_storage.rb +0 -73
  95. data/lib/selenium/webdriver/devtools/cast.rb +0 -70
  96. data/lib/selenium/webdriver/devtools/css.rb +0 -165
  97. data/lib/selenium/webdriver/devtools/database.rb +0 -64
  98. data/lib/selenium/webdriver/devtools/debugger.rb +0 -229
  99. data/lib/selenium/webdriver/devtools/device_orientation.rb +0 -53
  100. data/lib/selenium/webdriver/devtools/dom.rb +0 -320
  101. data/lib/selenium/webdriver/devtools/domdebugger.rb +0 -93
  102. data/lib/selenium/webdriver/devtools/domsnapshot.rb +0 -65
  103. data/lib/selenium/webdriver/devtools/domstorage.rb +0 -79
  104. data/lib/selenium/webdriver/devtools/emulation.rb +0 -180
  105. data/lib/selenium/webdriver/devtools/fetch.rb +0 -97
  106. data/lib/selenium/webdriver/devtools/headless_experimental.rb +0 -61
  107. data/lib/selenium/webdriver/devtools/heap_profiler.rb +0 -107
  108. data/lib/selenium/webdriver/devtools/indexed_db.rb +0 -100
  109. data/lib/selenium/webdriver/devtools/input.rb +0 -140
  110. data/lib/selenium/webdriver/devtools/inspector.rb +0 -55
  111. data/lib/selenium/webdriver/devtools/io.rb +0 -59
  112. data/lib/selenium/webdriver/devtools/layer_tree.rb +0 -95
  113. data/lib/selenium/webdriver/devtools/log.rb +0 -66
  114. data/lib/selenium/webdriver/devtools/media.rb +0 -57
  115. data/lib/selenium/webdriver/devtools/memory.rb +0 -86
  116. data/lib/selenium/webdriver/devtools/network.rb +0 -228
  117. data/lib/selenium/webdriver/devtools/overlay.rb +0 -157
  118. data/lib/selenium/webdriver/devtools/page.rb +0 -374
  119. data/lib/selenium/webdriver/devtools/performance.rb +0 -63
  120. data/lib/selenium/webdriver/devtools/profiler.rb +0 -111
  121. data/lib/selenium/webdriver/devtools/runtime.rb +0 -193
  122. data/lib/selenium/webdriver/devtools/schema.rb +0 -46
  123. data/lib/selenium/webdriver/devtools/security.rb +0 -71
  124. data/lib/selenium/webdriver/devtools/service_worker.rb +0 -116
  125. data/lib/selenium/webdriver/devtools/storage.rb +0 -95
  126. data/lib/selenium/webdriver/devtools/system_info.rb +0 -50
  127. data/lib/selenium/webdriver/devtools/target.rb +0 -141
  128. data/lib/selenium/webdriver/devtools/tethering.rb +0 -55
  129. data/lib/selenium/webdriver/devtools/tracing.rb +0 -76
  130. data/lib/selenium/webdriver/devtools/web_audio.rb +0 -70
  131. data/lib/selenium/webdriver/devtools/web_authn.rb +0 -94
  132. data/lib/selenium/webdriver/edge_html/options.rb +0 -84
  133. data/lib/selenium/webdriver/edge_html/service.rb +0 -47
@@ -0,0 +1,30 @@
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 DriverExtensions
23
+ module HasLogs
24
+ def logs
25
+ @logs ||= Logs.new(@bridge)
26
+ end
27
+ end # HasLogs
28
+ end # DriverExtensions
29
+ end # WebDriver
30
+ end # Selenium
@@ -17,40 +17,19 @@
17
17
  # specific language governing permissions and limitations
18
18
  # under the License.
19
19
 
20
+ # TODO: Deprecated; Delete after 4.0 release
20
21
  module Selenium
21
22
  module WebDriver
22
23
  module DriverExtensions
23
24
  module HasNetworkConnection
24
25
  def network_connection_type
25
- connection_value = @bridge.network_connection
26
-
27
- connection_type = values_to_type[connection_value]
28
-
29
- # In case the connection type is not recognized return the
30
- # connection value.
31
- connection_type || connection_value
32
- end
33
-
34
- def network_connection_type=(connection_type)
35
- raise ArgumentError, 'Invalid connection type' unless valid_type? connection_type
36
-
37
- connection_value = type_to_values[connection_type]
38
-
39
- @bridge.network_connection = connection_value
40
- end
41
-
42
- private
43
-
44
- def type_to_values
45
- {airplane_mode: 1, wifi: 2, data: 4, all: 6, none: 0}
46
- end
47
-
48
- def values_to_type
49
- type_to_values.invert
26
+ raise Error::UnsupportedOperationError,
27
+ 'The W3C standard does not currently support getting network connection'
50
28
  end
51
29
 
52
- def valid_type?(type)
53
- type_to_values.key? type
30
+ def network_connection_type=(*)
31
+ raise Error::UnsupportedOperationError,
32
+ 'The W3C standard does not currently support setting network connection'
54
33
  end
55
34
  end # HasNetworkConnection
56
35
  end # DriverExtensions
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Licensed to the Software Freedom Conservancy (SFC) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The SFC licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+
20
+ module Selenium
21
+ module WebDriver
22
+ module DriverExtensions
23
+ module HasNetworkInterception
24
+
25
+ #
26
+ # Intercepts requests coming from browser allowing
27
+ # to either pass them through like proxy or provide
28
+ # a stubbed response instead.
29
+ #
30
+ # @example Log requests and pass through
31
+ # driver.intercept do |request|
32
+ # puts "#{request.method} #{request.url}"
33
+ # request.continue
34
+ # end
35
+ #
36
+ # @example Stub response for image requests
37
+ # driver.intercept do |request|
38
+ # if request.url.match?(/\.png$/)
39
+ # request.respond(body: File.read('myfile.png'))
40
+ # else
41
+ # request.continue
42
+ # end
43
+ # end
44
+ #
45
+ # @param [#call] block which is called when request is interecepted
46
+ # @yieldparam [DevTools::Request]
47
+ #
48
+
49
+ def intercept
50
+ devtools.network.set_cache_disabled(cache_disabled: true)
51
+ devtools.fetch.on(:request_paused) do |params|
52
+ request = DevTools::Request.new(
53
+ devtools: devtools,
54
+ id: params['requestId'],
55
+ url: params.dig('request', 'url'),
56
+ method: params.dig('request', 'method'),
57
+ headers: params.dig('request', 'headers')
58
+ )
59
+ yield request
60
+ end
61
+ devtools.fetch.enable
62
+ end
63
+
64
+ end # HasNetworkInterception
65
+ end # DriverExtensions
66
+ end # WebDriver
67
+ end # Selenium
@@ -22,6 +22,7 @@ module Selenium
22
22
  module DriverExtensions
23
23
  module HasRemoteStatus
24
24
  def remote_status
25
+ WebDriver.logger.deprecate('#remote_status', '#status')
25
26
  @bridge.status
26
27
  end
27
28
  end # HasRemoteStatus
@@ -19,43 +19,41 @@
19
19
 
20
20
  module Selenium
21
21
  module WebDriver
22
- #
23
- # @api private
24
- #
25
-
26
22
  module DriverExtensions
27
- module Rotatable
28
- ORIENTATIONS = %i[landscape portrait].freeze
29
-
23
+ module PrintsPage
24
+ #
25
+ # Save a page as a PDF to the given path
30
26
  #
31
- # Change the screen orientation
27
+ # @example Save Printed Page
28
+ # driver.save_print_page('../printed_page.pdf')
32
29
  #
33
- # @param [:landscape, :portrait] orientation
30
+ # @param [String] path to where the pdf should be saved
34
31
  #
35
32
  # @api public
36
33
  #
37
34
 
38
- def rotation=(orientation)
39
- unless ORIENTATIONS.include?(orientation)
40
- raise ArgumentError, "expected #{ORIENTATIONS.inspect}, got #{orientation.inspect}"
35
+ def save_print_page(path, **options)
36
+ File.open(path, 'wb') do |file|
37
+ content = Base64.decode64 print_page(options)
38
+ file << content
41
39
  end
42
-
43
- bridge.screen_orientation = orientation.to_s.upcase
44
40
  end
45
- alias_method :rotate, :rotation=
46
41
 
47
42
  #
48
- # Get the current screen orientation
43
+ # Return a Base64 encoded Print Page as a string
49
44
  #
50
- # @return [:landscape, :portrait] orientation
45
+ # @see https://w3c.github.io/webdriver/#print-page
51
46
  #
52
47
  # @api public
53
48
  #
54
49
 
55
- def orientation
56
- bridge.screen_orientation.to_sym.downcase
50
+ def print_page(**options)
51
+ options[:pageRanges] = Array(options.delete(:page_ranges)) || []
52
+ options[:shrinkToFit] = options.delete(:shrink_to_fit) { true }
53
+
54
+ @bridge.print_page(options)
57
55
  end
58
- end # Rotatable
56
+ end # PrintsPage
59
57
  end # DriverExtensions
60
58
  end # WebDriver
61
59
  end # Selenium
@@ -23,6 +23,7 @@ module Selenium
23
23
  ELEMENT_KEY = 'element-6066-11e4-a52e-4f735466cecf'
24
24
 
25
25
  include SearchContext
26
+ include TakesScreenshot
26
27
 
27
28
  #
28
29
  # Creates a new Element
@@ -91,13 +92,18 @@ module Selenium
91
92
  end
92
93
 
93
94
  #
94
- # Get the value of a the given attribute of the element. Will return the current value, even if
95
- # this has been modified after the page has been loaded. More exactly, this method will return
96
- # the value of the given attribute, unless that attribute is not present, in which case the
97
- # value of the property with the same name is returned. If neither value is set, nil is
98
- # returned. The "style" attribute is converted as best can be to a text representation with a
99
- # trailing semi-colon. The following are deemed to be "boolean" attributes, and will
100
- # return either "true" or "false":
95
+ # This method attempts to provide the most likely desired current value for the attribute
96
+ # of the element, even when that desired value is actually a JavaScript property.
97
+ # It is implemented with a custom JavaScript atom. To obtain the exact value of the attribute or property,
98
+ # use #dom_attribute or #property methods respectively.
99
+ #
100
+ # More exactly, this method will return the value of the property with the given name,
101
+ # if it exists. If it does not, then the value of the attribute with the given name is returned.
102
+ # If neither exists, null is returned.
103
+ #
104
+ # The "style" attribute is converted as best can be to a text representation with a trailing semi-colon.
105
+ #
106
+ # The following are deemed to be "boolean" attributes, and will return either "true" or "false":
101
107
  #
102
108
  # async, autofocus, autoplay, checked, compact, complete, controls, declare, defaultchecked,
103
109
  # defaultselected, defer, disabled, draggable, ended, formnovalidate, hidden, indeterminate,
@@ -105,22 +111,46 @@ module Selenium
105
111
  # nowrap, open, paused, pubdate, readonly, required, reversed, scoped, seamless, seeking,
106
112
  # selected, spellcheck, truespeed, willvalidate
107
113
  #
108
- # Finally, the following commonly mis-capitalized attribute/property names are evaluated as
109
- # expected:
114
+ # Finally, the following commonly mis-capitalized attribute/property names are evaluated as expected:
110
115
  #
111
- # class, readonly
116
+ # When the value of "class" is requested, the "className" property is returned.
117
+ # When the value of "readonly" is requested, the "readOnly" property is returned.
112
118
  #
113
119
  # @param [String] name attribute name
114
120
  # @return [String, nil] attribute value
115
121
  #
122
+ # @see #dom_attribute
123
+ # @see #property
124
+ #
116
125
 
117
126
  def attribute(name)
118
127
  bridge.element_attribute self, name
119
128
  end
120
129
 
121
130
  #
122
- # Get the value of a the given property with the same name of the element. If the value is not
123
- # set, nil is returned.
131
+ # Gets the value of a declared HTML attribute of this element.
132
+ #
133
+ # As opposed to the #attribute method, this method
134
+ # only returns attributes declared in the element's HTML markup.
135
+ #
136
+ # If the attribute is not set, nil is returned.
137
+ #
138
+ # @param [String] name attribute name
139
+ # @return [String, nil] attribute value
140
+ #
141
+ # @see #attribute
142
+ # @see #property
143
+ #
144
+
145
+ def dom_attribute(name)
146
+ bridge.element_dom_attribute self, name
147
+ end
148
+
149
+ #
150
+ # Gets the value of a JavaScript property of this element
151
+ # This will return the current value,
152
+ # even if this has been modified after the page has been loaded.
153
+ # If the value is not set, nil is returned.
124
154
  #
125
155
  # @param [String] name property name
126
156
  # @return [String, nil] property value
@@ -130,6 +160,26 @@ module Selenium
130
160
  bridge.element_property self, name
131
161
  end
132
162
 
163
+ #
164
+ # Gets the computed WAI-ARIA role of element
165
+ #
166
+ # @return [String]
167
+ #
168
+
169
+ def aria_role
170
+ bridge.element_aria_role self
171
+ end
172
+
173
+ #
174
+ # Gets the computed WAI-ARIA label of element.
175
+ #
176
+ # @return [String]
177
+ #
178
+
179
+ def accessible_name
180
+ bridge.element_aria_label self
181
+ end
182
+
133
183
  #
134
184
  # Get the text content of this element
135
185
  #
@@ -327,6 +377,10 @@ module Selenium
327
377
 
328
378
  tn == 'option' || (tn == 'input' && %w[radio checkbox].include?(type))
329
379
  end
380
+
381
+ def screenshot
382
+ bridge.element_screenshot(self)
383
+ end
330
384
  end # Element
331
385
  end # WebDriver
332
386
  end # Selenium
@@ -26,7 +26,10 @@ module Selenium
26
26
  attr_reader :source
27
27
 
28
28
  def initialize(source)
29
- raise TypeError, "#{source.type} is not a valid input type" unless Interactions::SOURCE_TYPES.include? source.type
29
+ unless Interactions::SOURCE_TYPES.include? source.type
30
+ raise TypeError,
31
+ "#{source.type} is not a valid input type"
32
+ end
30
33
 
31
34
  @source = source
32
35
  end
@@ -108,10 +108,11 @@ module Selenium
108
108
  #
109
109
  # @param [String] old
110
110
  # @param [String, nil] new
111
- # @param [Symbol, Array<Sybmol>] id
111
+ # @param [Symbol, Array<Symbol>] id
112
+ # @param [String] reference
112
113
  # @yield appends additional message to end of provided template
113
114
  #
114
- def deprecate(old, new = nil, id: [], &block)
115
+ def deprecate(old, new = nil, id: [], reference: '', &block)
115
116
  id = Array(id)
116
117
  return if @ignored.include?(:deprecations) || (@ignored & id).any?
117
118
 
@@ -123,6 +124,8 @@ module Selenium
123
124
  else
124
125
  ' and will be removed in a future release.'
125
126
  end
127
+ message << " See explanation for this deprecation: #{reference}." unless reference.empty?
128
+
126
129
  warn message, &block
127
130
  end
128
131
 
@@ -46,12 +46,15 @@ module Selenium
46
46
  raise ArgumentError, 'name is required' unless opts[:name]
47
47
  raise ArgumentError, 'value is required' unless opts[:value]
48
48
 
49
- opts[:path] ||= '/'
49
+ # NOTE: This is required because of https://bugs.chromium.org/p/chromedriver/issues/detail?id=3732
50
50
  opts[:secure] ||= false
51
51
 
52
52
  same_site = opts.delete(:same_site)
53
53
  opts[:sameSite] = same_site if same_site
54
54
 
55
+ http_only = opts.delete(:http_only)
56
+ opts[:httpOnly] = http_only if http_only
57
+
55
58
  obj = opts.delete(:expires)
56
59
  opts[:expiry] = seconds_from(obj).to_i if obj
57
60
 
@@ -106,6 +109,7 @@ module Selenium
106
109
  #
107
110
 
108
111
  def logs
112
+ WebDriver.logger.deprecate('Manager#logs', 'Chrome::Driver#logs')
109
113
  @logs ||= Logs.new(@bridge)
110
114
  end
111
115
 
@@ -174,6 +178,7 @@ module Selenium
174
178
  domain: cookie['domain'] && strip_port(cookie['domain']),
175
179
  expires: cookie['expiry'] && datetime_at(cookie['expiry']),
176
180
  same_site: cookie['sameSite'],
181
+ http_only: cookie['httpOnly'],
177
182
  secure: cookie['secure']
178
183
  }
179
184
  end
@@ -23,19 +23,51 @@ module Selenium
23
23
  W3C_OPTIONS = %i[browser_name browser_version platform_name accept_insecure_certs page_load_strategy proxy
24
24
  set_window_rect timeouts unhandled_prompt_behavior strict_file_interactability].freeze
25
25
 
26
- W3C_OPTIONS.each do |key|
27
- define_method key do
28
- @options[key]
26
+ class << self
27
+ attr_reader :driver_path
28
+
29
+ def chrome(**opts)
30
+ Chrome::Options.new(**opts)
31
+ end
32
+
33
+ def firefox(**opts)
34
+ Firefox::Options.new(**opts)
35
+ end
36
+
37
+ def ie(**opts)
38
+ IE::Options.new(**opts)
39
+ end
40
+ alias_method :internet_explorer, :ie
41
+
42
+ def edge(**opts)
43
+ Edge::Options.new(**opts)
44
+ end
45
+ alias_method :microsoftedge, :edge
46
+
47
+ def safari(**opts)
48
+ Safari::Options.new(**opts)
29
49
  end
30
50
 
31
- define_method "#{key}=" do |value|
32
- @options[key] = value
51
+ def set_capabilities
52
+ (W3C_OPTIONS + self::CAPABILITIES.keys).each do |key|
53
+ next if method_defined? key
54
+
55
+ define_method key do
56
+ @options[key]
57
+ end
58
+
59
+ define_method "#{key}=" do |value|
60
+ @options[key] = value
61
+ end
62
+ end
33
63
  end
34
64
  end
35
65
 
36
66
  attr_accessor :options
37
67
 
38
68
  def initialize(options: nil, **opts)
69
+ self.class.set_capabilities
70
+
39
71
  @options = if options
40
72
  WebDriver.logger.deprecate(":options as keyword for initializing #{self.class}",
41
73
  "custom values directly in #new constructor",
@@ -62,6 +94,14 @@ module Selenium
62
94
  @options[name] = value
63
95
  end
64
96
 
97
+ def ==(other)
98
+ return false unless other.is_a? self.class
99
+
100
+ as_json == other.as_json
101
+ end
102
+
103
+ alias_method :eql?, :==
104
+
65
105
  #
66
106
  # @api private
67
107
  #
@@ -69,28 +109,40 @@ module Selenium
69
109
  def as_json(*)
70
110
  options = @options.dup
71
111
 
72
- w3c_options = options.select { |key, _val| W3C_OPTIONS.include?(key) }
73
- options.delete_if { |key, _val| W3C_OPTIONS.include?(key) }
112
+ w3c_options = process_w3c_options(options)
74
113
 
75
114
  self.class::CAPABILITIES.each do |capability_alias, capability_name|
76
115
  capability_value = options.delete(capability_alias)
77
- options[capability_name] = capability_value unless capability_value.nil?
116
+ options[capability_name] = capability_value if !capability_value.nil? && !options.key?(capability_name)
78
117
  end
79
118
  browser_options = defined?(self.class::KEY) ? {self.class::KEY => options} : options
80
119
 
81
- process_browser_options(browser_options) if private_methods(false).include?(:process_browser_options)
120
+ process_browser_options(browser_options)
82
121
  generate_as_json(w3c_options.merge(browser_options))
83
122
  end
84
123
 
85
124
  private
86
125
 
126
+ def process_w3c_options(options)
127
+ w3c_options = options.select { |key, _val| W3C_OPTIONS.include?(key) }
128
+ w3c_options[:unhandled_prompt_behavior] &&= w3c_options[:unhandled_prompt_behavior]&.to_s&.tr('_', ' ')
129
+ options.delete_if { |key, _val| W3C_OPTIONS.include?(key) }
130
+ w3c_options
131
+ end
132
+
133
+ def process_browser_options(_browser_options)
134
+ nil
135
+ end
136
+
137
+ def camelize?(_key)
138
+ true
139
+ end
140
+
87
141
  def generate_as_json(value, camelize_keys: true)
88
- if value.respond_to?(:as_json)
142
+ if value.is_a?(Hash)
143
+ process_json_hash(value, camelize_keys)
144
+ elsif value.respond_to?(:as_json)
89
145
  value.as_json
90
- elsif value.is_a?(Hash)
91
- value.each_with_object({}) do |(key, val), hash|
92
- hash[convert_json_key(key, camelize: camelize_keys)] = generate_as_json(val, camelize_keys: camelize_keys)
93
- end
94
146
  elsif value.is_a?(Array)
95
147
  value.map { |val| generate_as_json(val, camelize_keys: camelize_keys) }
96
148
  elsif value.is_a?(Symbol)
@@ -100,6 +152,16 @@ module Selenium
100
152
  end
101
153
  end
102
154
 
155
+ def process_json_hash(value, camelize_keys)
156
+ value.each_with_object({}) do |(key, val), hash|
157
+ next if val.respond_to?(:empty?) && val.empty?
158
+
159
+ camelize = camelize_keys ? camelize?(key) : false
160
+ key = convert_json_key(key, camelize: camelize)
161
+ hash[key] = generate_as_json(val, camelize_keys: camelize)
162
+ end
163
+ end
164
+
103
165
  def convert_json_key(key, camelize: true)
104
166
  key = key.to_s if key.is_a?(Symbol)
105
167
  key = camel_case(key) if camelize