Implementation of WebDriver BiDi for Chromium
Installations
npm install chromium-bidi
Score
98
Supply Chain
99.1
Quality
96
Maintenance
100
Vulnerability
99.6
License
Releases
chromium-bidi: v0.10.1
Published on 25 Nov 2024
chromium-bidi: v0.10.0
Published on 15 Nov 2024
chromium-bidi: v0.9.1
Published on 06 Nov 2024
chromium-bidi: v0.9.0
Published on 23 Oct 2024
chromium-bidi: v0.8.1
Published on 11 Oct 2024
chromium-bidi: v0.8.0
Published on 30 Sept 2024
Contributors
Developer
Developer Guide
Module System
Unable to determine the module system for this package.
Min. Node Version
Typescript Support
No
Node Version
20.18.0
NPM Version
10.8.2
Statistics
97 Stars
1,979 Commits
32 Forks
13 Watching
47 Branches
28 Contributors
Updated on 27 Nov 2024
Languages
TypeScript (55.88%)
Python (38.27%)
JavaScript (5.51%)
HTML (0.34%)
Total Downloads
Cumulative downloads
Total Downloads
218,819,252
Last day
3.6%
825,557
Compared to previous day
Last week
6.3%
4,380,194
Compared to previous week
Last month
12.7%
18,016,740
Compared to previous month
Last year
218.8%
166,575,640
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
3
Peer Dependencies
1
Dev Dependencies
49
WebDriver BiDi for Chromium
CI status
This is an implementation of the WebDriver BiDi protocol with some extensions (BiDi+) for Chromium, implemented as a JavaScript layer translating between BiDi and CDP, running inside a Chrome tab.
Current status can be checked at WPT WebDriver BiDi status.
BiDi+
"BiDi+" is an extension of the WebDriver BiDi protocol. In addition to WebDriver BiDi it has:
Command cdp.sendCommand
1CdpSendCommandCommand = { 2 method: "cdp.sendCommand", 3 params: CdpSendCommandParameters, 4} 5 6CdpSendCommandParameters = { 7 method: text, 8 params: any, 9 session?: text, 10} 11 12CdpSendCommandResult = { 13 result: any, 14 session: text, 15}
The command runs the described CDP command and returns the result.
Command cdp.getSession
1CdpGetSessionCommand = { 2 method: "cdp.getSession", 3 params: CdpGetSessionParameters, 4} 5 6CdpGetSessionParameters = { 7 context: BrowsingContext, 8} 9 10CdpGetSessionResult = { 11 session: text, 12}
The command returns the default CDP session for the selected browsing context.
Command cdp.resolveRealm
1CdpResolveRealmCommand = { 2 method: "cdp.resolveRealm", 3 params: CdpResolveRealmParameters, 4} 5 6CdpResolveRealmParameters = { 7 realm: Script.Realm, 8} 9 10CdpResolveRealmResult = { 11 executionContextId: text, 12}
The command returns resolves a BiDi realm to its CDP execution context ID.
Events cdp
1CdpEventReceivedEvent = { 2 method: "cdp.<CDP Event Name>", 3 params: CdpEventReceivedParameters, 4} 5 6CdpEventReceivedParameters = { 7 event: text, 8 params: any, 9 session: text, 10}
The event contains a CDP event.
Field channel
Each command can be extended with a channel
:
1Command = { 2 id: js-uint, 3 channel?: text, 4 CommandData, 5 Extensible, 6}
If provided and non-empty string, the very same channel
is added to the response:
1CommandResponse = { 2 id: js-uint, 3 channel?: text, 4 result: ResultData, 5 Extensible, 6} 7 8ErrorResponse = { 9 id: js-uint / null, 10 channel?: text, 11 error: ErrorCode, 12 message: text, 13 ?stacktrace: text, 14 Extensible 15}
When client uses
commands session.subscribe
and session.unsubscribe
with channel
, the subscriptions are handled per channel, and the corresponding
channel
filed is added to the event message:
1Event = { 2 channel?: text, 3 EventData, 4 Extensible, 5}
Dev Setup
npm
This is a Node.js project, so install dependencies as usual:
1npm install
cargo
We use cddlconv to generate our WebDriverBiDi types before building.
- Install Rust.
- Run
cargo install --git https://github.com/google/cddlconv.git cddlconv
pre-commit.com integration
Refer to the documentation at .pre-commit-config.yaml.
1pre-commit install --hook-type pre-push
Starting WebDriver BiDi Server
This will run the server on port 8080
:
1npm run server
Use the PORT=
environment variable or --port=
argument to run it on another port:
1PORT=8081 npm run server 2npm run server -- --port=8081
Use the DEBUG
environment variable to see debug info:
1DEBUG=* npm run server
Use the DEBUG_DEPTH
(default: 10
) environment variable to see debug deeply nested objects:
1DEBUG_DEPTH=100 DEBUG=* npm run server
Use the CHANNEL=...
environment variable with one of the following values to run
the specific Chrome channel: stable
, beta
, canary
, dev
, local
. Default is
local
. The local
channel means the pinned in .browser
Chrome version will be
downloaded if it is not yet in cache. Otherwise, the requested Chrome version should
be installed.
1CHANNEL=dev npm run server
Use the CLI argument --verbose
to have CDP events printed to the console. Note: you have to enable debugging output bidi:mapper:debug:*
as well.
1DEBUG=bidi:mapper:debug:* npm run server -- --verbose
or
1DEBUG=* npm run server -- --verbose
Starting on Linux and Mac
TODO: verify it works on Windows.
You can also run the server by using npm run server
. It will write
output to the file log.txt
:
1npm run server -- --port=8081 --headless=false
Running with in other project
Sometimes it good to verify that a change will not affect thing downstream for other packages.
There is a useful puppeteer
label you can add to any PR to run Puppeteer test with your changes.
It will bundle chromium-bidi
and install it in Puppeteer project then run that package test.
Running
Unit tests
Running:
1npm run unit
E2E tests
The e2e tests serve the following purposes:
- Brief checks of the scenarios (the detailed check is done in WPT)
- Test Chromium-specific behavior nuances
- Add a simple setup for engaging the specific command
The E2E tests are written using Python, in order to more-or-less align with the web-platform-tests.
Installation
Python 3.10+ and some dependencies are required:
1python -m pip install --user pipenv 2pipenv install
Running
The E2E tests require BiDi server running on the same host. By default, tests
try to connect to the port 8080
. The server can be run from the project root:
1npm run e2e # alias to to e2e:headless 2npm run e2e:headful 3npm run e2e:headless
This commands will run ./tools/run-e2e.mjs
, which will log the PyTest output to console,
Additionally the output is also recorded under ./logs/<DATE>.e2e.log
, this will contain
both the PyTest logs and in the event of FAILED
test all the Chromium-BiDi logs.
If you need to see the logs for all test run the command with VERBOSE=true
.
Simply pass npm run e2e -- tests/<PathOrFile>
and the e2e will run only the selected one.
You run a specific test by running npm run e2e -- -k <TestName>
.
Use CHROMEDRIVER
environment to run tests in chromedriver
instead of NodeJS runner:
1CHROMEDRIVER=true npm run e2e
Use the PORT
environment variable to connect to another port:
1PORT=8081 npm run e2e
Use the HEADLESS
to run the tests in headless (new or old) or headful modes.
Values: new
, old
, false
, default: new
.
1HEADLESS=new npm run e2e
Updating snapshots
1npm run e2e -- --snapshot-update
See https://github.com/tophat/syrupy for more information.
Local http server
E2E tests use local http
server pytest-httpserver
, which is run
automatically with the tests. However,
sometimes it is useful to run the http server outside the test
case, for example for manual debugging. This can be done by running:
1pipenv run local_http_server
...or directly:
1python tests/tools/local_http_server.py
Examples
Refer to examples/README.md.
WPT (Web Platform Tests)
WPT is added as a git submodule. To get run WPT tests:
Check out and setup WPT
1. Check out WPT
1git submodule update --init
2. Go to the WPT folder
1cd wpt
3. Set up virtualenv
Follow the System Setup instructions.
4. Setup hosts
file
Follow
the hosts
File Setup
instructions.
4.a On Linux, macOS or other UNIX-like system
1./wpt make-hosts-file | sudo tee -a /etc/hosts
4.b On Windows
This must be run in a PowerShell session with Administrator privileges:
1python wpt make-hosts-file | Out-File $env:SystemRoot\System32\drivers\etc\hosts -Encoding ascii -Append
If you are behind a proxy, you also need to make sure the domains above are excluded from your proxy lookups.
5. Set BROWSER_BIN
Set the BROWSER_BIN
environment variable to a Chrome, Edge or Chromium binary to launch.
For example, on macOS:
1# Chrome 2export BROWSER_BIN="/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary" 3export BROWSER_BIN="/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev" 4export BROWSER_BIN="/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta" 5export BROWSER_BIN="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" 6export BROWSER_BIN="/Applications/Chromium.app/Contents/MacOS/Chromium" 7 8# Edge 9export BROWSER_BIN="/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary" 10export BROWSER_BIN="/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
Run WPT tests
1. Make sure you have Chrome Dev installed
https://www.google.com/chrome/dev/
2. Build Chromedriver BiDi
Oneshot:
1npm run build
Continuously:
1npm run build --watch
3. Run
1npm run wpt -- webdriver/tests/bidi/
Update WPT expectations if needed
1UPDATE_EXPECTATIONS=true npm run wpt -- webdriver/tests/bidi/
How does it work?
The architecture is described in the WebDriver BiDi in Chrome Context implementation plan .
There are 2 main modules:
- backend WS server in
src
. It runs webSocket server, and for each ws connection runs an instance of browser with BiDi Mapper. - front-end BiDi Mapper in
src/bidiMapper
. Gets BiDi commands from the backend, and map them to CDP commands.
Contributing
The BiDi commands are processed in the src/bidiMapper/commandProcessor.ts
. To add a
new command, add it to _processCommand
, write and call processor for it.
Publish new npm
release
Release branches
chromium-bidi
maintains release branches corresponding to Chrome releases. The
branches are named using the following pattern: releases/m$MAJOR_VERSION
.
The new release branch is created as soon a new major browser version is published by the update-browser-version job:
- the PR created by this job should be marked as a feature and it should cause the major package version to be bumped.
- once the browser version is bumped, the commit preceding the version bump should be used to create a release branch for major version pinned before the bump.
Changes that need to be cherry-picked into the release branch should be marked as patches. Either major or minor version bumps are not allowed on the release branch.
Example workflow:
1gitGraph 2 commit id: "feat: featA" 3 commit id: "release: v0.5.0" 4 branch release/m129 5 checkout main 6 commit id: "feat: roll Chrome to M130 from 129" 7 commit id: "release: v0.6.0" 8 commit id: "fix: for m129" 9 checkout release/m129 10 cherry-pick id: "fix: for m129" 11 commit id: "release: v0.5.1 "
Currently, the releases from release branches are not automated.
Automatic release
We use release-please to automate releases. When a release should be done, check for the release PR in our pull requests and merge it.
Manual release
-
Dry-run
1npm publish --dry-run
-
Open a PR bumping the chromium-bidi version number in
package.json
for review:1npm version patch -m 'chore: Release v%s' --no-git-tag-version
Instead of
patch
, useminor
ormajor
as needed. -
After the PR is reviewed, create a GitHub release specifying the tag name matching the bumped version. Our CI then automatically publishes the new release to npm based on the tag name.
Roll into Chromium
This section assumes you already have a Chromium set-up locally, and knowledge on how to submit changes to the repo. Otherwise submit an issue for a project maintainer.
- Create a new branch in chromium
src/
. - Update the mapper version:
1third_party/bidimapper/roll_bidmapper
-
Submit a CL with bug
42323268
(link). -
Regenerate WPT expectations or baselines:
4.1. Trigger a build and test run:
1third_party/blink/tools/blink_tool.py rebaseline-cl --build="linux-blink-rel" --verbose
4.2. Once the test completes on the builder, rerun that command to update the baselines. Update test expectations if there are any crashes or timeouts. Commit the changes (if any), and upload the new patch to the CL.
-
Add appropriate reviewers or comment the CL link on the PR.
Adding new command
Want to add a shiny new command to WebDriver BiDi for Chromium? Here's the playbook:
Prerequisites
Specification
The WebDriver BiDi module, command, or event must be specified either in the WebDriver BiDi specification or as an extension in a separate specification (e.g., the Permissions specification). The specification should include the command's type definitions in valid CDDL format.
WPT wdspec tests
You'll need tests to prove your command works as expected. These tests should be written using WPT wdspec and submitted along with the spec itself. Don't forget to roll the WPT repo into the Mapper (dependabot can help, and you will likely need to tweak some expectations afterward).
CDP implementation
Make sure Chromium already has the CDP methods your command will rely on.
Update CDDL types
- If your command lives in a separate spec, add a link to that spec in the "Build WebDriverBiDi types" GitHub action (check out the "bluetooth" pull request for an example).
- Run the "Update WebdriverBiDi types" GitHub action. This will create a pull request with your new types. If you added a command, this PR will have a failing check complaining about a non-exhaustive switch statement:
error: Switch is not exhaustive. Cases not matched: "{NEW_COMMAND_NAME}" @typescript-eslint/switch-exhaustiveness-check
- Update the created pull request. Add your new command to
CommandProcessor.#processCommand
. For now, just have it throw an UnknownErrorException (see the example for how to do this).
1case '{NEW_COMMAND_NAME}': 2 throw new UnknownErrorException( 3 `Method ${command.method} is not implemented.`, 4 );
- Merge it! Standard PR process: create, review, merge.
Implement the new command
CommandProcessor.#processCommand
handles parsing parameters and running your command.
(only if the new command has non-empty parameters) parse command parameters
If your command has parameters, update the BidiCommandParameterParser
and implement the parsing logic in BidiNoOpParser
, BidiParser
and protocol-parser
. Look at the example for guidance.
Implement the new command
Write the core logic for your command in the appropriate domain processor. Again, example is your friend.
Call the domain processor's method
Call your new domain processor method from CommandProcessor.#processCommand
, passing in the parsed parameters. Example.
Add e2e tests
Write end-to-end tests for your command, including the happy path and any edge cases that might trip things up. Focus on testing the code in the mapper.
Update WPT expectations
Your WPT tests will probably fail now.
Tests with unexpected results: PASS [expected FAIL] ...
Update the expectations in a draft PR with the "update-expectations" label. This will trigger an automated PR "test: update the expectations for PR" that you'll need to merge to your branch.
Merge it!
Mark your PR as ready, get it reviewed, and merge it in.
Roll in ChromeDriver
This bit usually involves the core devs:
- Release your changes.
- Roll the changes into ChromeDriver.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
30 out of 30 merged PRs checked by a CI test -- score normalized to 10
Reason
all changesets reviewed
Reason
project has 22 contributing companies or organizations
Details
- Info: 60devs contributor org/company found, v8 contributor org/company found, iRail contributor org/company found, GoogleCloudPlatform contributor org/company found, puppeteer contributor org/company found, googlers contributor org/company found, chromium contributor org/company found, oftn-oswg contributor org/company found, h5bp contributor org/company found, unicode-org contributor org/company found, GoogleChromeLabs contributor org/company found, microsoft contributor org/company found, google contributor org/company found, ctfs contributor org/company found, ChromeDevTools contributor org/company found, tibiamaps contributor org/company found, bestiejs contributor org/company found, tc39 contributor org/company found, GoogleChrome contributor org/company found, whatwg contributor org/company found, kinectitude contributor org/company found, MicrosoftEdge contributor org/company found,
Reason
no dangerous workflow patterns detected
Reason
update tool detected
Details
- Info: detected update tool: Dependabot: .github/dependabot.yml:1
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0
Reason
30 commit(s) and 22 issue activity found in the last 90 days -- score normalized to 10
Reason
security policy file detected
Details
- Info: security policy file detected: SECURITY.md:1
- Info: Found linked content: SECURITY.md:1
- Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1
- Info: Found text in security policy: SECURITY.md:1
Reason
GitHub workflow tokens follow principle of least privilege
Details
- Info: jobLevel 'contents' permission set to 'read': .github/workflows/wpt.yml:282
- Info: topLevel permissions set to 'read-all': .github/workflows/chromium-roll-reminder.yml:4
- Info: topLevel permissions set to 'read-all': .github/workflows/e2e.yml:6
- Info: topLevel permissions set to 'read-all': .github/workflows/labeler.yml:4
- Info: topLevel permissions set to 'read-all': .github/workflows/pre-commit.yml:6
- Info: topLevel permissions set to 'read-all': .github/workflows/publish.yml:4
- Info: topLevel permissions set to 'read-all': .github/workflows/puppeteer.yml:4
- Info: topLevel permissions set to 'read-all': .github/workflows/scorecard.yml:14
- Info: topLevel permissions set to 'read-all': .github/workflows/selenium.yml:6
- Info: topLevel permissions set to 'read-all': .github/workflows/unit.yml:7
- Info: topLevel permissions set to 'read-all': .github/workflows/update-bidi-types.yml:6
- Info: topLevel permissions set to 'read-all': .github/workflows/update-browser-version.yml:6
- Info: topLevel permissions set to 'read-all': .github/workflows/webdriverio.yml:6
- Info: topLevel permissions set to 'read-all': .github/workflows/wpt.yml:7
- Info: no jobLevel write permissions found
Reason
0 existing vulnerabilities detected
Reason
dependency not pinned by hash detected -- score normalized to 9
Details
- Warn: pipCommand not pinned by hash: .github/workflows/e2e.yml:79
- Warn: pipCommand not pinned by hash: .github/workflows/update-bidi-types.yml:120
- Warn: pipCommand not pinned by hash: .github/workflows/wpt.yml:97
- Warn: pipCommand not pinned by hash: .github/workflows/wpt.yml:179
- Info: 54 out of 54 GitHub-owned GitHubAction dependencies pinned
- Info: 16 out of 16 third-party GitHubAction dependencies pinned
- Info: 13 out of 13 npmCommand dependencies pinned
- Info: 0 out of 4 pipCommand dependencies pinned
Reason
SAST tool is not run on all commits -- score normalized to 7
Details
- Warn: 23 commits out of 30 are checked with a SAST tool
Reason
branch protection is not maximal on development and all release branches
Details
- Info: 'allow deletion' disabled on branch 'main'
- Info: 'force pushes' disabled on branch 'main'
- Info: 'branch protection settings apply to administrators' is required to merge on branch 'main'
- Warn: 'stale review dismissal' is disable on branch 'main'
- Warn: required approving review count is 1 on branch 'main'
- Warn: codeowners review is not required on branch 'main'
- Warn: 'last push approval' is disable on branch 'main'
- Info: 'up-to-date branches' is required to merge on branch 'main'
- Info: status check found to merge onto on branch 'main'
- Info: PRs are required in order to make changes on branch 'main'
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Score
8.6
/10
Last Scanned on 2024-11-27T19:26:19Z
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreOther packages similar to chromium-bidi
webdriver
A Node.js bindings implementation for the W3C WebDriver and Mobile JSONWire Protocol
bidi-js
A JavaScript implementation of the Unicode Bidirectional Algorithm
electron-to-chromium
Provides a list of electron-to-chromium version mappings
@react-pdf/textkit
An advanced text layout framework