selenium-webdriver 4.25.0 → 4.27.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 +16 -0
- package/bidi/browsingContext.js +7 -3
- package/bidi/continueRequestParameters.js +1 -1
- package/bidi/filterBy.js +1 -1
- package/bidi/logEntries.js +3 -1
- package/bidi/protocolValue.js +2 -2
- package/bidi/storage.js +2 -10
- package/bin/linux/selenium-manager +0 -0
- package/bin/macos/selenium-manager +0 -0
- package/bin/windows/selenium-manager.exe +0 -0
- package/lib/network.js +34 -21
- package/lib/webdriver.js +30 -15
- package/package.json +22 -12
package/CHANGES.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 4.27.0
|
|
2
|
+
|
|
3
|
+
- Add CDP for Chrome 131 and remove 128
|
|
4
|
+
- Add Firefox CDP deprecation warnings
|
|
5
|
+
- Update supported versions for Chrome DevTools
|
|
6
|
+
- [bidi] Allow passing in uri for authentication handlers (#14386)
|
|
7
|
+
- [bidi] Enable locate node tests for Chrome and Edge
|
|
8
|
+
- [bidi] Ensure start nodes are serialized
|
|
9
|
+
|
|
10
|
+
## 4.26.0
|
|
11
|
+
|
|
12
|
+
- Add CDP for Chrome 130 and remove 127
|
|
13
|
+
- Fix sendKeys command fail on FileDetector.handleFile error (#14663)
|
|
14
|
+
- Update dependencies to latest versions to resolve security alerts
|
|
15
|
+
- Close BiDi websocket connection (#14507)
|
|
16
|
+
|
|
1
17
|
## 4.25.0
|
|
2
18
|
|
|
3
19
|
- Add CDP for Chrome 129 and remove 126
|
package/bidi/browsingContext.js
CHANGED
|
@@ -156,8 +156,7 @@ class BrowsingContext {
|
|
|
156
156
|
method: 'browsingContext.create',
|
|
157
157
|
params: Object.fromEntries(parameters),
|
|
158
158
|
}
|
|
159
|
-
|
|
160
|
-
return res
|
|
159
|
+
return await this.bidi.send(params)
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
/**
|
|
@@ -528,10 +527,15 @@ class BrowsingContext {
|
|
|
528
527
|
throw Error(`Pass in an array of ReferenceValue objects. Received: ${startNodes}`)
|
|
529
528
|
}
|
|
530
529
|
|
|
530
|
+
let startNodesSerialized = undefined
|
|
531
|
+
|
|
531
532
|
if (startNodes !== undefined && Array.isArray(startNodes)) {
|
|
533
|
+
startNodesSerialized = []
|
|
532
534
|
startNodes.forEach((node) => {
|
|
533
535
|
if (!(node instanceof ReferenceValue)) {
|
|
534
536
|
throw Error(`Pass in a ReferenceValue object. Received: ${node}`)
|
|
537
|
+
} else {
|
|
538
|
+
startNodesSerialized.push(node.asMap())
|
|
535
539
|
}
|
|
536
540
|
})
|
|
537
541
|
}
|
|
@@ -544,7 +548,7 @@ class BrowsingContext {
|
|
|
544
548
|
maxNodeCount: maxNodeCount,
|
|
545
549
|
sandbox: sandbox,
|
|
546
550
|
serializationOptions: serializationOptions,
|
|
547
|
-
startNodes:
|
|
551
|
+
startNodes: startNodesSerialized,
|
|
548
552
|
},
|
|
549
553
|
}
|
|
550
554
|
|
|
@@ -47,7 +47,7 @@ class ContinueRequestParameters {
|
|
|
47
47
|
* Sets the cookies for the request.
|
|
48
48
|
*
|
|
49
49
|
* @param {Header[]} cookieHeaders - An array of cookie headers.
|
|
50
|
-
* @returns {
|
|
50
|
+
* @returns {ContinueRequestParameters} - The current instance of the ContinueRequestParameters for chaining.
|
|
51
51
|
* @throws {Error} - If a cookie header is not an instance of Header.
|
|
52
52
|
*/
|
|
53
53
|
cookies(cookieHeaders) {
|
package/bidi/filterBy.js
CHANGED
|
@@ -21,7 +21,7 @@ class FilterBy {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
static logLevel(level) {
|
|
24
|
-
if (level === undefined || (level
|
|
24
|
+
if (level === undefined || (level !== undefined && !['debug', 'error', 'info', 'warning'].includes(level))) {
|
|
25
25
|
throw Error(
|
|
26
26
|
`Please pass valid log level. Valid log levels are 'debug', 'error', 'info' and 'warning'. Received: ${level}`,
|
|
27
27
|
)
|
package/bidi/logEntries.js
CHANGED
|
@@ -21,12 +21,13 @@ const { Source } = require('./scriptTypes')
|
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* Represents a base log entry.
|
|
24
|
-
*
|
|
24
|
+
* Described in https://w3c.github.io/webdriver-bidi/#types-log-logentry.
|
|
25
25
|
*/
|
|
26
26
|
class BaseLogEntry {
|
|
27
27
|
/**
|
|
28
28
|
* Creates a new instance of BaseLogEntry.
|
|
29
29
|
* @param {string} level - The log level.
|
|
30
|
+
* @param {source} source - Script Source
|
|
30
31
|
* @param {string} text - The log source.
|
|
31
32
|
* @param {string} text - The log text.
|
|
32
33
|
* @param {number} timeStamp - The log timestamp.
|
|
@@ -86,6 +87,7 @@ class GenericLogEntry extends BaseLogEntry {
|
|
|
86
87
|
/**
|
|
87
88
|
* Creates an instance of GenericLogEntry.
|
|
88
89
|
* @param {string} level - The log level.
|
|
90
|
+
* @param {source} source - Script Source
|
|
89
91
|
* @param {string} text - The log text.
|
|
90
92
|
* @param {Date} timeStamp - The log timestamp.
|
|
91
93
|
* @param {string} type - The log type.
|
package/bidi/protocolValue.js
CHANGED
|
@@ -145,7 +145,7 @@ class LocalValue {
|
|
|
145
145
|
/**
|
|
146
146
|
* Creates a new LocalValue object from the passed object.
|
|
147
147
|
*
|
|
148
|
-
* @param {Object}
|
|
148
|
+
* @param {Object} object - The object.
|
|
149
149
|
* @returns {LocalValue} - The created LocalValue object.
|
|
150
150
|
*/
|
|
151
151
|
static createObjectValue(object) {
|
|
@@ -431,7 +431,7 @@ class ChannelValue {
|
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
if (resultOwnership
|
|
434
|
+
if (resultOwnership !== undefined) {
|
|
435
435
|
if (['root', 'none'].includes(resultOwnership)) {
|
|
436
436
|
this.resultOwnership = resultOwnership
|
|
437
437
|
} else {
|
package/bidi/storage.js
CHANGED
|
@@ -138,11 +138,7 @@ class Storage {
|
|
|
138
138
|
Object.prototype.hasOwnProperty.call(response.result.partitionKey, 'userContext') &&
|
|
139
139
|
Object.prototype.hasOwnProperty.call(response.result.partitionKey, 'sourceOrigin')
|
|
140
140
|
) {
|
|
141
|
-
|
|
142
|
-
response.result.partitionKey.userContext,
|
|
143
|
-
response.result.partitionKey.sourceOrigin,
|
|
144
|
-
)
|
|
145
|
-
return partitionKey
|
|
141
|
+
return new PartitionKey(response.result.partitionKey.userContext, response.result.partitionKey.sourceOrigin)
|
|
146
142
|
}
|
|
147
143
|
}
|
|
148
144
|
}
|
|
@@ -182,11 +178,7 @@ class Storage {
|
|
|
182
178
|
Object.prototype.hasOwnProperty.call(response.result.partitionKey, 'userContext') &&
|
|
183
179
|
Object.prototype.hasOwnProperty.call(response.result.partitionKey, 'sourceOrigin')
|
|
184
180
|
) {
|
|
185
|
-
|
|
186
|
-
response.result.partitionKey.userContext,
|
|
187
|
-
response.result.partitionKey.sourceOrigin,
|
|
188
|
-
)
|
|
189
|
-
return partitionKey
|
|
181
|
+
return new PartitionKey(response.result.partitionKey.userContext, response.result.partitionKey.sourceOrigin)
|
|
190
182
|
}
|
|
191
183
|
}
|
|
192
184
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/network.js
CHANGED
|
@@ -20,9 +20,10 @@ const { InterceptPhase } = require('../bidi/interceptPhase')
|
|
|
20
20
|
const { AddInterceptParameters } = require('../bidi/addInterceptParameters')
|
|
21
21
|
|
|
22
22
|
class Network {
|
|
23
|
+
#callbackId = 0
|
|
23
24
|
#driver
|
|
24
25
|
#network
|
|
25
|
-
#
|
|
26
|
+
#authHandlers = new Map()
|
|
26
27
|
|
|
27
28
|
constructor(driver) {
|
|
28
29
|
this.#driver = driver
|
|
@@ -30,7 +31,7 @@ class Network {
|
|
|
30
31
|
|
|
31
32
|
// This should be done in the constructor.
|
|
32
33
|
// But since it needs to call async methods we cannot do that in the constructor.
|
|
33
|
-
// We can have a separate async method that initialises the
|
|
34
|
+
// We can have a separate async method that initialises the Network instance.
|
|
34
35
|
// However, that pattern does not allow chaining the methods as we would like the user to use it.
|
|
35
36
|
// Since it involves awaiting to get the instance and then another await to call the method.
|
|
36
37
|
// Using this allows the user to do this "await driver.network.addAuthenticationHandler(callback)"
|
|
@@ -39,39 +40,51 @@ class Network {
|
|
|
39
40
|
return
|
|
40
41
|
}
|
|
41
42
|
this.#network = await network(this.#driver)
|
|
42
|
-
}
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
await this.#init()
|
|
44
|
+
await this.#network.addIntercept(new AddInterceptParameters(InterceptPhase.AUTH_REQUIRED))
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
await this.#network.authRequired(async (event) => {
|
|
47
|
+
const requestId = event.request.request
|
|
48
|
+
const uri = event.request.url
|
|
49
|
+
const credentials = this.getAuthCredentials(uri)
|
|
50
|
+
if (credentials !== null) {
|
|
51
|
+
await this.#network.continueWithAuth(requestId, credentials.username, credentials.password)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
48
54
|
|
|
49
|
-
|
|
50
|
-
await this.#network.continueWithAuth(event.request.request, username, password)
|
|
55
|
+
await this.#network.continueWithAuthNoCredentials(requestId)
|
|
51
56
|
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getAuthCredentials(uri) {
|
|
60
|
+
for (let [, value] of this.#authHandlers) {
|
|
61
|
+
if (uri.match(value.uri)) {
|
|
62
|
+
return value
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return null
|
|
66
|
+
}
|
|
67
|
+
async addAuthenticationHandler(username, password, uri = '//') {
|
|
68
|
+
await this.#init()
|
|
52
69
|
|
|
53
|
-
this.#
|
|
70
|
+
const id = this.#callbackId++
|
|
71
|
+
|
|
72
|
+
this.#authHandlers.set(id, { username, password, uri })
|
|
54
73
|
return id
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
async removeAuthenticationHandler(id) {
|
|
58
77
|
await this.#init()
|
|
59
78
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.#callBackInterceptIdMap.delete(id)
|
|
79
|
+
if (this.#authHandlers.has(id)) {
|
|
80
|
+
this.#authHandlers.delete(id)
|
|
81
|
+
} else {
|
|
82
|
+
throw Error(`Callback with id ${id} not found`)
|
|
83
|
+
}
|
|
66
84
|
}
|
|
67
85
|
|
|
68
86
|
async clearAuthenticationHandlers() {
|
|
69
|
-
|
|
70
|
-
await this.#network.removeIntercept(value)
|
|
71
|
-
await this.#network.removeCallback(key)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
this.#callBackInterceptIdMap.clear()
|
|
87
|
+
this.#authHandlers.clear()
|
|
75
88
|
}
|
|
76
89
|
}
|
|
77
90
|
|
package/lib/webdriver.js
CHANGED
|
@@ -789,8 +789,13 @@ class WebDriver {
|
|
|
789
789
|
// If the websocket connection is not closed,
|
|
790
790
|
// and we are running CDP sessions against the Selenium Grid,
|
|
791
791
|
// the node process never exits since the websocket connection is open until the Grid is shutdown.
|
|
792
|
-
if (this.
|
|
793
|
-
this.
|
|
792
|
+
if (this._cdpWsConnection !== undefined) {
|
|
793
|
+
this._cdpWsConnection.close()
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Close the BiDi websocket connection
|
|
797
|
+
if (this._bidiConnection !== undefined) {
|
|
798
|
+
this._bidiConnection.close()
|
|
794
799
|
}
|
|
795
800
|
})
|
|
796
801
|
}
|
|
@@ -1225,6 +1230,12 @@ class WebDriver {
|
|
|
1225
1230
|
|
|
1226
1231
|
const caps = await this.getCapabilities()
|
|
1227
1232
|
|
|
1233
|
+
if (caps['map_'].get('browserName') === 'firefox') {
|
|
1234
|
+
console.warn(
|
|
1235
|
+
'CDP support for Firefox is deprecated and will be removed in future versions. Please switch to WebDriver BiDi.',
|
|
1236
|
+
)
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1228
1239
|
if (process.env.SELENIUM_REMOTE_URL) {
|
|
1229
1240
|
const host = new URL(process.env.SELENIUM_REMOTE_URL).host
|
|
1230
1241
|
const sessionId = await this.getSession().then((session) => session.getId())
|
|
@@ -1241,18 +1252,18 @@ class WebDriver {
|
|
|
1241
1252
|
this._wsUrl = await this.getWsUrl(debuggerUrl, target, caps)
|
|
1242
1253
|
return new Promise((resolve, reject) => {
|
|
1243
1254
|
try {
|
|
1244
|
-
this.
|
|
1245
|
-
this._cdpConnection = new cdp.CdpConnection(this.
|
|
1255
|
+
this._cdpWsConnection = new WebSocket(this._wsUrl.replace('localhost', '127.0.0.1'))
|
|
1256
|
+
this._cdpConnection = new cdp.CdpConnection(this._cdpWsConnection)
|
|
1246
1257
|
} catch (err) {
|
|
1247
1258
|
reject(err)
|
|
1248
1259
|
return
|
|
1249
1260
|
}
|
|
1250
1261
|
|
|
1251
|
-
this.
|
|
1262
|
+
this._cdpWsConnection.on('open', async () => {
|
|
1252
1263
|
await this.getCdpTargets()
|
|
1253
1264
|
})
|
|
1254
1265
|
|
|
1255
|
-
this.
|
|
1266
|
+
this._cdpWsConnection.on('message', async (message) => {
|
|
1256
1267
|
const params = JSON.parse(message)
|
|
1257
1268
|
if (params.result) {
|
|
1258
1269
|
if (params.result.targetInfos) {
|
|
@@ -1273,7 +1284,7 @@ class WebDriver {
|
|
|
1273
1284
|
}
|
|
1274
1285
|
})
|
|
1275
1286
|
|
|
1276
|
-
this.
|
|
1287
|
+
this._cdpWsConnection.on('error', (error) => {
|
|
1277
1288
|
reject(error)
|
|
1278
1289
|
})
|
|
1279
1290
|
})
|
|
@@ -1288,9 +1299,12 @@ class WebDriver {
|
|
|
1288
1299
|
* @returns {BIDI}
|
|
1289
1300
|
*/
|
|
1290
1301
|
async getBidi() {
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1302
|
+
if (this._bidiConnection === undefined) {
|
|
1303
|
+
const caps = await this.getCapabilities()
|
|
1304
|
+
let WebSocketUrl = caps['map_'].get('webSocketUrl')
|
|
1305
|
+
this._bidiConnection = new BIDI(WebSocketUrl.replace('localhost', '127.0.0.1'))
|
|
1306
|
+
}
|
|
1307
|
+
return this._bidiConnection
|
|
1294
1308
|
}
|
|
1295
1309
|
|
|
1296
1310
|
/**
|
|
@@ -1338,7 +1352,7 @@ class WebDriver {
|
|
|
1338
1352
|
* @param connection CDP Connection
|
|
1339
1353
|
*/
|
|
1340
1354
|
async register(username, password, connection) {
|
|
1341
|
-
this.
|
|
1355
|
+
this._cdpWsConnection.on('message', (message) => {
|
|
1342
1356
|
const params = JSON.parse(message)
|
|
1343
1357
|
|
|
1344
1358
|
if (params.method === 'Fetch.authRequired') {
|
|
@@ -1383,7 +1397,7 @@ class WebDriver {
|
|
|
1383
1397
|
* @param callback callback called when we intercept requests.
|
|
1384
1398
|
*/
|
|
1385
1399
|
async onIntercept(connection, httpResponse, callback) {
|
|
1386
|
-
this.
|
|
1400
|
+
this._cdpWsConnection.on('message', (message) => {
|
|
1387
1401
|
const params = JSON.parse(message)
|
|
1388
1402
|
if (params.method === 'Fetch.requestPaused') {
|
|
1389
1403
|
const requestPausedParams = params['params']
|
|
@@ -1420,7 +1434,7 @@ class WebDriver {
|
|
|
1420
1434
|
* @returns {Promise<void>}
|
|
1421
1435
|
*/
|
|
1422
1436
|
async onLogEvent(connection, callback) {
|
|
1423
|
-
this.
|
|
1437
|
+
this._cdpWsConnection.on('message', (message) => {
|
|
1424
1438
|
const params = JSON.parse(message)
|
|
1425
1439
|
if (params.method === 'Runtime.consoleAPICalled') {
|
|
1426
1440
|
const consoleEventParams = params['params']
|
|
@@ -1457,7 +1471,7 @@ class WebDriver {
|
|
|
1457
1471
|
async onLogException(connection, callback) {
|
|
1458
1472
|
await connection.execute('Runtime.enable', {}, null)
|
|
1459
1473
|
|
|
1460
|
-
this.
|
|
1474
|
+
this._cdpWsConnection.on('message', (message) => {
|
|
1461
1475
|
const params = JSON.parse(message)
|
|
1462
1476
|
|
|
1463
1477
|
if (params.method === 'Runtime.exceptionThrown') {
|
|
@@ -1510,7 +1524,7 @@ class WebDriver {
|
|
|
1510
1524
|
null,
|
|
1511
1525
|
)
|
|
1512
1526
|
|
|
1513
|
-
this.
|
|
1527
|
+
this._cdpWsConnection.on('message', async (message) => {
|
|
1514
1528
|
const params = JSON.parse(message)
|
|
1515
1529
|
if (params.method === 'Runtime.bindingCalled') {
|
|
1516
1530
|
let payload = JSON.parse(params['params']['payload'])
|
|
@@ -2744,6 +2758,7 @@ class WebElement {
|
|
|
2744
2758
|
keys = await this.driver_.fileDetector_.handleFile(this.driver_, keys.join(''))
|
|
2745
2759
|
} catch (ex) {
|
|
2746
2760
|
this.log_.severe('Error trying parse string as a file with file detector; sending keys instead' + ex)
|
|
2761
|
+
keys = keys.join('')
|
|
2747
2762
|
}
|
|
2748
2763
|
|
|
2749
2764
|
return this.execute_(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selenium-webdriver",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.27.0",
|
|
4
4
|
"description": "The official WebDriver JavaScript bindings from the Selenium project",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -23,30 +23,30 @@
|
|
|
23
23
|
"node": ">= 14.21.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@bazel/runfiles": "^
|
|
26
|
+
"@bazel/runfiles": "^6.3.1",
|
|
27
27
|
"jszip": "^3.10.1",
|
|
28
28
|
"tmp": "^0.2.3",
|
|
29
29
|
"ws": "^8.18.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@eslint/js": "^9.
|
|
32
|
+
"@eslint/js": "^9.14.0",
|
|
33
33
|
"clean-jsdoc-theme": "^4.3.0",
|
|
34
|
-
"eslint": "^9.
|
|
34
|
+
"eslint": "^9.14.0",
|
|
35
35
|
"eslint-config-prettier": "^9.1.0",
|
|
36
36
|
"eslint-plugin-mocha": "^10.5.0",
|
|
37
|
-
"eslint-plugin-n": "^17.
|
|
38
|
-
"eslint-plugin-no-only-tests": "^3.
|
|
37
|
+
"eslint-plugin-n": "^17.13.1",
|
|
38
|
+
"eslint-plugin-no-only-tests": "^3.3.0",
|
|
39
39
|
"eslint-plugin-prettier": "^5.2.1",
|
|
40
|
-
"express": "^4.
|
|
41
|
-
"globals": "^15.
|
|
40
|
+
"express": "^4.21.1",
|
|
41
|
+
"globals": "^15.12.0",
|
|
42
42
|
"has-flag": "^5.0.1",
|
|
43
|
-
"jsdoc": "^4.0.
|
|
44
|
-
"mocha": "^10.
|
|
43
|
+
"jsdoc": "^4.0.4",
|
|
44
|
+
"mocha": "^10.8.2",
|
|
45
45
|
"mocha-junit-reporter": "^2.2.1",
|
|
46
46
|
"multer": "1.4.5-lts.1",
|
|
47
47
|
"prettier": "^3.3.3",
|
|
48
48
|
"serve-index": "^1.9.1",
|
|
49
|
-
"sinon": "^
|
|
49
|
+
"sinon": "^19.0.2",
|
|
50
50
|
"supports-color": "^9.4.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
@@ -61,5 +61,15 @@
|
|
|
61
61
|
},
|
|
62
62
|
"publishConfig": {
|
|
63
63
|
"registry": "https://registry.npmjs.org/"
|
|
64
|
-
}
|
|
64
|
+
},
|
|
65
|
+
"funding": [
|
|
66
|
+
{
|
|
67
|
+
"type": "github",
|
|
68
|
+
"url": "https://github.com/sponsors/SeleniumHQ"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"type": "opencollective",
|
|
72
|
+
"url": "https://opencollective.com/selenium"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
65
75
|
}
|