selenium-webdriver 4.0.0.alpha5 → 4.0.0.beta3
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.
- checksums.yaml +4 -4
- data/lib/selenium/devtools.rb +30 -0
- data/lib/selenium/server.rb +18 -26
- data/lib/selenium/webdriver.rb +1 -3
- data/lib/selenium/webdriver/atoms/findElements.js +93 -93
- data/lib/selenium/webdriver/atoms/getAttribute.js +75 -59
- data/lib/selenium/webdriver/atoms/isDisplayed.js +72 -72
- data/lib/selenium/webdriver/atoms/mutationListener.js +55 -0
- data/lib/selenium/webdriver/chrome.rb +1 -1
- data/lib/selenium/webdriver/chrome/driver.rb +28 -6
- data/lib/selenium/webdriver/chrome/{bridge.rb → features.rb} +6 -8
- data/lib/selenium/webdriver/chrome/options.rb +54 -37
- data/lib/selenium/webdriver/chrome/profile.rb +6 -3
- data/lib/selenium/webdriver/chrome/service.rb +4 -2
- data/lib/selenium/webdriver/common.rb +7 -2
- data/lib/selenium/webdriver/common/driver.rb +86 -26
- data/lib/selenium/webdriver/common/driver_extensions/has_authentication.rb +89 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_devtools.rb +6 -1
- data/lib/selenium/webdriver/common/driver_extensions/has_location.rb +5 -8
- data/lib/selenium/webdriver/common/driver_extensions/has_log_events.rb +149 -0
- data/lib/selenium/webdriver/{edge_chrome/bridge.rb → common/driver_extensions/has_logs.rb} +7 -7
- data/lib/selenium/webdriver/common/driver_extensions/has_network_connection.rb +6 -27
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +67 -0
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +1 -0
- data/lib/selenium/webdriver/common/driver_extensions/{rotatable.rb → prints_page.rb} +18 -20
- data/lib/selenium/webdriver/common/element.rb +66 -12
- data/lib/selenium/webdriver/common/interactions/interaction.rb +4 -1
- data/lib/selenium/webdriver/common/logger.rb +6 -3
- data/lib/selenium/webdriver/common/manager.rb +11 -1
- data/lib/selenium/webdriver/common/options.rb +90 -11
- data/lib/selenium/webdriver/common/platform.rb +3 -1
- data/lib/selenium/webdriver/common/port_prober.rb +4 -6
- data/lib/selenium/webdriver/common/proxy.rb +4 -1
- data/lib/selenium/webdriver/common/search_context.rb +4 -1
- data/lib/selenium/webdriver/common/service.rb +13 -114
- data/lib/selenium/webdriver/common/service_manager.rb +151 -0
- data/lib/selenium/webdriver/common/socket_poller.rb +19 -30
- data/lib/selenium/webdriver/common/takes_screenshot.rb +63 -0
- data/lib/selenium/webdriver/common/target_locator.rb +4 -4
- data/lib/selenium/webdriver/devtools.rb +144 -0
- data/lib/selenium/webdriver/devtools/console_event.rb +38 -0
- data/lib/selenium/webdriver/{edge_html/driver.rb → devtools/exception_event.rb} +10 -13
- data/lib/selenium/webdriver/devtools/mutation_event.rb +37 -0
- data/lib/selenium/webdriver/devtools/request.rb +57 -0
- data/lib/selenium/webdriver/edge.rb +7 -29
- data/lib/selenium/webdriver/{edge_chrome → edge}/driver.rb +10 -4
- data/lib/selenium/webdriver/edge/features.rb +39 -0
- data/lib/selenium/webdriver/{edge_chrome → edge}/options.rb +12 -3
- data/lib/selenium/webdriver/{edge_chrome → edge}/profile.rb +2 -2
- data/lib/selenium/webdriver/{edge_chrome → edge}/service.rb +2 -2
- data/lib/selenium/webdriver/firefox.rb +5 -1
- data/lib/selenium/webdriver/firefox/driver.rb +19 -3
- data/lib/selenium/webdriver/firefox/{bridge.rb → features.rb} +3 -3
- data/lib/selenium/webdriver/firefox/options.rb +25 -31
- data/lib/selenium/webdriver/firefox/profile.rb +12 -2
- data/lib/selenium/webdriver/firefox/service.rb +1 -1
- data/lib/selenium/webdriver/ie/driver.rb +1 -2
- data/lib/selenium/webdriver/ie/options.rb +7 -20
- data/lib/selenium/webdriver/ie/service.rb +4 -2
- data/lib/selenium/webdriver/remote/bridge.rb +50 -42
- data/lib/selenium/webdriver/remote/capabilities.rb +127 -71
- data/lib/selenium/webdriver/remote/commands.rb +3 -0
- data/lib/selenium/webdriver/remote/driver.rb +10 -3
- data/lib/selenium/webdriver/remote/http/common.rb +0 -5
- data/lib/selenium/webdriver/remote/http/default.rb +8 -7
- data/lib/selenium/webdriver/remote/http/persistent.rb +6 -0
- data/lib/selenium/webdriver/safari.rb +8 -1
- data/lib/selenium/webdriver/safari/driver.rb +3 -4
- data/lib/selenium/webdriver/safari/{bridge.rb → features.rb} +3 -3
- data/lib/selenium/webdriver/safari/options.rb +1 -33
- data/lib/selenium/webdriver/support/block_event_listener.rb +1 -1
- data/lib/selenium/webdriver/support/color.rb +2 -2
- data/lib/selenium/webdriver/support/event_firing_bridge.rb +1 -1
- data/lib/selenium/webdriver/support/guards.rb +95 -0
- data/lib/selenium/webdriver/support/guards/guard.rb +89 -0
- data/lib/selenium/webdriver/support/guards/guard_condition.rb +52 -0
- data/lib/selenium/webdriver/support/select.rb +2 -2
- data/lib/selenium/webdriver/version.rb +1 -1
- metadata +69 -32
- data/CHANGES +0 -1725
- data/Gemfile +0 -4
- data/LICENSE +0 -202
- data/README.md +0 -35
- data/lib/selenium/webdriver/common/driver_extensions/takes_screenshot.rb +0 -65
- data/lib/selenium/webdriver/edge_html/options.rb +0 -91
- data/lib/selenium/webdriver/edge_html/service.rb +0 -47
- data/selenium-webdriver.gemspec +0 -48
@@ -17,14 +17,14 @@
|
|
17
17
|
# specific language governing permissions and limitations
|
18
18
|
# under the License.
|
19
19
|
|
20
|
-
require 'selenium/webdriver/chrome/bridge'
|
21
|
-
|
22
20
|
module Selenium
|
23
21
|
module WebDriver
|
24
|
-
module
|
25
|
-
module
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
module DriverExtensions
|
23
|
+
module HasLogs
|
24
|
+
def logs
|
25
|
+
@logs ||= Logs.new(@bridge)
|
26
|
+
end
|
27
|
+
end # HasLogs
|
28
|
+
end # DriverExtensions
|
29
29
|
end # WebDriver
|
30
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
|
-
|
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
|
53
|
-
|
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
|
@@ -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
|
28
|
-
|
29
|
-
|
23
|
+
module PrintsPage
|
24
|
+
#
|
25
|
+
# Save a page as a PDF to the given path
|
30
26
|
#
|
31
|
-
#
|
27
|
+
# @example Save Printed Page
|
28
|
+
# driver.save_print_page('../printed_page.pdf')
|
32
29
|
#
|
33
|
-
# @param [
|
30
|
+
# @param [String] path to where the pdf should be saved
|
34
31
|
#
|
35
32
|
# @api public
|
36
33
|
#
|
37
34
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
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
|
-
#
|
43
|
+
# Return a Base64 encoded Print Page as a string
|
49
44
|
#
|
50
|
-
# @
|
45
|
+
# @see https://w3c.github.io/webdriver/#print-page
|
51
46
|
#
|
52
47
|
# @api public
|
53
48
|
#
|
54
49
|
|
55
|
-
def
|
56
|
-
|
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 #
|
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
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
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,
|
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
|
-
#
|
123
|
-
#
|
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
|
-
|
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
|
@@ -40,7 +40,7 @@ module Selenium
|
|
40
40
|
:close,
|
41
41
|
:debug, :debug?,
|
42
42
|
:info, :info?,
|
43
|
-
:warn
|
43
|
+
:warn?,
|
44
44
|
:error, :error?,
|
45
45
|
:fatal, :fatal?,
|
46
46
|
:level, :level=
|
@@ -108,10 +108,11 @@ module Selenium
|
|
108
108
|
#
|
109
109
|
# @param [String] old
|
110
110
|
# @param [String, nil] new
|
111
|
-
# @param [Symbol, Array<
|
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
|
|
@@ -36,6 +36,7 @@ module Selenium
|
|
36
36
|
# @option opts [String] :value A value
|
37
37
|
# @option opts [String] :path ('/') A path
|
38
38
|
# @option opts [String] :secure (false) A boolean
|
39
|
+
# @option opts [String] :same_site (Strict or Lax) currently supported only in chrome 80+ versions
|
39
40
|
# @option opts [Time,DateTime,Numeric,nil] :expires (nil) Expiry date, either as a Time, DateTime, or seconds since epoch.
|
40
41
|
#
|
41
42
|
# @raise [ArgumentError] if :name or :value is not specified
|
@@ -45,9 +46,15 @@ module Selenium
|
|
45
46
|
raise ArgumentError, 'name is required' unless opts[:name]
|
46
47
|
raise ArgumentError, 'value is required' unless opts[:value]
|
47
48
|
|
48
|
-
|
49
|
+
# NOTE: This is required because of https://bugs.chromium.org/p/chromedriver/issues/detail?id=3732
|
49
50
|
opts[:secure] ||= false
|
50
51
|
|
52
|
+
same_site = opts.delete(:same_site)
|
53
|
+
opts[:sameSite] = same_site if same_site
|
54
|
+
|
55
|
+
http_only = opts.delete(:http_only)
|
56
|
+
opts[:httpOnly] = http_only if http_only
|
57
|
+
|
51
58
|
obj = opts.delete(:expires)
|
52
59
|
opts[:expiry] = seconds_from(obj).to_i if obj
|
53
60
|
|
@@ -102,6 +109,7 @@ module Selenium
|
|
102
109
|
#
|
103
110
|
|
104
111
|
def logs
|
112
|
+
WebDriver.logger.deprecate('Manager#logs', 'Chrome::Driver#logs')
|
105
113
|
@logs ||= Logs.new(@bridge)
|
106
114
|
end
|
107
115
|
|
@@ -169,6 +177,8 @@ module Selenium
|
|
169
177
|
path: cookie['path'],
|
170
178
|
domain: cookie['domain'] && strip_port(cookie['domain']),
|
171
179
|
expires: cookie['expiry'] && datetime_at(cookie['expiry']),
|
180
|
+
same_site: cookie['sameSite'],
|
181
|
+
http_only: cookie['httpOnly'],
|
172
182
|
secure: cookie['secure']
|
173
183
|
}
|
174
184
|
end
|
@@ -20,9 +20,54 @@
|
|
20
20
|
module Selenium
|
21
21
|
module WebDriver
|
22
22
|
class Options
|
23
|
+
W3C_OPTIONS = %i[browser_name browser_version platform_name accept_insecure_certs page_load_strategy proxy
|
24
|
+
set_window_rect timeouts unhandled_prompt_behavior strict_file_interactability].freeze
|
25
|
+
|
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)
|
49
|
+
end
|
50
|
+
|
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
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
23
66
|
attr_accessor :options
|
24
67
|
|
25
68
|
def initialize(options: nil, **opts)
|
69
|
+
self.class.set_capabilities
|
70
|
+
|
26
71
|
@options = if options
|
27
72
|
WebDriver.logger.deprecate(":options as keyword for initializing #{self.class}",
|
28
73
|
"custom values directly in #new constructor",
|
@@ -31,6 +76,7 @@ module Selenium
|
|
31
76
|
else
|
32
77
|
opts
|
33
78
|
end
|
79
|
+
@options[:browser_name] = self.class::BROWSER
|
34
80
|
end
|
35
81
|
|
36
82
|
#
|
@@ -48,6 +94,14 @@ module Selenium
|
|
48
94
|
@options[name] = value
|
49
95
|
end
|
50
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
|
+
|
51
105
|
#
|
52
106
|
# @api private
|
53
107
|
#
|
@@ -55,22 +109,36 @@ module Selenium
|
|
55
109
|
def as_json(*)
|
56
110
|
options = @options.dup
|
57
111
|
|
58
|
-
|
112
|
+
w3c_options = options.select { |key, _val| W3C_OPTIONS.include?(key) }
|
113
|
+
options.delete_if { |key, _val| W3C_OPTIONS.include?(key) }
|
114
|
+
|
115
|
+
self.class::CAPABILITIES.each do |capability_alias, capability_name|
|
59
116
|
capability_value = options.delete(capability_alias)
|
60
|
-
|
117
|
+
options[capability_name] = capability_value unless capability_value.nil?
|
61
118
|
end
|
62
|
-
|
119
|
+
browser_options = defined?(self.class::KEY) ? {self.class::KEY => options} : options
|
120
|
+
|
121
|
+
process_browser_options(browser_options)
|
122
|
+
generate_as_json(w3c_options.merge(browser_options))
|
63
123
|
end
|
64
124
|
|
65
125
|
private
|
66
126
|
|
67
|
-
def
|
68
|
-
|
127
|
+
def process_browser_options(_browser_options)
|
128
|
+
nil
|
129
|
+
end
|
130
|
+
|
131
|
+
def camelize?(_key)
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
def generate_as_json(value, camelize_keys: true)
|
136
|
+
if value.is_a?(Hash)
|
137
|
+
process_json_hash(value, camelize_keys)
|
138
|
+
elsif value.respond_to?(:as_json)
|
69
139
|
value.as_json
|
70
|
-
elsif value.is_a?(Hash)
|
71
|
-
value.each_with_object({}) { |(key, val), hash| hash[convert_json_key(key)] = generate_as_json(val) }
|
72
140
|
elsif value.is_a?(Array)
|
73
|
-
value.map(
|
141
|
+
value.map { |val| generate_as_json(val, camelize_keys: camelize_keys) }
|
74
142
|
elsif value.is_a?(Symbol)
|
75
143
|
value.to_s
|
76
144
|
else
|
@@ -78,15 +146,26 @@ module Selenium
|
|
78
146
|
end
|
79
147
|
end
|
80
148
|
|
81
|
-
def
|
82
|
-
|
149
|
+
def process_json_hash(value, camelize_keys)
|
150
|
+
value.each_with_object({}) do |(key, val), hash|
|
151
|
+
next if val.respond_to?(:empty?) && val.empty?
|
152
|
+
|
153
|
+
camelize = camelize_keys ? camelize?(key) : false
|
154
|
+
key = convert_json_key(key, camelize: camelize)
|
155
|
+
hash[key] = generate_as_json(val, camelize_keys: camelize)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def convert_json_key(key, camelize: true)
|
160
|
+
key = key.to_s if key.is_a?(Symbol)
|
161
|
+
key = camel_case(key) if camelize
|
83
162
|
return key if key.is_a?(String)
|
84
163
|
|
85
164
|
raise TypeError, "expected String or Symbol, got #{key.inspect}:#{key.class}"
|
86
165
|
end
|
87
166
|
|
88
167
|
def camel_case(str)
|
89
|
-
str.
|
168
|
+
str.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
|
90
169
|
end
|
91
170
|
end # Options
|
92
171
|
end # WebDriver
|