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.
- package/CHANGES.md +154 -137
- package/chrome.js +10 -36
- package/chromium.js +4 -2
- package/devtools/CDPConnection.js +1 -1
- package/edge.js +8 -32
- package/firefox.js +1 -1
- package/ie.js +3 -3
- package/index.js +1 -1
- package/lib/command.js +9 -0
- package/lib/http.js +40 -0
- package/lib/input.js +76 -23
- package/lib/virtual_authenticator.js +230 -0
- package/lib/webdriver.js +120 -11
- package/net/index.js +9 -2
- package/package.json +10 -10
- package/testing/index.js +17 -19
package/lib/http.js
CHANGED
|
@@ -347,6 +347,44 @@ const W3C_COMMAND_MAP = new Map([
|
|
|
347
347
|
|
|
348
348
|
// Server Extensions
|
|
349
349
|
[cmd.Name.UPLOAD_FILE, post('/session/:sessionId/se/file')],
|
|
350
|
+
|
|
351
|
+
// Virtual Authenticator
|
|
352
|
+
[
|
|
353
|
+
cmd.Name.ADD_VIRTUAL_AUTHENTICATOR,
|
|
354
|
+
post('/session/:sessionId/webauthn/authenticator'),
|
|
355
|
+
],
|
|
356
|
+
[
|
|
357
|
+
cmd.Name.REMOVE_VIRTUAL_AUTHENTICATOR,
|
|
358
|
+
del('/session/:sessionId/webauthn/authenticator/:authenticatorId'),
|
|
359
|
+
],
|
|
360
|
+
[
|
|
361
|
+
cmd.Name.ADD_CREDENTIAL,
|
|
362
|
+
post(
|
|
363
|
+
'/session/:sessionId/webauthn/authenticator/:authenticatorId/credential'
|
|
364
|
+
),
|
|
365
|
+
],
|
|
366
|
+
[
|
|
367
|
+
cmd.Name.GET_CREDENTIALS,
|
|
368
|
+
get(
|
|
369
|
+
'/session/:sessionId/webauthn/authenticator/:authenticatorId/credentials'
|
|
370
|
+
),
|
|
371
|
+
],
|
|
372
|
+
[
|
|
373
|
+
cmd.Name.REMOVE_CREDENTIAL,
|
|
374
|
+
del(
|
|
375
|
+
'/session/:sessionId/webauthn/authenticator/:authenticatorId/credentials/:credentialId'
|
|
376
|
+
),
|
|
377
|
+
],
|
|
378
|
+
[
|
|
379
|
+
cmd.Name.REMOVE_ALL_CREDENTIALS,
|
|
380
|
+
del(
|
|
381
|
+
'/session/:sessionId/webauthn/authenticator/:authenticatorId/credentials'
|
|
382
|
+
),
|
|
383
|
+
],
|
|
384
|
+
[
|
|
385
|
+
cmd.Name.SET_USER_VERIFIED,
|
|
386
|
+
post('/session/:sessionId/webauthn/authenticator/:authenticatorId/uv'),
|
|
387
|
+
],
|
|
350
388
|
])
|
|
351
389
|
|
|
352
390
|
/**
|
|
@@ -472,6 +510,7 @@ class Executor {
|
|
|
472
510
|
this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`)
|
|
473
511
|
|
|
474
512
|
let httpResponse = /** @type {!Response} */ (response)
|
|
513
|
+
|
|
475
514
|
let { isW3C, value } = parseHttpResponse(command, httpResponse)
|
|
476
515
|
|
|
477
516
|
if (command.getName() === cmd.Name.NEW_SESSION) {
|
|
@@ -530,6 +569,7 @@ function parseHttpResponse(command, httpResponse) {
|
|
|
530
569
|
}
|
|
531
570
|
|
|
532
571
|
let parsed = tryParse(httpResponse.body)
|
|
572
|
+
|
|
533
573
|
if (parsed && typeof parsed === 'object') {
|
|
534
574
|
let value = parsed.value
|
|
535
575
|
let isW3C =
|
package/lib/input.js
CHANGED
|
@@ -346,16 +346,42 @@ class Pointer extends Device {
|
|
|
346
346
|
|
|
347
347
|
/**
|
|
348
348
|
* @param {!Button=} button The button to press.
|
|
349
|
+
* @param width
|
|
350
|
+
* @param height
|
|
351
|
+
* @param pressure
|
|
352
|
+
* @param tangentialPressure
|
|
353
|
+
* @param tiltX
|
|
354
|
+
* @param tiltY
|
|
355
|
+
* @param twist
|
|
356
|
+
* @param altitudeAngle
|
|
357
|
+
* @param azimuthAngle
|
|
349
358
|
* @return {!Action} An action to press the specified button with this device.
|
|
350
359
|
* @package
|
|
351
360
|
*/
|
|
352
|
-
press(
|
|
353
|
-
|
|
354
|
-
|
|
361
|
+
press(
|
|
362
|
+
button = Button.LEFT,
|
|
363
|
+
width = 0,
|
|
364
|
+
height = 0,
|
|
365
|
+
pressure = 0,
|
|
366
|
+
tangentialPressure = 0,
|
|
367
|
+
tiltX = 0,
|
|
368
|
+
tiltY = 0,
|
|
369
|
+
twist = 0,
|
|
370
|
+
altitudeAngle = 0,
|
|
371
|
+
azimuthAngle = 0
|
|
372
|
+
) {
|
|
355
373
|
return {
|
|
356
|
-
type: Action.Type.POINTER_DOWN,
|
|
357
|
-
|
|
358
|
-
|
|
374
|
+
type: Action.Type.POINTER_DOWN,
|
|
375
|
+
button,
|
|
376
|
+
width,
|
|
377
|
+
height,
|
|
378
|
+
pressure,
|
|
379
|
+
tangentialPressure,
|
|
380
|
+
tiltX,
|
|
381
|
+
tiltY,
|
|
382
|
+
twist,
|
|
383
|
+
altitudeAngle,
|
|
384
|
+
azimuthAngle,
|
|
359
385
|
}
|
|
360
386
|
}
|
|
361
387
|
|
|
@@ -385,15 +411,36 @@ class Pointer extends Device {
|
|
|
385
411
|
* @return {!Action} The new action.
|
|
386
412
|
* @package
|
|
387
413
|
*/
|
|
388
|
-
move({
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
414
|
+
move({
|
|
415
|
+
x = 0,
|
|
416
|
+
y = 0,
|
|
417
|
+
duration = 100,
|
|
418
|
+
origin = Origin.VIEWPORT,
|
|
419
|
+
width = 0,
|
|
420
|
+
height = 0,
|
|
421
|
+
pressure = 0,
|
|
422
|
+
tangentialPressure = 0,
|
|
423
|
+
tiltX = 0,
|
|
424
|
+
tiltY = 0,
|
|
425
|
+
twist = 0,
|
|
426
|
+
altitudeAngle = 0,
|
|
427
|
+
azimuthAngle = 0,
|
|
392
428
|
}) {
|
|
393
429
|
return {
|
|
394
|
-
type: Action.Type.POINTER_MOVE,
|
|
395
|
-
|
|
396
|
-
|
|
430
|
+
type: Action.Type.POINTER_MOVE,
|
|
431
|
+
origin,
|
|
432
|
+
duration,
|
|
433
|
+
x,
|
|
434
|
+
y,
|
|
435
|
+
width,
|
|
436
|
+
height,
|
|
437
|
+
pressure,
|
|
438
|
+
tangentialPressure,
|
|
439
|
+
tiltX,
|
|
440
|
+
tiltY,
|
|
441
|
+
twist,
|
|
442
|
+
altitudeAngle,
|
|
443
|
+
azimuthAngle,
|
|
397
444
|
}
|
|
398
445
|
}
|
|
399
446
|
}
|
|
@@ -410,10 +457,9 @@ Pointer.Type = {
|
|
|
410
457
|
|
|
411
458
|
class Wheel extends Device {
|
|
412
459
|
/**
|
|
413
|
-
* @param {string} id the device ID
|
|
414
|
-
* @param {Pointer.Type} type the pointer type.
|
|
460
|
+
* @param {string} id the device ID..
|
|
415
461
|
*/
|
|
416
|
-
constructor(id
|
|
462
|
+
constructor(id) {
|
|
417
463
|
super(Device.Type.WHEEL, id)
|
|
418
464
|
}
|
|
419
465
|
|
|
@@ -423,15 +469,19 @@ class Wheel extends Device {
|
|
|
423
469
|
* @param {number} y starting y coordinate
|
|
424
470
|
* @param {number} deltaX Delta X to scroll to target
|
|
425
471
|
* @param {number} deltaY Delta Y to scroll to target
|
|
472
|
+
* @param {WebElement} origin element origin
|
|
426
473
|
* @param {number} duration duration ratio be the ratio of time delta and duration
|
|
427
474
|
* @returns {!Action} An action to scroll with this device.
|
|
428
475
|
*/
|
|
429
476
|
scroll(x, y, deltaX, deltaY, origin, duration) {
|
|
430
477
|
return {
|
|
431
478
|
type: Action.Type.SCROLL,
|
|
432
|
-
duration: duration,
|
|
433
|
-
|
|
434
|
-
|
|
479
|
+
duration: duration,
|
|
480
|
+
x: x,
|
|
481
|
+
y: y,
|
|
482
|
+
deltaX: deltaX,
|
|
483
|
+
deltaY: deltaY,
|
|
484
|
+
origin: origin,
|
|
435
485
|
}
|
|
436
486
|
}
|
|
437
487
|
}
|
|
@@ -795,18 +845,21 @@ class Actions {
|
|
|
795
845
|
* @param {number} deltax delta x to scroll to target
|
|
796
846
|
* @param {number} deltay delta y to scroll to target
|
|
797
847
|
* @param {number} duration duration ratio be the ratio of time delta and duration
|
|
798
|
-
* @returns {!
|
|
848
|
+
* @returns {!Actions} An action to scroll with this device.
|
|
799
849
|
*/
|
|
800
850
|
scroll(x, y, targetDeltaX, targetDeltaY, origin, duration) {
|
|
801
|
-
return this.insert(
|
|
851
|
+
return this.insert(
|
|
852
|
+
this.wheel_,
|
|
853
|
+
this.wheel_.scroll(x, y, targetDeltaX, targetDeltaY, origin, duration)
|
|
854
|
+
)
|
|
802
855
|
}
|
|
803
856
|
|
|
804
857
|
/**
|
|
805
858
|
* Inserts an action for moving the mouse `x` and `y` pixels relative to the
|
|
806
859
|
* specified `origin`. The `origin` may be defined as the mouse's
|
|
807
|
-
* {@linkplain ./input.Origin.POINTER current position}, the
|
|
860
|
+
* {@linkplain ./input.Origin.POINTER current position}, the top-left corner of the
|
|
808
861
|
* {@linkplain ./input.Origin.VIEWPORT viewport}, or the center of a specific
|
|
809
|
-
* {@linkplain ./webdriver.WebElement WebElement}.
|
|
862
|
+
* {@linkplain ./webdriver.WebElement WebElement}. Default is top left corner of the view-port if origin is not specified
|
|
810
863
|
*
|
|
811
864
|
* You may adjust how long the remote end should take, in milliseconds, to
|
|
812
865
|
* perform the move using the `duration` parameter (defaults to 100 ms).
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// Licensed to the Software Freedom Conservancy (SFC) under one
|
|
2
|
+
// or more contributor license agreements. See the NOTICE file
|
|
3
|
+
// distributed with this work for additional information
|
|
4
|
+
// regarding copyright ownership. The SFC licenses this file
|
|
5
|
+
// to you under the Apache License, Version 2.0 (the
|
|
6
|
+
// "License"); you may not use this file except in compliance
|
|
7
|
+
// with the License. You may obtain a copy of the License at
|
|
8
|
+
//
|
|
9
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
//
|
|
11
|
+
// Unless required by applicable law or agreed to in writing,
|
|
12
|
+
// software distributed under the License is distributed on an
|
|
13
|
+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
// KIND, either express or implied. See the License for the
|
|
15
|
+
// specific language governing permissions and limitations
|
|
16
|
+
// under the License.
|
|
17
|
+
|
|
18
|
+
'use strict'
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Options for the creation of virtual authenticators.
|
|
22
|
+
* @see http://w3c.github.io/webauthn/#sctn-automation
|
|
23
|
+
*/
|
|
24
|
+
class VirtualAuthenticatorOptions {
|
|
25
|
+
|
|
26
|
+
static Protocol = {
|
|
27
|
+
"CTAP2": 'ctap2',
|
|
28
|
+
"U2F": 'ctap1/u2f',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static Transport = {
|
|
32
|
+
"BLE": 'ble',
|
|
33
|
+
"USB": 'usb',
|
|
34
|
+
"NFC": 'nfc',
|
|
35
|
+
"INTERNAL": 'internal',
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Constructor to initialise VirtualAuthenticatorOptions object.
|
|
40
|
+
*/
|
|
41
|
+
constructor() {
|
|
42
|
+
this._protocol = VirtualAuthenticatorOptions.Protocol["CTAP2"]
|
|
43
|
+
this._transport = VirtualAuthenticatorOptions.Transport["USB"]
|
|
44
|
+
this._hasResidentKey = false
|
|
45
|
+
this._hasUserVerification = false
|
|
46
|
+
this._isUserConsenting = true
|
|
47
|
+
this._isUserVerified = false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getProtocol() {
|
|
51
|
+
return this._protocol
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
setProtocol(protocol) {
|
|
55
|
+
this._protocol = protocol
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
getTransport() {
|
|
59
|
+
return this._transport
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
setTransport(transport) {
|
|
63
|
+
this._transport = transport
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
getHasResidentKey() {
|
|
67
|
+
return this._hasResidentKey
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setHasResidentKey(value) {
|
|
71
|
+
this._hasResidentKey = value
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
getHasUserVerification() {
|
|
75
|
+
return this._hasUserVerification
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
setHasUserVerification(value) {
|
|
79
|
+
this._hasUserVerification = value
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getIsUserConsenting() {
|
|
83
|
+
return this._isUserConsenting
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setIsUserConsenting(value) {
|
|
87
|
+
this._isUserConsenting = value
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getIsUserVerified() {
|
|
91
|
+
return this._isUserVerified
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
setIsUserVerified(value) {
|
|
95
|
+
this._isUserVerified = value
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
toDict() {
|
|
99
|
+
return {
|
|
100
|
+
"protocol": this.getProtocol(),
|
|
101
|
+
"transport": this.getTransport(),
|
|
102
|
+
"hasResidentKey": this.getHasResidentKey(),
|
|
103
|
+
"hasUserVerification": this.getHasUserVerification(),
|
|
104
|
+
"isUserConsenting": this.getIsUserConsenting(),
|
|
105
|
+
"isUserVerified": this.getIsUserVerified(),
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* A credential stored in a virtual authenticator.
|
|
113
|
+
* @see https://w3c.github.io/webauthn/#credential-parameters
|
|
114
|
+
*/
|
|
115
|
+
class Credential {
|
|
116
|
+
constructor(
|
|
117
|
+
credentialId,
|
|
118
|
+
isResidentCredential,
|
|
119
|
+
rpId,
|
|
120
|
+
userHandle,
|
|
121
|
+
privateKey,
|
|
122
|
+
signCount
|
|
123
|
+
) {
|
|
124
|
+
this._id = credentialId
|
|
125
|
+
this._isResidentCredential = isResidentCredential
|
|
126
|
+
this._rpId = rpId
|
|
127
|
+
this._userHandle = userHandle
|
|
128
|
+
this._privateKey = privateKey
|
|
129
|
+
this._signCount = signCount
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
id() {
|
|
133
|
+
return this._id
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
isResidentCredential() {
|
|
137
|
+
return this._isResidentCredential
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
rpId() {
|
|
141
|
+
return this._rpId
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
userHandle() {
|
|
145
|
+
if (this._userHandle != null) {
|
|
146
|
+
return this._userHandle
|
|
147
|
+
}
|
|
148
|
+
return null
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
privateKey() {
|
|
152
|
+
return this._privateKey
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
signCount() {
|
|
156
|
+
return this._signCount
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Creates a resident (i.e. stateless) credential.
|
|
161
|
+
* @param id Unique base64 encoded string.
|
|
162
|
+
* @param rpId Relying party identifier.
|
|
163
|
+
* @param userHandle userHandle associated to the credential. Must be Base64 encoded string.
|
|
164
|
+
* @param privateKey Base64 encoded PKCS
|
|
165
|
+
* @param signCount initial value for a signature counter.
|
|
166
|
+
* @returns A resident credential
|
|
167
|
+
*/
|
|
168
|
+
createResidentCredential(id, rpId, userHandle, privateKey, signCount) {
|
|
169
|
+
return new Credential(id, true, rpId, userHandle, privateKey, signCount)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Creates a non-resident (i.e. stateless) credential.
|
|
174
|
+
* @param id Unique base64 encoded string.
|
|
175
|
+
* @param rpId Relying party identifier.
|
|
176
|
+
* @param privateKey Base64 encoded PKCS
|
|
177
|
+
* @param signCount initial value for a signature counter.
|
|
178
|
+
* @returns A non-resident credential
|
|
179
|
+
*/
|
|
180
|
+
createNonResidentCredential(id, rpId, privateKey, signCount) {
|
|
181
|
+
return new Credential(id, false, rpId, null, privateKey, signCount)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
toDict() {
|
|
185
|
+
let credentialData = {
|
|
186
|
+
'credentialId': Buffer.from(this._id).toString('base64url'),
|
|
187
|
+
'isResidentCredential': this._isResidentCredential,
|
|
188
|
+
'rpId': this._rpId,
|
|
189
|
+
'privateKey': Buffer.from(this._privateKey, 'binary').toString('base64url'),
|
|
190
|
+
'signCount': this._signCount,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (this.userHandle() != null) {
|
|
194
|
+
credentialData['userHandle'] = Buffer.from(this._userHandle).toString('base64url')
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return credentialData
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Creates a credential from a map.
|
|
202
|
+
*/
|
|
203
|
+
fromDict(data) {
|
|
204
|
+
let id = new Uint8Array(Buffer.from(data['credentialId'], 'base64url'))
|
|
205
|
+
let isResidentCredential = data['isResidentCredential']
|
|
206
|
+
let rpId = data['rpId']
|
|
207
|
+
let privateKey = Buffer.from(data['privateKey'], 'base64url').toString('binary')
|
|
208
|
+
let signCount = data['signCount']
|
|
209
|
+
let userHandle
|
|
210
|
+
|
|
211
|
+
if ('userHandle' in data) {
|
|
212
|
+
userHandle = new Uint8Array(Buffer.from(data['userHandle'], 'base64url'))
|
|
213
|
+
} else {
|
|
214
|
+
userHandle = null
|
|
215
|
+
}
|
|
216
|
+
return new Credential(
|
|
217
|
+
id,
|
|
218
|
+
isResidentCredential,
|
|
219
|
+
rpId,
|
|
220
|
+
userHandle,
|
|
221
|
+
privateKey,
|
|
222
|
+
signCount
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = {
|
|
228
|
+
Credential,
|
|
229
|
+
VirtualAuthenticatorOptions,
|
|
230
|
+
}
|
package/lib/webdriver.js
CHANGED
|
@@ -37,6 +37,7 @@ const { Capabilities } = require('./capabilities')
|
|
|
37
37
|
const path = require('path')
|
|
38
38
|
const { NoSuchElementError } = require('./error')
|
|
39
39
|
const cdpTargets = ['page', 'browser']
|
|
40
|
+
const Credential = require('./virtual_authenticator').Credential
|
|
40
41
|
|
|
41
42
|
// Capability names that are defined in the W3C spec.
|
|
42
43
|
const W3C_CAPABILITY_NAMES = new Set([
|
|
@@ -679,6 +680,9 @@ class WebDriver {
|
|
|
679
680
|
|
|
680
681
|
/** @private @const {(function(this: void): ?|undefined)} */
|
|
681
682
|
this.onQuit_ = onQuit
|
|
683
|
+
|
|
684
|
+
/** @private {./virtual_authenticator}*/
|
|
685
|
+
this.authenticatorId_ = null
|
|
682
686
|
}
|
|
683
687
|
|
|
684
688
|
/**
|
|
@@ -730,6 +734,7 @@ class WebDriver {
|
|
|
730
734
|
/** @override */
|
|
731
735
|
async execute(command) {
|
|
732
736
|
command.setParameter('sessionId', this.session_)
|
|
737
|
+
|
|
733
738
|
let parameters = await toWireValue(command.getParameters())
|
|
734
739
|
command.setParameters(parameters)
|
|
735
740
|
let value = await this.executor_.execute(command)
|
|
@@ -1363,12 +1368,11 @@ class WebDriver {
|
|
|
1363
1368
|
if (params.method === 'Fetch.requestPaused') {
|
|
1364
1369
|
const requestPausedParams = params['params']
|
|
1365
1370
|
if (requestPausedParams.request.url == httpResponse.urlToIntercept) {
|
|
1366
|
-
connection.execute('Fetch.
|
|
1371
|
+
connection.execute('Fetch.fulfillRequest', {
|
|
1367
1372
|
requestId: requestPausedParams['requestId'],
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
postData: httpResponse.body,
|
|
1373
|
+
responseCode: 200,
|
|
1374
|
+
responseHeaders: httpResponse.headers,
|
|
1375
|
+
body: httpResponse.body,
|
|
1372
1376
|
})
|
|
1373
1377
|
callback()
|
|
1374
1378
|
} else {
|
|
@@ -1515,6 +1519,110 @@ class WebDriver {
|
|
|
1515
1519
|
}
|
|
1516
1520
|
})
|
|
1517
1521
|
}
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
*
|
|
1525
|
+
* @returns The value of authenticator ID added
|
|
1526
|
+
*/
|
|
1527
|
+
virtualAuthenticatorId() {
|
|
1528
|
+
return this.authenticatorId_
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
/**
|
|
1532
|
+
* Adds a virtual authenticator with the given options.
|
|
1533
|
+
* @param options VirtualAuthenticatorOptions object to set authenticator optons.
|
|
1534
|
+
*/
|
|
1535
|
+
async addVirtualAuthenticator(options) {
|
|
1536
|
+
this.authenticatorId_ = await this.execute(
|
|
1537
|
+
new command.Command(command.Name.ADD_VIRTUAL_AUTHENTICATOR).setParameters(
|
|
1538
|
+
options.toDict()
|
|
1539
|
+
)
|
|
1540
|
+
)
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
/**
|
|
1544
|
+
* Removes a previously added virtual authenticator. The authenticator is no
|
|
1545
|
+
* longer valid after removal, so no methods may be called.
|
|
1546
|
+
*/
|
|
1547
|
+
async removeVirtualAuthenticator() {
|
|
1548
|
+
await this.execute(
|
|
1549
|
+
new command.Command(
|
|
1550
|
+
command.Name.REMOVE_VIRTUAL_AUTHENTICATOR
|
|
1551
|
+
).setParameter('authenticatorId', this.authenticatorId_)
|
|
1552
|
+
)
|
|
1553
|
+
this.authenticatorId_ = null
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
/**
|
|
1557
|
+
* Injects a credential into the authenticator.
|
|
1558
|
+
* @param credential Credential to be added
|
|
1559
|
+
*/
|
|
1560
|
+
async addCredential(credential) {
|
|
1561
|
+
credential = credential.toDict()
|
|
1562
|
+
credential['authenticatorId'] = this.authenticatorId_
|
|
1563
|
+
await this.execute(
|
|
1564
|
+
new command.Command(command.Name.ADD_CREDENTIAL).setParameters(credential)
|
|
1565
|
+
)
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
/**
|
|
1569
|
+
*
|
|
1570
|
+
* @returns The list of credentials owned by the authenticator.
|
|
1571
|
+
*/
|
|
1572
|
+
async getCredentials() {
|
|
1573
|
+
let credential_data = await this.execute(
|
|
1574
|
+
new command.Command(command.Name.GET_CREDENTIALS).setParameter(
|
|
1575
|
+
'authenticatorId',
|
|
1576
|
+
this.virtualAuthenticatorId()
|
|
1577
|
+
)
|
|
1578
|
+
)
|
|
1579
|
+
var credential_list = []
|
|
1580
|
+
for (var i = 0; i < credential_data.length; i++) {
|
|
1581
|
+
credential_list.push(new Credential().fromDict(credential_data[i]))
|
|
1582
|
+
}
|
|
1583
|
+
return credential_list
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
/**
|
|
1587
|
+
* Removes a credential from the authenticator.
|
|
1588
|
+
* @param credential_id The ID of the credential to be removed.
|
|
1589
|
+
*/
|
|
1590
|
+
async removeCredential(credential_id) {
|
|
1591
|
+
// If credential_id is not a base64url, then convert it to base64url.
|
|
1592
|
+
if (Array.isArray(credential_id)) {
|
|
1593
|
+
credential_id = Buffer.from(credential_id).toString('base64url')
|
|
1594
|
+
}
|
|
1595
|
+
|
|
1596
|
+
await this.execute(
|
|
1597
|
+
new command.Command(command.Name.REMOVE_CREDENTIAL)
|
|
1598
|
+
.setParameter('credentialId', credential_id)
|
|
1599
|
+
.setParameter('authenticatorId', this.authenticatorId_)
|
|
1600
|
+
)
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
/**
|
|
1604
|
+
* Removes all the credentials from the authenticator.
|
|
1605
|
+
*/
|
|
1606
|
+
async removeAllCredentials() {
|
|
1607
|
+
await this.execute(
|
|
1608
|
+
new command.Command(command.Name.REMOVE_ALL_CREDENTIALS).setParameter(
|
|
1609
|
+
'authenticatorId',
|
|
1610
|
+
this.authenticatorId_
|
|
1611
|
+
)
|
|
1612
|
+
)
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
/**
|
|
1616
|
+
* Sets whether the authenticator will simulate success or fail on user verification.
|
|
1617
|
+
* @param verified true if the authenticator will pass user verification, false otherwise.
|
|
1618
|
+
*/
|
|
1619
|
+
async setUserVerified(verified) {
|
|
1620
|
+
await this.execute(
|
|
1621
|
+
new command.Command(command.Name.SET_USER_VERIFIED)
|
|
1622
|
+
.setParameter('authenticatorId', this.authenticatorId_)
|
|
1623
|
+
.setParameter('isUserVerified', verified)
|
|
1624
|
+
)
|
|
1625
|
+
}
|
|
1518
1626
|
}
|
|
1519
1627
|
|
|
1520
1628
|
/**
|
|
@@ -2765,17 +2873,18 @@ class WebElement {
|
|
|
2765
2873
|
* when the form has been submitted.
|
|
2766
2874
|
*/
|
|
2767
2875
|
submit() {
|
|
2768
|
-
const script =
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2876
|
+
const script =
|
|
2877
|
+
'var form = arguments[0];\n' +
|
|
2878
|
+
'while (form.nodeName != "FORM" && form.parentNode) {\n' +
|
|
2879
|
+
' form = form.parentNode;\n' +
|
|
2880
|
+
'}\n' +
|
|
2772
2881
|
"if (!form) { throw Error('Unable to find containing form element'); }\n" +
|
|
2773
2882
|
"if (!form.ownerDocument) { throw Error('Unable to find owning document'); }\n" +
|
|
2774
2883
|
"var e = form.ownerDocument.createEvent('Event');\n" +
|
|
2775
2884
|
"e.initEvent('submit', true, true);\n" +
|
|
2776
|
-
|
|
2885
|
+
'if (form.dispatchEvent(e)) { HTMLFormElement.prototype.submit.call(form) }\n'
|
|
2777
2886
|
|
|
2778
|
-
this.driver_.executeScript(script, this)
|
|
2887
|
+
this.driver_.executeScript(script, this)
|
|
2779
2888
|
}
|
|
2780
2889
|
|
|
2781
2890
|
/**
|
package/net/index.js
CHANGED
|
@@ -48,7 +48,10 @@ function getIPAddress(loopback, family) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
for (let ipAddress of interfaces[key]) {
|
|
51
|
-
if (
|
|
51
|
+
if (
|
|
52
|
+
(ipAddress.family === family || `IPv${ipAddress.family}` === family) &&
|
|
53
|
+
ipAddress.internal === loopback
|
|
54
|
+
) {
|
|
52
55
|
return ipAddress.address
|
|
53
56
|
}
|
|
54
57
|
}
|
|
@@ -73,7 +76,11 @@ function getAddress(family = 'IPv4') {
|
|
|
73
76
|
* @return {(string|undefined)} The IP address or undefined if not available.
|
|
74
77
|
*/
|
|
75
78
|
function getLoopbackAddress(family = 'IPv4') {
|
|
76
|
-
|
|
79
|
+
let address = getIPAddress(true, family)
|
|
80
|
+
if (address === '127.0.0.1') {
|
|
81
|
+
address = 'localhost'
|
|
82
|
+
}
|
|
83
|
+
return address
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selenium-webdriver",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "The official WebDriver JavaScript bindings from the Selenium project",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -23,26 +23,26 @@
|
|
|
23
23
|
"node": ">= 10.15.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"jszip": "^3.
|
|
26
|
+
"jszip": "^3.10.0",
|
|
27
27
|
"tmp": "^0.2.1",
|
|
28
|
-
"ws": ">=7.
|
|
28
|
+
"ws": ">=8.7.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"eslint": "^
|
|
32
|
-
"eslint-config-prettier": "^8.
|
|
31
|
+
"eslint": "^8.16.0",
|
|
32
|
+
"eslint-config-prettier": "^8.5.0",
|
|
33
33
|
"eslint-plugin-no-only-tests": "^2.6.0",
|
|
34
34
|
"eslint-plugin-node": "^11.1.0",
|
|
35
|
-
"eslint-plugin-prettier": "^
|
|
35
|
+
"eslint-plugin-prettier": "^4.0.0",
|
|
36
36
|
"express": "^4.17.1",
|
|
37
37
|
"jasmine": "^3.8.0",
|
|
38
|
-
"mocha": "^
|
|
39
|
-
"multer": "^1.4.
|
|
40
|
-
"prettier": "^2.
|
|
38
|
+
"mocha": "^10.0.0",
|
|
39
|
+
"multer": "^1.4.5-lts.1",
|
|
40
|
+
"prettier": "^2.6.1",
|
|
41
41
|
"serve-index": "^1.9.1",
|
|
42
42
|
"sinon": "^10.0.0"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"lint": "eslint --ignore-pattern node_modules --ignore-pattern generator --ext js lib/http.js \"**/*.js\"",
|
|
45
|
+
"lint": "eslint --ignore-pattern node_modules --ignore-pattern generator --fix --ext js lib/http.js \"**/*.js\"",
|
|
46
46
|
"test": "npm run lint && mocha -t 600000 --recursive test",
|
|
47
47
|
"test-jasmine": "jasmine JASMINE_CONFIG_PATH=jasmine.json"
|
|
48
48
|
},
|