selenium-webdriver 4.47.0 → 4.49.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 +19 -0
- package/bidi/domain.js +87 -0
- package/bidi/generated/browsing_context.d.ts +5 -0
- package/bidi/generated/emulation.d.ts +30 -4
- package/bidi/index.js +187 -15
- package/bidi/serialization/enum.js +35 -0
- package/bidi/serialization/record.js +345 -0
- package/bidi/serialization/registry.js +34 -0
- package/bidi/serialization/union.js +102 -0
- package/bin/linux-arm64/selenium-manager +0 -0
- package/bin/{linux → linux-x86_64}/selenium-manager +0 -0
- package/bin/macos/selenium-manager +0 -0
- package/bin/selenium-manager-THIRD-PARTY-NOTICES.txt +343 -129
- package/bin/selenium-manager.cdx.json +947 -868
- package/bin/windows/selenium-manager.exe +0 -0
- package/chromium.js +1 -1
- package/common/seleniumManager.js +2 -2
- package/example/chrome_mobile_emulation.js +1 -1
- package/lib/bidi_connection.js +84 -0
- package/lib/logging.js +35 -0
- package/lib/webdriver.js +56 -19
- package/package.json +4 -4
|
Binary file
|
package/chromium.js
CHANGED
|
@@ -506,7 +506,7 @@ class Options extends Capabilities {
|
|
|
506
506
|
* __Example 1: Using a Pre-configured Device__
|
|
507
507
|
*
|
|
508
508
|
* let options = new chrome.Options().setMobileEmulation(
|
|
509
|
-
* {deviceName: '
|
|
509
|
+
* {deviceName: 'Pixel 10'});
|
|
510
510
|
*
|
|
511
511
|
* let driver = chrome.Driver.createSession(options);
|
|
512
512
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* Wrapper for getting information from the Selenium Manager binaries
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
const { platform } = require('node:process')
|
|
24
|
+
const { platform, arch } = require('node:process')
|
|
25
25
|
const path = require('node:path')
|
|
26
26
|
const fs = require('node:fs')
|
|
27
27
|
const spawnSync = require('node:child_process').spawnSync
|
|
@@ -39,7 +39,7 @@ function getBinary() {
|
|
|
39
39
|
darwin: 'macos',
|
|
40
40
|
win32: 'windows',
|
|
41
41
|
cygwin: 'windows',
|
|
42
|
-
linux: 'linux',
|
|
42
|
+
linux: arch === 'arm64' ? 'linux-arm64' : 'linux-x86_64',
|
|
43
43
|
}[platform]
|
|
44
44
|
|
|
45
45
|
const file = directory === 'windows' ? 'selenium-manager.exe' : 'selenium-manager'
|
|
@@ -30,7 +30,7 @@ const { Options } = require('../chrome')
|
|
|
30
30
|
try {
|
|
31
31
|
driver = await new Builder()
|
|
32
32
|
.forBrowser('chrome')
|
|
33
|
-
.setChromeOptions(new Options().setMobileEmulation({ deviceName: '
|
|
33
|
+
.setChromeOptions(new Options().setMobileEmulation({ deviceName: 'Pixel 10' }))
|
|
34
34
|
.build()
|
|
35
35
|
await driver.get('http://www.google.com/ncr')
|
|
36
36
|
await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN)
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
const BiDi = require('../bidi')
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One BiDi connection per driver, kept outside the WebDriver class itself so
|
|
22
|
+
* it isn't a discoverable method on it — see
|
|
23
|
+
* docs/decisions/17670-bidi-implementation-boundaries.md. Not re-exported from
|
|
24
|
+
* the package's public entry point.
|
|
25
|
+
*
|
|
26
|
+
* Stores the in-flight promise, not the resolved connection, so a second
|
|
27
|
+
* concurrent call for the same driver awaits the same creation instead of
|
|
28
|
+
* racing its own and leaking whichever connection loses.
|
|
29
|
+
* @type {WeakMap<object, Promise<BiDi>>}
|
|
30
|
+
*/
|
|
31
|
+
const connections = new WeakMap()
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Returns the BiDi connection for `driver`, creating it on first access.
|
|
35
|
+
* @param {object} driver The WebDriver instance to obtain a BiDi connection for.
|
|
36
|
+
* @returns {Promise<BiDi>} A promise resolving to `driver`'s BiDi connection, shared
|
|
37
|
+
* with any other in-flight or already-resolved call for the same driver.
|
|
38
|
+
*/
|
|
39
|
+
function getBidiConnection(driver) {
|
|
40
|
+
if (!connections.has(driver)) {
|
|
41
|
+
connections.set(driver, createConnection(driver))
|
|
42
|
+
}
|
|
43
|
+
return connections.get(driver)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @param {object} driver
|
|
48
|
+
* @returns {Promise<BiDi>}
|
|
49
|
+
*/
|
|
50
|
+
async function createConnection(driver) {
|
|
51
|
+
const caps = await driver.getCapabilities()
|
|
52
|
+
const webSocketUrl = caps['map_'].get('webSocketUrl')
|
|
53
|
+
if (!webSocketUrl) {
|
|
54
|
+
throw new Error('WebDriver instance must support BiDi protocol')
|
|
55
|
+
}
|
|
56
|
+
return new BiDi(webSocketUrl.replace('localhost', '127.0.0.1'))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Closes `driver`'s BiDi connection, if one was ever opened. A no-op
|
|
61
|
+
* otherwise — must not lazily create a connection just to close it.
|
|
62
|
+
*
|
|
63
|
+
* Callers (e.g. quit()) invoke this fire-and-forget, so it must never reject:
|
|
64
|
+
* if the original connection attempt itself had failed, `pending` is already
|
|
65
|
+
* rejected and there is nothing live to close.
|
|
66
|
+
* @param {object} driver The WebDriver instance whose BiDi connection should be closed.
|
|
67
|
+
* @returns {Promise<void>} A promise that always resolves, once any open connection
|
|
68
|
+
* has been closed (or immediately, if none was ever opened).
|
|
69
|
+
*/
|
|
70
|
+
async function closeBidiConnection(driver) {
|
|
71
|
+
const pending = connections.get(driver)
|
|
72
|
+
if (pending === undefined) {
|
|
73
|
+
return
|
|
74
|
+
}
|
|
75
|
+
connections.delete(driver)
|
|
76
|
+
try {
|
|
77
|
+
const connection = await pending
|
|
78
|
+
await connection.close()
|
|
79
|
+
} catch {
|
|
80
|
+
// Nothing to close — the original connection attempt failed.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = { getBidiConnection, closeBidiConnection }
|
package/lib/logging.js
CHANGED
|
@@ -271,6 +271,9 @@ class Logger {
|
|
|
271
271
|
|
|
272
272
|
/** @private {Set<function(!Entry)>} */
|
|
273
273
|
this.handlers_ = null
|
|
274
|
+
|
|
275
|
+
/** @private {Set<string>} ids already reported via {@link #deprecate}. */
|
|
276
|
+
this.deprecated_ = new Set()
|
|
274
277
|
}
|
|
275
278
|
|
|
276
279
|
/** @return {string} the name of this logger. */
|
|
@@ -392,6 +395,38 @@ class Logger {
|
|
|
392
395
|
this.log(Level.INFO, loggable)
|
|
393
396
|
}
|
|
394
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Logs a deprecation notice at the {@link Level.WARNING} log level, once per
|
|
400
|
+
* `id` for this logger's lifetime — a repeat call with the same `id` is a
|
|
401
|
+
* no-op, matching the once-only behavior `util.deprecate` gives by call-site
|
|
402
|
+
* identity, but keyed on a stable id instead so it survives being wrapped,
|
|
403
|
+
* rebound, or called through multiple paths.
|
|
404
|
+
*
|
|
405
|
+
* `id` is only claimed once the notice is actually loggable at this
|
|
406
|
+
* logger's effective level — under the default `Level.OFF` root level, a
|
|
407
|
+
* call here logs nothing and leaves `id` unclaimed, so a later call (once
|
|
408
|
+
* logging is enabled) still gets to report it instead of finding it already
|
|
409
|
+
* silently used up.
|
|
410
|
+
* @param {string} id a stable, non-empty identifier for this deprecation
|
|
411
|
+
* (e.g. `'webdriver-getBidi'`), distinct from the message text so
|
|
412
|
+
* tooling can key off it even if the wording changes later.
|
|
413
|
+
* @param {string} message the deprecation notice to log.
|
|
414
|
+
* @throws {TypeError} if `id` is empty.
|
|
415
|
+
*/
|
|
416
|
+
deprecate(id, message) {
|
|
417
|
+
if (!id) {
|
|
418
|
+
throw new TypeError('Logger#deprecate() requires a non-empty id')
|
|
419
|
+
}
|
|
420
|
+
if (this.deprecated_.has(id)) {
|
|
421
|
+
return
|
|
422
|
+
}
|
|
423
|
+
if (!this.isLoggable(Level.WARNING)) {
|
|
424
|
+
return
|
|
425
|
+
}
|
|
426
|
+
this.deprecated_.add(id)
|
|
427
|
+
this.warning(`[${id}] ${message}`)
|
|
428
|
+
}
|
|
429
|
+
|
|
395
430
|
/**
|
|
396
431
|
* Logs a message at the {@link Level.DEBUG} log level.
|
|
397
432
|
* @param {(string|function(): string)} loggable the message to log, or a
|
package/lib/webdriver.js
CHANGED
|
@@ -40,7 +40,7 @@ const cdpTargets = ['page', 'browser']
|
|
|
40
40
|
const { Credential } = require('./virtual_authenticator')
|
|
41
41
|
const webElement = require('./webelement')
|
|
42
42
|
const { isObject } = require('./util')
|
|
43
|
-
const
|
|
43
|
+
const { getBidiConnection, closeBidiConnection } = require('./bidi_connection')
|
|
44
44
|
const { PinnedScript } = require('./pinnedScript')
|
|
45
45
|
const JSZip = require('jszip')
|
|
46
46
|
const Script = require('./script')
|
|
@@ -691,6 +691,16 @@ class WebDriver {
|
|
|
691
691
|
this.pinnedScripts_ = {}
|
|
692
692
|
}
|
|
693
693
|
|
|
694
|
+
/**
|
|
695
|
+
* The shared logger deprecation notices (e.g. {@link WebDriver#getBidi})
|
|
696
|
+
* are emitted through — a class-level accessor since a deprecation can be
|
|
697
|
+
* reported from a static/prototype context with no driver instance at hand.
|
|
698
|
+
* @return {!./logging.Logger} the shared `selenium.webdriver.webdriver` logger.
|
|
699
|
+
*/
|
|
700
|
+
static get logger() {
|
|
701
|
+
return logging.getLogger('selenium.webdriver.webdriver')
|
|
702
|
+
}
|
|
703
|
+
|
|
694
704
|
/**
|
|
695
705
|
* Creates a new WebDriver session.
|
|
696
706
|
*
|
|
@@ -794,10 +804,9 @@ class WebDriver {
|
|
|
794
804
|
this._cdpWsConnection.close()
|
|
795
805
|
}
|
|
796
806
|
|
|
797
|
-
//
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
}
|
|
807
|
+
// Not awaited: the session is already torn down by this point, so
|
|
808
|
+
// closing our end of the socket doesn't need to gate quit() completing.
|
|
809
|
+
closeBidiConnection(this)
|
|
801
810
|
})
|
|
802
811
|
}
|
|
803
812
|
|
|
@@ -1045,6 +1054,9 @@ class WebDriver {
|
|
|
1045
1054
|
async findElementInternal_(locatorFn, context) {
|
|
1046
1055
|
let result = await locatorFn(context)
|
|
1047
1056
|
if (Array.isArray(result)) {
|
|
1057
|
+
if (result.length === 0) {
|
|
1058
|
+
throw new NoSuchElementError('Cannot locate an element with provided parameters')
|
|
1059
|
+
}
|
|
1048
1060
|
result = result[0]
|
|
1049
1061
|
}
|
|
1050
1062
|
if (!(result instanceof WebElement)) {
|
|
@@ -1088,7 +1100,15 @@ class WebDriver {
|
|
|
1088
1100
|
* @private
|
|
1089
1101
|
*/
|
|
1090
1102
|
async findElementsInternal_(locatorFn, context) {
|
|
1091
|
-
|
|
1103
|
+
let result
|
|
1104
|
+
try {
|
|
1105
|
+
result = await locatorFn(context)
|
|
1106
|
+
} catch (ex) {
|
|
1107
|
+
if (ex instanceof NoSuchElementError) {
|
|
1108
|
+
return []
|
|
1109
|
+
}
|
|
1110
|
+
throw ex
|
|
1111
|
+
}
|
|
1092
1112
|
if (result instanceof WebElement) {
|
|
1093
1113
|
return [result]
|
|
1094
1114
|
}
|
|
@@ -1301,19 +1321,6 @@ class WebDriver {
|
|
|
1301
1321
|
this._cdpConnection.execute('Target.getTargets')
|
|
1302
1322
|
}
|
|
1303
1323
|
|
|
1304
|
-
/**
|
|
1305
|
-
* Initiates bidi connection using 'webSocketUrl'
|
|
1306
|
-
* @returns {BIDI}
|
|
1307
|
-
*/
|
|
1308
|
-
async getBidi() {
|
|
1309
|
-
if (this._bidiConnection === undefined) {
|
|
1310
|
-
const caps = await this.getCapabilities()
|
|
1311
|
-
let WebSocketUrl = caps['map_'].get('webSocketUrl')
|
|
1312
|
-
this._bidiConnection = new BIDI(WebSocketUrl.replace('localhost', '127.0.0.1'))
|
|
1313
|
-
}
|
|
1314
|
-
return this._bidiConnection
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
1324
|
/**
|
|
1318
1325
|
* Retrieves 'webSocketDebuggerUrl' by sending a http request using debugger address
|
|
1319
1326
|
* @param {string} debuggerAddress
|
|
@@ -1778,6 +1785,36 @@ class WebDriver {
|
|
|
1778
1785
|
}
|
|
1779
1786
|
}
|
|
1780
1787
|
|
|
1788
|
+
/**
|
|
1789
|
+
* Returns the WebDriver BiDi connection for this session.
|
|
1790
|
+
*
|
|
1791
|
+
* @deprecated BiDi is an internal implementation detail — this accessor hands
|
|
1792
|
+
* back the raw transport directly, which is no longer supported public API.
|
|
1793
|
+
* Use a composed BiDi module instead, e.g. `Network.create(driver)` or
|
|
1794
|
+
* `require('selenium-webdriver/bidi/network')`.
|
|
1795
|
+
* @function
|
|
1796
|
+
* @name WebDriver#getBidi
|
|
1797
|
+
* @returns {Promise<import('../bidi')>} A promise resolving to this session's raw
|
|
1798
|
+
* BiDi connection, opened on first access and reused afterward.
|
|
1799
|
+
*/
|
|
1800
|
+
// Object.defineProperty, not `WebDriver.prototype.getBidi = function () {...}`:
|
|
1801
|
+
// a plain assignment creates an enumerable property, but a method declared in
|
|
1802
|
+
// the class body (like every other method here) is non-enumerable — so BiDi
|
|
1803
|
+
// would become more discoverable off the driver than it was before.
|
|
1804
|
+
Object.defineProperty(WebDriver.prototype, 'getBidi', {
|
|
1805
|
+
value: function () {
|
|
1806
|
+
WebDriver.logger.deprecate(
|
|
1807
|
+
'webdriver-getBidi',
|
|
1808
|
+
'WebDriver#getBidi() is deprecated. Use a composed BiDi module instead, e.g. Network.create(driver) or ' +
|
|
1809
|
+
"require('selenium-webdriver/bidi/network').",
|
|
1810
|
+
)
|
|
1811
|
+
return getBidiConnection(this)
|
|
1812
|
+
},
|
|
1813
|
+
writable: true,
|
|
1814
|
+
enumerable: false,
|
|
1815
|
+
configurable: true,
|
|
1816
|
+
})
|
|
1817
|
+
|
|
1781
1818
|
/**
|
|
1782
1819
|
* Interface for navigating back and forth in the browser history.
|
|
1783
1820
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selenium-webdriver",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.49.0",
|
|
4
4
|
"description": "The official WebDriver JavaScript bindings from the Selenium project",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -33,19 +33,19 @@
|
|
|
33
33
|
"cddl": "^0.21.1",
|
|
34
34
|
"cddl2ts": "^0.10.1",
|
|
35
35
|
"clean-jsdoc-theme": "^4.3.3",
|
|
36
|
-
"eslint": "^10.
|
|
36
|
+
"eslint": "^10.10.0",
|
|
37
37
|
"eslint-config-prettier": "^10.1.8",
|
|
38
38
|
"eslint-plugin-mocha": "^11.3.0",
|
|
39
39
|
"eslint-plugin-n": "^18.3.0",
|
|
40
40
|
"eslint-plugin-no-only-tests": "^3.4.0",
|
|
41
41
|
"eslint-plugin-prettier": "^5.5.6",
|
|
42
42
|
"express": "^5.2.1",
|
|
43
|
-
"globals": "^17.
|
|
43
|
+
"globals": "^17.12.0",
|
|
44
44
|
"has-flag": "^5.0.1",
|
|
45
45
|
"jsdoc": "^4.0.5",
|
|
46
46
|
"mocha": "^11.8.0",
|
|
47
47
|
"mocha-junit-reporter": "^2.2.1",
|
|
48
|
-
"multer": "^2.
|
|
48
|
+
"multer": "^2.3.0",
|
|
49
49
|
"prettier": "^3.9.6",
|
|
50
50
|
"serve-index": "^1.9.2",
|
|
51
51
|
"sinon": "^22.1.0",
|