selenium-webdriver 4.2.0 → 4.4.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.
- checksums.yaml +4 -4
- data/CHANGES +40 -1
- data/lib/selenium/server.rb +1 -1
- data/lib/selenium/webdriver/chrome/options.rb +14 -0
- data/lib/selenium/webdriver/chrome.rb +0 -14
- data/lib/selenium/webdriver/common/driver.rb +20 -53
- data/lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb +2 -67
- data/lib/selenium/webdriver/common/interactions/pointer_actions.rb +17 -34
- data/lib/selenium/webdriver/common/interactions/wheel_actions.rb +1 -1
- data/lib/selenium/webdriver/common/manager.rb +0 -27
- data/lib/selenium/webdriver/common/options.rb +2 -9
- data/lib/selenium/webdriver/common/takes_screenshot.rb +1 -1
- data/lib/selenium/webdriver/common/virtual_authenticator/credential.rb +83 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb +73 -0
- data/lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb +62 -0
- data/lib/selenium/webdriver/common/websocket_connection.rb +13 -6
- data/lib/selenium/webdriver/common/window.rb +6 -6
- data/lib/selenium/webdriver/common/zipper.rb +1 -1
- data/lib/selenium/webdriver/common.rb +3 -1
- data/lib/selenium/webdriver/devtools/network_interceptor.rb +176 -0
- data/lib/selenium/webdriver/devtools.rb +1 -0
- data/lib/selenium/webdriver/firefox.rb +0 -14
- data/lib/selenium/webdriver/ie.rb +0 -14
- data/lib/selenium/webdriver/remote/bridge.rb +35 -2
- data/lib/selenium/webdriver/remote/commands.rb +15 -1
- data/lib/selenium/webdriver/remote/driver.rb +0 -1
- data/lib/selenium/webdriver/safari.rb +0 -14
- data/lib/selenium/webdriver/version.rb +1 -1
- data/selenium-webdriver.gemspec +3 -3
- metadata +17 -15
- data/lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb +0 -31
- data/lib/selenium/webdriver/remote/http/persistent.rb +0 -65
@@ -0,0 +1,62 @@
|
|
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
|
+
#
|
21
|
+
# Options for the creation of virtual authenticators.
|
22
|
+
# @see http://w3c.github.io/webauthn/#sctn-automation
|
23
|
+
#
|
24
|
+
|
25
|
+
module Selenium
|
26
|
+
module WebDriver
|
27
|
+
class VirtualAuthenticatorOptions
|
28
|
+
|
29
|
+
PROTOCOL = {ctap2: "ctap2", u2f: "ctap1/u2f"}.freeze
|
30
|
+
TRANSPORT = {ble: "ble", usb: "usb", nfc: "nfc", internal: "internal"}.freeze
|
31
|
+
|
32
|
+
attr_accessor :protocol, :transport, :resident_key, :user_verification, :user_consenting, :user_verified
|
33
|
+
alias_method :resident_key?, :resident_key
|
34
|
+
alias_method :user_verification?, :user_verification
|
35
|
+
alias_method :user_consenting?, :user_consenting
|
36
|
+
alias_method :user_verified?, :user_verified
|
37
|
+
|
38
|
+
def initialize(protocol: :ctap2, transport: :usb, resident_key: false,
|
39
|
+
user_verification: false, user_consenting: true, user_verified: false)
|
40
|
+
@protocol = protocol
|
41
|
+
@transport = transport
|
42
|
+
@resident_key = resident_key
|
43
|
+
@user_verification = user_verification
|
44
|
+
@user_consenting = user_consenting
|
45
|
+
@user_verified = user_verified
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
#
|
51
|
+
|
52
|
+
def as_json(*)
|
53
|
+
{'protocol' => PROTOCOL[protocol],
|
54
|
+
'transport' => TRANSPORT[transport],
|
55
|
+
'hasResidentKey' => resident_key?,
|
56
|
+
'hasUserVerification' => user_verification?,
|
57
|
+
'isUserConsenting' => user_consenting?,
|
58
|
+
'isUserVerified' => user_verified?}
|
59
|
+
end
|
60
|
+
end # VirtualAuthenticatorOptions
|
61
|
+
end # WebDriver
|
62
|
+
end # Selenium
|
@@ -25,10 +25,11 @@ module Selenium
|
|
25
25
|
RESPONSE_WAIT_TIMEOUT = 30
|
26
26
|
RESPONSE_WAIT_INTERVAL = 0.1
|
27
27
|
|
28
|
+
MAX_LOG_MESSAGE_SIZE = 9999
|
29
|
+
|
28
30
|
def initialize(url:)
|
29
31
|
@callback_threads = ThreadGroup.new
|
30
32
|
|
31
|
-
@messages = []
|
32
33
|
@session_id = nil
|
33
34
|
@url = url
|
34
35
|
|
@@ -49,17 +50,23 @@ module Selenium
|
|
49
50
|
def send_cmd(**payload)
|
50
51
|
id = next_id
|
51
52
|
data = payload.merge(id: id)
|
53
|
+
WebDriver.logger.debug "WebSocket -> #{data}"[...MAX_LOG_MESSAGE_SIZE]
|
52
54
|
data = JSON.generate(data)
|
53
|
-
WebDriver.logger.debug "WebSocket -> #{data}"
|
54
|
-
|
55
55
|
out_frame = WebSocket::Frame::Outgoing::Client.new(version: ws.version, data: data, type: 'text')
|
56
56
|
socket.write(out_frame.to_s)
|
57
57
|
|
58
|
-
wait.until {
|
58
|
+
wait.until { messages.delete(id) }
|
59
59
|
end
|
60
60
|
|
61
61
|
private
|
62
62
|
|
63
|
+
# We should be thread-safe to use the hash without synchronization
|
64
|
+
# because its keys are WebSocket message identifiers and they should be
|
65
|
+
# unique within a devtools session.
|
66
|
+
def messages
|
67
|
+
@messages ||= {}
|
68
|
+
end
|
69
|
+
|
63
70
|
def process_handshake
|
64
71
|
socket.print(ws.to_s)
|
65
72
|
ws << socket.readpartial(1024)
|
@@ -97,8 +104,8 @@ module Selenium
|
|
97
104
|
return {} if message.empty?
|
98
105
|
|
99
106
|
message = JSON.parse(message)
|
100
|
-
|
101
|
-
WebDriver.logger.debug "WebSocket <- #{message}"
|
107
|
+
messages[message["id"]] = message
|
108
|
+
WebDriver.logger.debug "WebSocket <- #{message}"[...MAX_LOG_MESSAGE_SIZE]
|
102
109
|
|
103
110
|
message
|
104
111
|
end
|
@@ -36,8 +36,8 @@ module Selenium
|
|
36
36
|
|
37
37
|
def size=(dimension)
|
38
38
|
unless dimension.respond_to?(:width) && dimension.respond_to?(:height)
|
39
|
-
raise ArgumentError, "expected #{dimension.inspect}:#{dimension.class}" \
|
40
|
-
'
|
39
|
+
raise ArgumentError, "expected #{dimension.inspect}:#{dimension.class} " \
|
40
|
+
'to respond to #width and #height'
|
41
41
|
end
|
42
42
|
|
43
43
|
@bridge.resize_window dimension.width, dimension.height
|
@@ -61,8 +61,8 @@ module Selenium
|
|
61
61
|
|
62
62
|
def position=(point)
|
63
63
|
unless point.respond_to?(:x) && point.respond_to?(:y)
|
64
|
-
raise ArgumentError, "expected #{point.inspect}:#{point.class}" \
|
65
|
-
'
|
64
|
+
raise ArgumentError, "expected #{point.inspect}:#{point.class} " \
|
65
|
+
'to respond to #x and #y'
|
66
66
|
end
|
67
67
|
|
68
68
|
@bridge.reposition_window point.x, point.y
|
@@ -86,8 +86,8 @@ module Selenium
|
|
86
86
|
|
87
87
|
def rect=(rectangle)
|
88
88
|
unless %w[x y width height].all? { |val| rectangle.respond_to? val }
|
89
|
-
raise ArgumentError, "expected #{rectangle.inspect}:#{rectangle.class}" \
|
90
|
-
'
|
89
|
+
raise ArgumentError, "expected #{rectangle.inspect}:#{rectangle.class} " \
|
90
|
+
'to respond to #x, #y, #width, and #height'
|
91
91
|
end
|
92
92
|
|
93
93
|
@bridge.set_window_rect(x: rectangle.x,
|
@@ -57,6 +57,9 @@ require 'selenium/webdriver/common/interactions/wheel_input'
|
|
57
57
|
require 'selenium/webdriver/common/interactions/scroll_origin'
|
58
58
|
require 'selenium/webdriver/common/interactions/wheel_actions'
|
59
59
|
require 'selenium/webdriver/common/action_builder'
|
60
|
+
require 'selenium/webdriver/common/virtual_authenticator/credential'
|
61
|
+
require 'selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options'
|
62
|
+
require 'selenium/webdriver/common/virtual_authenticator/virtual_authenticator'
|
60
63
|
require 'selenium/webdriver/common/html5/shared_web_storage'
|
61
64
|
require 'selenium/webdriver/common/html5/local_storage'
|
62
65
|
require 'selenium/webdriver/common/html5/session_storage'
|
@@ -64,7 +67,6 @@ require 'selenium/webdriver/common/driver_extensions/has_web_storage'
|
|
64
67
|
require 'selenium/webdriver/common/driver_extensions/downloads_files'
|
65
68
|
require 'selenium/webdriver/common/driver_extensions/has_location'
|
66
69
|
require 'selenium/webdriver/common/driver_extensions/has_session_id'
|
67
|
-
require 'selenium/webdriver/common/driver_extensions/has_remote_status'
|
68
70
|
require 'selenium/webdriver/common/driver_extensions/has_network_conditions'
|
69
71
|
require 'selenium/webdriver/common/driver_extensions/has_network_connection'
|
70
72
|
require 'selenium/webdriver/common/driver_extensions/has_network_interception'
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Licensed to the Software Freedom Conservancy (SFC) under one
|
4
|
+
# or more contributor license agreements. See the NOTICE file
|
5
|
+
# distributed with this work for additional information
|
6
|
+
# regarding copyright ownership. The SFC licenses this file
|
7
|
+
# to you under the Apache License, Version 2.0 (the
|
8
|
+
# "License"); you may not use this file except in compliance
|
9
|
+
# with the License. You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing,
|
14
|
+
# software distributed under the License is distributed on an
|
15
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
16
|
+
# KIND, either express or implied. See the License for the
|
17
|
+
# specific language governing permissions and limitations
|
18
|
+
# under the License.
|
19
|
+
|
20
|
+
module Selenium
|
21
|
+
module WebDriver
|
22
|
+
class DevTools
|
23
|
+
|
24
|
+
#
|
25
|
+
# Wraps the network request/response interception, providing
|
26
|
+
# thread-safety guarantees and handling special cases such as browser
|
27
|
+
# canceling requests midst interception.
|
28
|
+
#
|
29
|
+
# You should not be using this class directly, use Driver#intercept instead.
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
|
33
|
+
class NetworkInterceptor
|
34
|
+
|
35
|
+
# CDP fails to get body on certain responses (301) and raises:
|
36
|
+
# "Can only get response body on requests captured after headers received."
|
37
|
+
CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE = "-32000"
|
38
|
+
|
39
|
+
# CDP fails to operate with intercepted requests.
|
40
|
+
# Typical reason is browser cancelling intercepted requests/responses.
|
41
|
+
INVALID_INTERCEPTION_ID_ERROR_CODE = "-32602"
|
42
|
+
|
43
|
+
def initialize(devtools)
|
44
|
+
@devtools = devtools
|
45
|
+
@lock = Mutex.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def intercept(&block)
|
49
|
+
devtools.network.on(:loading_failed) { |params| track_cancelled_request(params) }
|
50
|
+
devtools.fetch.on(:request_paused) { |params| request_paused(params, &block) }
|
51
|
+
|
52
|
+
devtools.network.set_cache_disabled(cache_disabled: true)
|
53
|
+
devtools.network.enable
|
54
|
+
devtools.fetch.enable(patterns: [{requestStage: 'Request'}, {requestStage: 'Response'}])
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
attr_accessor :devtools, :lock
|
60
|
+
|
61
|
+
# We should be thread-safe to use the hash without synchronization
|
62
|
+
# because its keys are interception job identifiers and they should be
|
63
|
+
# unique within a devtools session.
|
64
|
+
def pending_response_requests
|
65
|
+
@pending_response_requests ||= {}
|
66
|
+
end
|
67
|
+
|
68
|
+
# Ensure usage of cancelled_requests is thread-safe via synchronization!
|
69
|
+
def cancelled_requests
|
70
|
+
@cancelled_requests ||= []
|
71
|
+
end
|
72
|
+
|
73
|
+
def track_cancelled_request(data)
|
74
|
+
return unless data['canceled']
|
75
|
+
|
76
|
+
lock.synchronize { cancelled_requests << data['requestId'] }
|
77
|
+
end
|
78
|
+
|
79
|
+
def request_paused(data, &block)
|
80
|
+
id = data['requestId']
|
81
|
+
network_id = data['networkId']
|
82
|
+
|
83
|
+
with_cancellable_request(network_id) do
|
84
|
+
if response?(data)
|
85
|
+
block = pending_response_requests.delete(id)
|
86
|
+
intercept_response(id, data, &block)
|
87
|
+
else
|
88
|
+
intercept_request(id, data, &block)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# The presence of any of these fields indicate we're at the response stage.
|
94
|
+
# @see https://chromedevtools.github.io/devtools-protocol/tot/Fetch/#event-requestPaused
|
95
|
+
def response?(params)
|
96
|
+
params.key?('responseStatusCode') || params.key?('responseErrorReason')
|
97
|
+
end
|
98
|
+
|
99
|
+
def intercept_request(id, params, &block)
|
100
|
+
original = DevTools::Request.from(id, params)
|
101
|
+
mutable = DevTools::Request.from(id, params)
|
102
|
+
|
103
|
+
block.call(mutable) do |&continue| # rubocop:disable Performance/RedundantBlockCall
|
104
|
+
pending_response_requests[id] = continue
|
105
|
+
|
106
|
+
if original == mutable
|
107
|
+
continue_request(original.id)
|
108
|
+
else
|
109
|
+
mutate_request(mutable)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def intercept_response(id, params)
|
115
|
+
return continue_response(id) unless block_given?
|
116
|
+
|
117
|
+
body = fetch_response_body(id)
|
118
|
+
original = DevTools::Response.from(id, body, params)
|
119
|
+
mutable = DevTools::Response.from(id, body, params)
|
120
|
+
yield mutable
|
121
|
+
|
122
|
+
if original == mutable
|
123
|
+
continue_response(id)
|
124
|
+
else
|
125
|
+
mutate_response(mutable)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def continue_request(id)
|
130
|
+
devtools.fetch.continue_request(request_id: id)
|
131
|
+
end
|
132
|
+
alias_method :continue_response, :continue_request
|
133
|
+
|
134
|
+
def mutate_request(request)
|
135
|
+
devtools.fetch.continue_request(
|
136
|
+
request_id: request.id,
|
137
|
+
url: request.url,
|
138
|
+
method: request.method,
|
139
|
+
post_data: request.post_data,
|
140
|
+
headers: request.headers.map do |k, v|
|
141
|
+
{name: k, value: v}
|
142
|
+
end
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
def mutate_response(response)
|
147
|
+
devtools.fetch.fulfill_request(
|
148
|
+
request_id: response.id,
|
149
|
+
body: (Base64.strict_encode64(response.body) if response.body),
|
150
|
+
response_code: response.code,
|
151
|
+
response_headers: response.headers.map do |k, v|
|
152
|
+
{name: k, value: v}
|
153
|
+
end
|
154
|
+
)
|
155
|
+
end
|
156
|
+
|
157
|
+
def fetch_response_body(id)
|
158
|
+
devtools.fetch.get_response_body(request_id: id).dig('result', 'body')
|
159
|
+
rescue Error::WebDriverError => e
|
160
|
+
raise unless e.message.start_with?(CANNOT_GET_BODY_ON_REDIRECT_ERROR_CODE)
|
161
|
+
end
|
162
|
+
|
163
|
+
def with_cancellable_request(network_id)
|
164
|
+
yield
|
165
|
+
rescue Error::WebDriverError => e
|
166
|
+
raise if e.message.start_with?(INVALID_INTERCEPTION_ID_ERROR_CODE) && !cancelled?(network_id)
|
167
|
+
end
|
168
|
+
|
169
|
+
def cancelled?(network_id)
|
170
|
+
lock.synchronize { !!cancelled_requests.delete(network_id) }
|
171
|
+
end
|
172
|
+
|
173
|
+
end # NetworkInterceptor
|
174
|
+
end # DevTools
|
175
|
+
end # WebDriver
|
176
|
+
end # Selenium
|
@@ -23,6 +23,7 @@ module Selenium
|
|
23
23
|
autoload :ConsoleEvent, 'selenium/webdriver/devtools/console_event'
|
24
24
|
autoload :ExceptionEvent, 'selenium/webdriver/devtools/exception_event'
|
25
25
|
autoload :MutationEvent, 'selenium/webdriver/devtools/mutation_event'
|
26
|
+
autoload :NetworkInterceptor, 'selenium/webdriver/devtools/network_interceptor'
|
26
27
|
autoload :PinnedScript, 'selenium/webdriver/devtools/pinned_script'
|
27
28
|
autoload :Request, 'selenium/webdriver/devtools/request'
|
28
29
|
autoload :Response, 'selenium/webdriver/devtools/response'
|
@@ -42,20 +42,6 @@ module Selenium
|
|
42
42
|
# until WebDriver Bidi is available.
|
43
43
|
DEVTOOLS_VERSION = 85
|
44
44
|
|
45
|
-
def self.driver_path=(path)
|
46
|
-
WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path=',
|
47
|
-
'Selenium::WebDriver::Firefox::Service#driver_path=',
|
48
|
-
id: :driver_path
|
49
|
-
Selenium::WebDriver::Firefox::Service.driver_path = path
|
50
|
-
end
|
51
|
-
|
52
|
-
def self.driver_path
|
53
|
-
WebDriver.logger.deprecate 'Selenium::WebDriver::Firefox#driver_path',
|
54
|
-
'Selenium::WebDriver::Firefox::Service#driver_path',
|
55
|
-
id: :driver_path
|
56
|
-
Selenium::WebDriver::Firefox::Service.driver_path
|
57
|
-
end
|
58
|
-
|
59
45
|
def self.path=(path)
|
60
46
|
Platform.assert_executable path
|
61
47
|
@path = path
|
@@ -23,20 +23,6 @@ module Selenium
|
|
23
23
|
autoload :Driver, 'selenium/webdriver/ie/driver'
|
24
24
|
autoload :Options, 'selenium/webdriver/ie/options'
|
25
25
|
autoload :Service, 'selenium/webdriver/ie/service'
|
26
|
-
|
27
|
-
def self.driver_path=(path)
|
28
|
-
WebDriver.logger.deprecate 'Selenium::WebDriver::IE#driver_path=',
|
29
|
-
'Selenium::WebDriver::IE::Service#driver_path=',
|
30
|
-
id: :driver_path
|
31
|
-
Selenium::WebDriver::IE::Service.driver_path = path
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.driver_path
|
35
|
-
WebDriver.logger.deprecate 'Selenium::WebDriver::IE#driver_path',
|
36
|
-
'Selenium::WebDriver::IE::Service#driver_path',
|
37
|
-
id: :driver_path
|
38
|
-
Selenium::WebDriver::IE::Service.driver_path
|
39
|
-
end
|
40
26
|
end # IE
|
41
27
|
end # WebDriver
|
42
28
|
end # Selenium
|
@@ -426,8 +426,8 @@ module Selenium
|
|
426
426
|
|
427
427
|
def submit_element(element)
|
428
428
|
script = "var form = arguments[0];\n" \
|
429
|
-
"while (form.nodeName != \"FORM\" && form.parentNode) {\n" \
|
430
|
-
"
|
429
|
+
"while (form.nodeName != \"FORM\" && form.parentNode) {\n " \
|
430
|
+
"form = form.parentNode;\n" \
|
431
431
|
"}\n" \
|
432
432
|
"if (!form) { throw Error('Unable to find containing form element'); }\n" \
|
433
433
|
"if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" \
|
@@ -568,6 +568,39 @@ module Selenium
|
|
568
568
|
ShadowRoot.new self, shadow_root_id_from(id)
|
569
569
|
end
|
570
570
|
|
571
|
+
#
|
572
|
+
# virtual-authenticator
|
573
|
+
#
|
574
|
+
|
575
|
+
def add_virtual_authenticator(options)
|
576
|
+
authenticator_id = execute :add_virtual_authenticator, {}, options.as_json
|
577
|
+
VirtualAuthenticator.new(self, authenticator_id, options)
|
578
|
+
end
|
579
|
+
|
580
|
+
def remove_virtual_authenticator(id)
|
581
|
+
execute :remove_virtual_authenticator, {authenticatorId: id}
|
582
|
+
end
|
583
|
+
|
584
|
+
def add_credential(credential, id)
|
585
|
+
execute :add_credential, {authenticatorId: id}, credential
|
586
|
+
end
|
587
|
+
|
588
|
+
def credentials(authenticator_id)
|
589
|
+
execute :get_credentials, {authenticatorId: authenticator_id}
|
590
|
+
end
|
591
|
+
|
592
|
+
def remove_credential(credential_id, authenticator_id)
|
593
|
+
execute :remove_credential, {credentialId: credential_id, authenticatorId: authenticator_id}
|
594
|
+
end
|
595
|
+
|
596
|
+
def remove_all_credentials(authenticator_id)
|
597
|
+
execute :remove_all_credentials, {authenticatorId: authenticator_id}
|
598
|
+
end
|
599
|
+
|
600
|
+
def user_verified(verified, authenticator_id)
|
601
|
+
execute :set_user_verified, {authenticatorId: authenticator_id}, {isUserVerified: verified}
|
602
|
+
end
|
603
|
+
|
571
604
|
private
|
572
605
|
|
573
606
|
#
|
@@ -149,7 +149,21 @@ module Selenium
|
|
149
149
|
# server extensions
|
150
150
|
#
|
151
151
|
|
152
|
-
upload_file: [:post, 'session/:session_id/se/file']
|
152
|
+
upload_file: [:post, 'session/:session_id/se/file'],
|
153
|
+
|
154
|
+
#
|
155
|
+
# virtual-authenticator
|
156
|
+
#
|
157
|
+
|
158
|
+
add_virtual_authenticator: [:post, 'session/:session_id/webauthn/authenticator'],
|
159
|
+
remove_virtual_authenticator: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId'],
|
160
|
+
add_credential: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/credential'],
|
161
|
+
get_credentials: [:get, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'],
|
162
|
+
remove_credential: [:delete,
|
163
|
+
'session/:session_id/webauthn/authenticator/:authenticatorId/credentials/:credentialId'],
|
164
|
+
remove_all_credentials: [:delete, 'session/:session_id/webauthn/authenticator/:authenticatorId/credentials'],
|
165
|
+
set_user_verified: [:post, 'session/:session_id/webauthn/authenticator/:authenticatorId/uv']
|
166
|
+
|
153
167
|
}.freeze
|
154
168
|
|
155
169
|
end # Bridge
|
@@ -29,7 +29,6 @@ module Selenium
|
|
29
29
|
class Driver < WebDriver::Driver
|
30
30
|
include DriverExtensions::UploadsFiles
|
31
31
|
include DriverExtensions::HasSessionId
|
32
|
-
include DriverExtensions::HasRemoteStatus
|
33
32
|
|
34
33
|
def initialize(bridge: nil, listener: nil, **opts)
|
35
34
|
desired_capabilities = opts[:desired_capabilities]
|
@@ -53,20 +53,6 @@ module Selenium
|
|
53
53
|
|
54
54
|
raise Error::WebDriverError, 'Unable to find Safari'
|
55
55
|
end
|
56
|
-
|
57
|
-
def driver_path=(path)
|
58
|
-
WebDriver.logger.deprecate 'Selenium::WebDriver::Safari#driver_path=',
|
59
|
-
'Selenium::WebDriver::Safari::Service#driver_path=',
|
60
|
-
id: :driver_path
|
61
|
-
Selenium::WebDriver::Safari::Service.driver_path = path
|
62
|
-
end
|
63
|
-
|
64
|
-
def driver_path
|
65
|
-
WebDriver.logger.deprecate 'Selenium::WebDriver::Safari#driver_path',
|
66
|
-
'Selenium::WebDriver::Safari::Service#driver_path',
|
67
|
-
id: :driver_path
|
68
|
-
Selenium::WebDriver::Safari::Service.driver_path
|
69
|
-
end
|
70
56
|
end
|
71
57
|
end # Safari
|
72
58
|
end # WebDriver
|
data/selenium-webdriver.gemspec
CHANGED
@@ -56,10 +56,10 @@ Gem::Specification.new do |s|
|
|
56
56
|
s.add_development_dependency 'rack', ['~> 2.0']
|
57
57
|
s.add_development_dependency 'rake'
|
58
58
|
s.add_development_dependency 'rspec', ['~> 3.0']
|
59
|
-
s.add_development_dependency 'rubocop', ['~> 1.
|
60
|
-
s.add_development_dependency 'rubocop-performance'
|
59
|
+
s.add_development_dependency 'rubocop', ['~> 1.31']
|
60
|
+
s.add_development_dependency 'rubocop-performance', ['~> 1.13']
|
61
61
|
s.add_development_dependency 'rubocop-rake'
|
62
|
-
s.add_development_dependency 'rubocop-rspec'
|
62
|
+
s.add_development_dependency 'rubocop-rspec', ['~> 2.12']
|
63
63
|
s.add_development_dependency 'webmock', ['~> 3.5']
|
64
64
|
s.add_development_dependency 'webrick', ['~> 1.7']
|
65
65
|
s.add_development_dependency 'yard', ['~> 0.9.11']
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: selenium-webdriver
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Rodionov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-
|
13
|
+
date: 2022-08-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: childprocess
|
@@ -162,28 +162,28 @@ dependencies:
|
|
162
162
|
requirements:
|
163
163
|
- - "~>"
|
164
164
|
- !ruby/object:Gem::Version
|
165
|
-
version: '1.
|
165
|
+
version: '1.31'
|
166
166
|
type: :development
|
167
167
|
prerelease: false
|
168
168
|
version_requirements: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
170
|
- - "~>"
|
171
171
|
- !ruby/object:Gem::Version
|
172
|
-
version: '1.
|
172
|
+
version: '1.31'
|
173
173
|
- !ruby/object:Gem::Dependency
|
174
174
|
name: rubocop-performance
|
175
175
|
requirement: !ruby/object:Gem::Requirement
|
176
176
|
requirements:
|
177
|
-
- - "
|
177
|
+
- - "~>"
|
178
178
|
- !ruby/object:Gem::Version
|
179
|
-
version: '
|
179
|
+
version: '1.13'
|
180
180
|
type: :development
|
181
181
|
prerelease: false
|
182
182
|
version_requirements: !ruby/object:Gem::Requirement
|
183
183
|
requirements:
|
184
|
-
- - "
|
184
|
+
- - "~>"
|
185
185
|
- !ruby/object:Gem::Version
|
186
|
-
version: '
|
186
|
+
version: '1.13'
|
187
187
|
- !ruby/object:Gem::Dependency
|
188
188
|
name: rubocop-rake
|
189
189
|
requirement: !ruby/object:Gem::Requirement
|
@@ -202,16 +202,16 @@ dependencies:
|
|
202
202
|
name: rubocop-rspec
|
203
203
|
requirement: !ruby/object:Gem::Requirement
|
204
204
|
requirements:
|
205
|
-
- - "
|
205
|
+
- - "~>"
|
206
206
|
- !ruby/object:Gem::Version
|
207
|
-
version: '
|
207
|
+
version: '2.12'
|
208
208
|
type: :development
|
209
209
|
prerelease: false
|
210
210
|
version_requirements: !ruby/object:Gem::Requirement
|
211
211
|
requirements:
|
212
|
-
- - "
|
212
|
+
- - "~>"
|
213
213
|
- !ruby/object:Gem::Version
|
214
|
-
version: '
|
214
|
+
version: '2.12'
|
215
215
|
- !ruby/object:Gem::Dependency
|
216
216
|
name: webmock
|
217
217
|
requirement: !ruby/object:Gem::Requirement
|
@@ -311,7 +311,6 @@ files:
|
|
311
311
|
- lib/selenium/webdriver/common/driver_extensions/has_network_interception.rb
|
312
312
|
- lib/selenium/webdriver/common/driver_extensions/has_permissions.rb
|
313
313
|
- lib/selenium/webdriver/common/driver_extensions/has_pinned_scripts.rb
|
314
|
-
- lib/selenium/webdriver/common/driver_extensions/has_remote_status.rb
|
315
314
|
- lib/selenium/webdriver/common/driver_extensions/has_session_id.rb
|
316
315
|
- lib/selenium/webdriver/common/driver_extensions/has_web_storage.rb
|
317
316
|
- lib/selenium/webdriver/common/driver_extensions/prints_page.rb
|
@@ -360,6 +359,9 @@ files:
|
|
360
359
|
- lib/selenium/webdriver/common/takes_screenshot.rb
|
361
360
|
- lib/selenium/webdriver/common/target_locator.rb
|
362
361
|
- lib/selenium/webdriver/common/timeouts.rb
|
362
|
+
- lib/selenium/webdriver/common/virtual_authenticator/credential.rb
|
363
|
+
- lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator.rb
|
364
|
+
- lib/selenium/webdriver/common/virtual_authenticator/virtual_authenticator_options.rb
|
363
365
|
- lib/selenium/webdriver/common/wait.rb
|
364
366
|
- lib/selenium/webdriver/common/websocket_connection.rb
|
365
367
|
- lib/selenium/webdriver/common/window.rb
|
@@ -368,6 +370,7 @@ files:
|
|
368
370
|
- lib/selenium/webdriver/devtools/console_event.rb
|
369
371
|
- lib/selenium/webdriver/devtools/exception_event.rb
|
370
372
|
- lib/selenium/webdriver/devtools/mutation_event.rb
|
373
|
+
- lib/selenium/webdriver/devtools/network_interceptor.rb
|
371
374
|
- lib/selenium/webdriver/devtools/pinned_script.rb
|
372
375
|
- lib/selenium/webdriver/devtools/request.rb
|
373
376
|
- lib/selenium/webdriver/devtools/response.rb
|
@@ -398,7 +401,6 @@ files:
|
|
398
401
|
- lib/selenium/webdriver/remote/http/common.rb
|
399
402
|
- lib/selenium/webdriver/remote/http/curb.rb
|
400
403
|
- lib/selenium/webdriver/remote/http/default.rb
|
401
|
-
- lib/selenium/webdriver/remote/http/persistent.rb
|
402
404
|
- lib/selenium/webdriver/remote/response.rb
|
403
405
|
- lib/selenium/webdriver/remote/server_error.rb
|
404
406
|
- lib/selenium/webdriver/safari.rb
|
@@ -443,7 +445,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
443
445
|
- !ruby/object:Gem::Version
|
444
446
|
version: 1.3.1
|
445
447
|
requirements: []
|
446
|
-
rubygems_version: 3.0.3
|
448
|
+
rubygems_version: 3.0.3.1
|
447
449
|
signing_key:
|
448
450
|
specification_version: 4
|
449
451
|
summary: Selenium is a browser automation tool for automated testing of webapps and
|