Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

selenium-webdriver

Package Overview
Dependencies
Maintainers
6
Versions
119
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

selenium-webdriver - npm Package Compare versions

Comparing version
4.43.0
to
4.44.0
+112
-21
bidi/index.js

@@ -36,9 +36,98 @@ // Licensed to the Software Freedom Conservancy (SFC) under one

this.connected = false
this._closed = false
this._pending = new Map()
this._connectWaiters = new Set()
this._ws = new WebSocket(_webSocketUrl)
this._ws.on('open', () => {
// The handshake can complete after close()/_failPending() has already
// marked the connection closed. Don't flip connected back to true and
// proactively close the now-orphan socket so it does not leak.
if (this._closed) {
try {
this._ws.close()
} catch {
/* socket already closing */
}
return
}
this.connected = true
for (const { resolve } of this._connectWaiters) {
resolve()
}
this._connectWaiters.clear()
})
// Single shared response dispatcher. Avoids attaching a new 'message'
// listener for every in-flight send(), which previously caused
// MaxListenersExceededWarning under concurrent BiDi traffic
// (e.g. network interception during a page navigation).
this._ws.on('message', (data) => {
// Frames can arrive after close() has cleared _pending; ignore them
// rather than re-emitting parse errors or dispatching to nothing.
if (this._closed) {
return
}
let payload
try {
payload = JSON.parse(data.toString())
} catch (err) {
// Surface protocol parse failures rather than silently dropping —
// otherwise callers see misleading send() timeouts.
const wrapped = new Error(`Failed to parse BiDi message: ${err.message}`)
if (this.listenerCount('error') > 0) {
this.emit('error', wrapped)
} else {
process.emitWarning(wrapped.message, 'BiDiProtocolWarning')
}
return
}
// Messages without a numeric id are BiDi events, not command
// responses; they are routed via subscribe/EventEmitter elsewhere
// and intentionally ignored by this dispatcher.
if (payload == null || typeof payload.id !== 'number') {
return
}
const entry = this._pending.get(payload.id)
if (entry === undefined) {
return
}
clearTimeout(entry.timeoutId)
this._pending.delete(payload.id)
entry.resolve(payload)
})
// Fail any in-flight send() calls promptly when the peer disconnects
// or the socket errors, instead of waiting for RESPONSE_TIMEOUT.
this._ws.on('close', () => {
this._failPending(new Error('BiDi connection closed unexpectedly'))
})
this._ws.on('error', (err) => {
this._failPending(new Error(`BiDi connection error: ${err.message}`))
})
}
/**
* Reject any in-flight sends and mark the connection failed. Idempotent so
* that close() and the underlying 'close'/'error' events do not double-reject.
* @param {Error} error
* @private
*/
_failPending(error) {
if (this._closed) {
return
}
this._closed = true
this.connected = false
for (const { reject, timeoutId } of this._pending.values()) {
clearTimeout(timeoutId)
reject(error)
}
this._pending.clear()
// Reject any callers parked in waitForConnection() so close() (or an
// unexpected disconnect) cannot leave them hanging forever.
for (const { reject } of this._connectWaiters) {
reject(error)
}
this._connectWaiters.clear()
}
/**
* @returns {WebSocket}

@@ -73,10 +162,15 @@ */

async waitForConnection() {
return new Promise((resolve) => {
return new Promise((resolve, reject) => {
if (this._closed) {
reject(new Error('BiDi connection is closed'))
return
}
if (this.connected) {
resolve()
} else {
this._ws.once('open', () => {
resolve()
})
return
}
// Park the waiter in a Set so the constructor's 'open' handler can
// resolve it and _failPending() can reject it. Avoids attaching socket
// listeners that close()'s removeAllListeners('close') would strip.
this._connectWaiters.add({ resolve, reject })
})

@@ -91,5 +185,14 @@ }

async send(params) {
if (this._closed) {
throw new Error('BiDi connection is closed')
}
if (!this.connected) {
await this.waitForConnection()
}
// Defense in depth: even after waitForConnection() resolves, the socket
// may have transitioned to CLOSING/CLOSED (e.g. caller closed the raw
// socket). Refuse rather than throwing from inside ws.send().
if (this._ws.readyState !== WebSocket.OPEN) {
throw new Error('BiDi connection is not open')
}

@@ -102,21 +205,7 @@ const id = ++this.id

const timeoutId = setTimeout(() => {
this._pending.delete(id)
reject(new Error(`Request with id ${id} timed out`))
handler.off('message', listener)
}, RESPONSE_TIMEOUT)
const listener = (data) => {
try {
const payload = JSON.parse(data.toString())
if (payload.id === id) {
clearTimeout(timeoutId)
handler.off('message', listener)
resolve(payload)
}
} catch (err) {
// eslint-disable-next-line no-undef
log.error(`Failed parse message: ${err.message}`)
}
}
const handler = this._ws.on('message', listener)
this._pending.set(id, { resolve, reject, timeoutId })
})

@@ -213,2 +302,4 @@ }

close() {
this._failPending(new Error('BiDi connection closed before response was received'))
const closeWebSocket = (callback) => {

@@ -215,0 +306,0 @@ // don't close if it's already closed

+6
-6
{
"name": "selenium-webdriver",
"version": "4.43.0",
"version": "4.44.0",
"description": "The official WebDriver JavaScript bindings from the Selenium project",

@@ -29,7 +29,7 @@ "license": "Apache-2.0",

"tmp": "^0.2.5",
"ws": "^8.20.0"
"ws": "^8.20.1"
},
"devDependencies": {
"@eslint/js": "^9.39.4",
"clean-jsdoc-theme": "^4.3.0",
"clean-jsdoc-theme": "^4.3.2",
"eslint": "^9.39.4",

@@ -39,5 +39,5 @@ "eslint-config-prettier": "^10.1.8",

"eslint-plugin-n": "^17.24.0",
"eslint-plugin-no-only-tests": "^3.3.0",
"eslint-plugin-no-only-tests": "^3.4.0",
"eslint-plugin-prettier": "^5.5.5",
"express": "^4.22.1",
"express": "^4.22.2",
"globals": "^15.15.0",

@@ -49,3 +49,3 @@ "has-flag": "^5.0.1",

"multer": "2.0.2",
"prettier": "^3.8.1",
"prettier": "^3.8.3",
"serve-index": "^1.9.2",

@@ -52,0 +52,0 @@ "sinon": "^19.0.5",

+55
-183
# selenium-webdriver
Selenium is a browser automation library. Most often used for testing
web-applications, Selenium may be used for any task that requires automating
interaction with the browser.
JavaScript language bindings for [Selenium WebDriver](https://www.selenium.dev).
Selenium automates browsers for testing and web-based task automation.
Requires Node.js >= 20.
## Installation
Selenium may be installed via npm with
```bash
npm install selenium-webdriver
```
npm install selenium-webdriver
## Quick Start
You will need to download additional components to work with each of the major
browsers. The drivers for Chrome, Firefox, and Microsoft's IE and Edge web
browsers are all standalone executables that should be placed on your system
[PATH]. Apple's safaridriver (v10 and above) can be found at the
following path – /usr/bin/safaridriver. To enable automation on safari,
you need to run command `safaridriver --enable`.
| Browser | Component |
| :---------------- | :------------------------------- |
| Chrome | [chromedriver(.exe)][chrome] |
| Internet Explorer | [IEDriverServer.exe][release] |
| Edge | [MicrosoftWebDriver.msi][edge] |
| Firefox | [geckodriver(.exe)][geckodriver] |
| Opera | [operadriver(.exe)][operadriver] |
| Safari | [safaridriver] |
## Usage
The sample below and others are included in the `example` directory. You may
also find the tests for selenium-webdriver informative.
```javascript
const { Builder, Browser, By, Key, until } = require('selenium-webdriver')
const { Builder, Browser } = require('selenium-webdriver')
;(async function example() {
let driver = await new Builder().forBrowser(Browser.FIREFOX).build()
let driver = await new Builder().forBrowser(Browser.CHROME).build()
try {
await driver.get('https://www.google.com/ncr')
await driver.findElement(By.name('q')).sendKeys('webdriver', Key.RETURN)
await driver.wait(until.titleIs('webdriver - Google Search'), 1000)
await driver.get('https://www.selenium.dev')
console.log(await driver.getTitle())
} finally {

@@ -49,183 +30,74 @@ await driver.quit()

### Using the Builder API
Selenium Manager automatically handles browser driver installation — no manual driver setup required.
The `Builder` class is your one-stop shop for configuring new WebDriver
instances. Rather than clutter your code with branches for the various browsers,
the builder lets you set all options in one flow. When you call
`Builder#build()`, all options irrelevant to the selected browser are dropped:
## Configuring the Builder
The `Builder` sets default options for all browsers in a single chain; options
for non-selected browsers are dropped at `build()` time. The target browser can
be swapped at runtime via the `SELENIUM_BROWSER` environment variable.
```javascript
const webdriver = require('selenium-webdriver')
const { Builder, Browser } = require('selenium-webdriver')
const chrome = require('selenium-webdriver/chrome')
const firefox = require('selenium-webdriver/firefox')
let driver = new webdriver.Builder()
.forBrowser(webdriver.Browser.FIREFOX)
.setChromeOptions(/* ... */)
.setFirefoxOptions(/* ... */)
let driver = new Builder()
.forBrowser(Browser.FIREFOX)
.setChromeOptions(new chrome.Options())
.setFirefoxOptions(new firefox.Options())
.build()
```
Why would you want to configure options irrelevant to the target browser? The
`Builder`'s API defines your _default_ configuration. You can change the target
browser at runtime through the `SELENIUM_BROWSER` environment variable. For
example, the `example/google_search.js` script is configured to run against
Firefox. You can run the example against other browsers just by changing the
runtime environment
## Running Against a Remote Server
# cd node_modules/selenium-webdriver
node example/google_search
SELENIUM_BROWSER=chrome node example/google_search
SELENIUM_BROWSER=safari node example/google_search
To run scripts against a [Selenium Grid](https://www.selenium.dev/documentation/grid/)
or standalone server, point the Builder at the server URL, or set
`SELENIUM_REMOTE_URL`:
### The Standalone Selenium Server
The standalone Selenium Server acts as a proxy between your script and the
browser-specific drivers. The server may be used when running locally, but it's
not recommend as it introduces an extra hop for each request and will slow
things down. The server is required, however, to use a browser on a remote host
(most browser drivers, like the IEDriverServer, do not accept remote
connections).
To use the Selenium Server, you will need to install the
[JDK](http://www.oracle.com/technetwork/java/javase/downloads/index.html) and
download the latest server from [Selenium][release]. Once downloaded, run the
server with
java -jar selenium-server-4.27.0.jar standalone
You may configure your tests to run against a remote server through the Builder
API:
```javascript
let driver = new webdriver.Builder()
.forBrowser(webdriver.Browser.FIREFOX)
.usingServer('http://localhost:4444/wd/hub')
.build()
let driver = new Builder().forBrowser(Browser.CHROME).usingServer('http://localhost:4444').build()
```
Or change the Builder's configuration at runtime with the `SELENIUM_REMOTE_URL`
environment variable:
```bash
SELENIUM_REMOTE_URL="http://localhost:4444" node script.js
```
SELENIUM_REMOTE_URL="http://localhost:4444/wd/hub" node script.js
You can experiment with these options using the `example/google_search.js`
script provided with `selenium-webdriver`.
## Documentation
API documentation is available online from the [Selenium project][api].
Additional resources include
- the #selenium channel on Libera IRC
- the [selenium-users@googlegroups.com][users] list
- [SeleniumHQ](https://selenium.dev/documentation/) documentation
## Contributing
Contributions are accepted either through [GitHub][gh] pull requests or patches
via the [Selenium issue tracker][issues].
## Node Support Policy
Each version of selenium-webdriver will support the latest _semver-minor_
version of the [LTS] and stable Node releases. All _semver-major_ &
_semver-minor_ versions between the LTS and stable release will have "best
effort" support. Following a Selenium release, any _semver-minor_ Node releases
will also have "best effort" support. Releases older than the latest LTS,
_semver-major_ releases, and all unstable release branches (e.g. "v.Next")
are considered strictly unsupported.
Each `selenium-webdriver` release targets the latest _semver-minor_ of Node's
[LTS and Current releases](https://github.com/nodejs/release#release-schedule).
For example, suppose the current LTS and stable releases are v22.13.0 and
v23.6.0,
respectively. Then a Selenium release would have the following support levels:
| Level | Guarantee |
| :------------ | :------------------------------------------------------------------------ |
| _supported_ | API compatible without runtime flags; bugs investigated and fixed. |
| _best effort_ | Bugs investigated as time permits; API compatibility only where required. |
| _unsupported_ | Bug reports closed as will-not-fix; API compatibility not guaranteed. |
| Version | Support |
| :--------: | :-----------: |
| <= 16.20.2 | _unsupported_ |
| 16.20.2 | supported |
| 18.8.0 | supported |
| >= 22.13.0 | best effort |
| v.Next | _unsupported_ |
Versions older than the active LTS, unstable release branches (e.g. `v.Next`),
and _semver-major_ Node releases outside the LTS / Current pair are _unsupported_.
### Support Level Definitions
## Documentation
- _supported:_ A selenium-webdriver release will be API compatible with the
platform API, without the use of runtime flags.
- [Getting Started](https://www.selenium.dev/documentation/webdriver/getting_started/)
- [JavaScript API Docs](https://www.selenium.dev/selenium/docs/api/javascript/)
- [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/)
- [Selenium Grid](https://www.selenium.dev/documentation/grid/)
- _best effort:_ Bugs will be investigated as time permits. API compatibility is
only guaranteed where required by a _supported_ release. This effectively
means the adoption of new JS features, such as ES2015 modules, will depend
on what is supported in Node's LTS.
## Support
- _unsupported:_ Bug submissions will be closed as will-not-fix and API
compatibility is not guaranteed.
- [Selenium Chat](https://www.selenium.dev/support/#ChatRoom)
- [GitHub Issues](https://github.com/SeleniumHQ/selenium/issues)
### Projected Support Schedule
## Contributing
If Node releases a new [LTS] each October and a new major version every 6
months, the support window for selenium-webdriver will be roughly:
Contributions are welcome via [GitHub](https://github.com/SeleniumHQ/selenium/) pull requests.
See the [source code](https://github.com/SeleniumHQ/selenium/tree/trunk/javascript/selenium-webdriver) for this binding.
| Release | Status | END-OF-LIFE |
| :-----: | :-------------: | :---------: |
| v18.x | Maintenance LTS | 2025-04-30 |
| v19.x | End-of-Life | 2023-06-01 |
| v20.x | Maintenance LTS | 2026-04-30 |
| v21.x | End-of-Life | 2024-06-01 |
| V22.x | Active LTS | 2027-04-30 |
| V23.x | Current | 2025-06-01 |
## Links
## Issues
- [npm](https://www.npmjs.com/package/selenium-webdriver)
- [Documentation](https://www.selenium.dev/documentation/?tab=javascript)
Please report any issues using the [Selenium issue tracker][issues]. When using
the issue tracker
- **Do** include a detailed description of the problem.
- **Do** include a link to a [gist](http://gist.github.com/) with any
interesting stack traces/logs (you may also attach these directly to the bug
report).
- **Do** include a [reduced test case][reduction]. Reporting "unable to find
element on the page" is _not_ a valid report - there's nothing for us to
look into. Expect your bug report to be closed if you do not provide enough
information for us to investigate.
- **Do not** use the issue tracker to submit basic help requests. All help
inquiries should be directed to the [user forum][users] or #selenium IRC
channel.
- **Do not** post empty "I see this too" or "Any updates?" comments. These
provide no additional information and clutter the log.
- **Do not** report regressions on closed bugs as they are not actively
monitored for updates (especially bugs that are >6 months old). Please open a
new issue and reference the original bug in your report.
## License
Licensed to the Software Freedom Conservancy (SFC) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The SFC licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
[LTS]: https://github.com/nodejs/LTS
[PATH]: http://en.wikipedia.org/wiki/PATH_%28variable%29
[api]: https://www.selenium.dev/selenium/docs/api/javascript/
[chrome]: https://googlechromelabs.github.io/chrome-for-testing/#stable
[gh]: https://github.com/SeleniumHQ/selenium/
[issues]: https://github.com/SeleniumHQ/selenium/issues
[edge]: http://go.microsoft.com/fwlink/?LinkId=619687
[geckodriver]: https://github.com/mozilla/geckodriver/releases/
[reduction]: http://www.webkit.org/quality/reduction.html
[release]: https://www.selenium.dev/downloads/
[users]: https://groups.google.com/forum/#!forum/selenium-users
[safaridriver]: https://developer.apple.com/library/prerelease/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html#//apple_ref/doc/uid/TP40014305-CH11-DontLinkElementID_28
[operadriver]: https://github.com/operasoftware/operachromiumdriver/releases
Licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display