blob: 36c70795073dfb810f869cbcfdee339e27ae9646 [file] [log] [blame] [view]
Randolfb0fe9c12023-03-06 14:03:481# WebDriver BiDi for Chromium [![chromium-bidi on npm](https://img.shields.io/npm/v/chromium-bidi)](https://www.npmjs.com/package/chromium-bidi)
2
Randolf55431462023-03-29 13:00:363## CI status
Randolfb0fe9c12023-03-06 14:03:484
Randolf55431462023-03-29 13:00:365![E2E Tests](https://github.com/GoogleChromeLabs/chromium-bidi/actions/workflows/e2e.yml/badge.svg)
6![Unit Tests](https://github.com/GoogleChromeLabs/chromium-bidi/actions/workflows/unit.yml/badge.svg)
Randolf Jungbcb3bc82023-06-26 16:30:147![WPT Tests](https://github.com/GoogleChromeLabs/chromium-bidi/actions/workflows/wpt.yml/badge.svg)
Randolf55431462023-03-29 13:00:368
Randolf55431462023-03-29 13:00:369![Pre-commit](https://github.com/GoogleChromeLabs/chromium-bidi/actions/workflows/pre-commit.yml/badge.svg)
Randolfb0fe9c12023-03-06 14:03:4810
11This is an implementation of the
12[WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) protocol with some
13extensions (**BiDi+**)
14for Chromium, implemented as a JavaScript layer translating between BiDi and CDP,
15running inside a Chrome tab.
16
17Current status can be checked
18at [WPT WebDriver BiDi status](https://wpt.fyi/results/webdriver/tests/bidi).
19
20## BiDi+
21
22**"BiDi+"** is an extension of the WebDriver BiDi protocol. In addition to [WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) it has:
23
24### Command `cdp.sendCommand`
25
26```cddl
27CdpSendCommandCommand = {
28 method: "cdp.sendCommand",
29 params: ScriptEvaluateParameters,
30}
31
32CdpSendCommandParameters = {
33 cdpMethod: text,
34 cdpParams: any,
35 cdpSession?: text,
36}
37
38CdpSendCommandResult = {
39 result: any,
40 cdpSession: text,
41}
42```
43
44The command runs the
45described [CDP command](https://chromedevtools.github.io/devtools-protocol)
46and returns result.
47
48### Command `cdp.getSession`
49
50```cddl
51CdpGetSessionCommand = {
52 method: "cdp.sendCommand",
53 params: ScriptEvaluateParameters,
54}
55
56CdpGetSessionParameters = {
57 context: BrowsingContext,
58}
59
60CdpGetSessionResult = {
61 cdpSession: text,
62}
63```
64
65The command returns the default CDP session for the selected browsing context.
66
67### Event `cdp.eventReceived`
68
69```cddl
70CdpEventReceivedEvent = {
71 method: "cdp.eventReceived",
72 params: ScriptEvaluateParameters,
73}
74
75CdpEventReceivedParameters = {
76 cdpMethod: text,
77 cdpParams: any,
78 cdpSession: string,
79}
80```
81
82The event contains a CDP event.
83
84### Field `channel`
85
86Each command can be extended with a `channel`:
87
88```cddl
89Command = {
90 id: js-uint,
91 channel?: text,
92 CommandData,
93 Extensible,
94}
95```
96
97If provided and non-empty string, the very same `channel` is added to the response:
98
99```cddl
100CommandResponse = {
101 id: js-uint,
102 channel?: text,
103 result: ResultData,
104 Extensible,
105}
106
107ErrorResponse = {
108 id: js-uint / null,
109 channel?: text,
110 error: ErrorCode,
111 message: text,
112 ?stacktrace: text,
113 Extensible
114}
115```
116
117When client uses
118commands [`session.subscribe`](https://w3c.github.io/webdriver-bidi/#command-session-subscribe)
119and [`session.unsubscribe`](https://w3c.github.io/webdriver-bidi/#command-session-unsubscribe)
120with `channel`, the subscriptions are handled per channel, and the corresponding
121`channel` filed is added to the event message:
122
123```cddl
124Event = {
125 channel?: text,
126 EventData,
127 Extensible,
128}
129```
130
131## Dev Setup
132
133### `npm`
134
135This is a Node.js project, so install dependencies as usual:
136
137```sh
138npm install
139```
140
141### pre-commit.com integration
142
143Refer to the documentation at [.pre-commit-config.yaml](.pre-commit-config.yaml).
144
145### Starting the Server
146
147This will run the server on port `8080`:
148
149```sh
150npm run server
151```
152
153Use the `PORT=` environment variable or `--port=` argument to run it on another port:
154
155```sh
156PORT=8081 npm run server
157npm run server -- --port=8081
158```
159
160Use the `DEBUG` environment variable to see debug info:
161
162```sh
163DEBUG=* npm run server
164```
165
166Use the CLI argument `--headless=false` to run browser in headful mode:
167
168```sh
169npm run server -- --headless=false
170```
171
172Use the `CHANNEL=...` environment variable or `--channel=...` argument with one of
Randolf55431462023-03-29 13:00:36173the following values to run the specific Chrome channel: `stable`,
174`beta`, `canary`, `dev`.
Randolfb0fe9c12023-03-06 14:03:48175
176The requested Chrome version should be installed.
177
178```sh
Randolf55431462023-03-29 13:00:36179CHANNEL=dev npm run server
180npm run server -- --channel=dev
181```
182
183Use the CLI argument `--verbose` to have CDP events printed to the console. Note: you have to enable debugging output `bidiMapper:mapperDebug:*` as well.
184
185```sh
186DEBUG=bidiMapper:mapperDebug:* npm run server -- --verbose
187```
188
189or
190
191```sh
192DEBUG=* npm run server -- --verbose
Randolfb0fe9c12023-03-06 14:03:48193```
194
195### Starting on Linux and Mac
196
Randolf Jungbcb3bc82023-06-26 16:30:14197TODO: verify it works on Windows.
Randolfb0fe9c12023-03-06 14:03:48198
199You can also run the server by using script `./runBiDiServer.sh`. It will write
200output to the file `log.txt`:
201
202```sh
203./runBiDiServer.sh --port=8081 --headless=false
204```
205
206## Running
207
208### Unit tests
209
210Running:
211
212```sh
Randolf Jungbcb3bc82023-06-26 16:30:14213npm run unit
Randolfb0fe9c12023-03-06 14:03:48214```
215
216### E2E tests
217
218The E2E tests are written using Python, in order to learn how to eventually do
219this in web-platform-tests.
220
221### Installation
222
223Python 3.6+ and some dependencies are required:
224
225```sh
226python3 -m pip install --user -r tests/requirements.txt
227```
228
229### Running
230
231The E2E tests require BiDi server running on the same host. By default, tests
232try to connect to the port `8080`. The server can be run from the project root:
233
234```sh
Randolf Jungbcb3bc82023-06-26 16:30:14235npm run e2e # alias to to e2e-headless
236npm run e2e-headful
237npm run e2e-headless
Randolfb0fe9c12023-03-06 14:03:48238```
239
240Use the `PORT` environment variable to connect to another port:
241
242```sh
243PORT=8081 npm run e2e
244```
245
246### Examples
247
248Refer to [examples/README.md](examples/README.md).
249
250## WPT (Web Platform Tests)
251
252WPT is added as
253a [git submodule](https://git-scm.com/book/en/v2/Git-Tools-Submodules). To get run
254WPT tests:
255
256### Check out and setup WPT
257
258#### 1. Check out WPT
259
260```sh
261git submodule update --init
262```
263
264#### 2. Go to the WPT folder
265
266```sh
267cd wpt
268```
269
270#### 3. Set up virtualenv
271
272Follow the [_System
273Setup_](https://web-platform-tests.org/running-tests/from-local-system.html#system-setup)
274instructions.
275
276#### 4. Setup `hosts` file
277
278Follow
279the [`hosts` File Setup](https://web-platform-tests.org/running-tests/from-local-system.html#hosts-file-setup)
280instructions.
281
282##### 4.a On Linux, macOS or other UNIX-like system
283
284```sh
285./wpt make-hosts-file | sudo tee -a /etc/hosts
286```
287
288##### 4.b On **Windows**
289
290This must be run in a PowerShell session with Administrator privileges:
291
292```sh
293python wpt make-hosts-file | Out-File $env:SystemRoot\System32\drivers\etc\hosts -Encoding ascii -Append
294```
295
296If you are behind a proxy, you also need to make sure the domains above are excluded
297from your proxy lookups.
298
Randolf Jungbcb3bc82023-06-26 16:30:14299#### 5. Set `BROWSER_BIN`
Randolfb0fe9c12023-03-06 14:03:48300
Randolf Jungbcb3bc82023-06-26 16:30:14301Set the `BROWSER_BIN` environment variable to a Chrome, Edge or Chromium binary to launch.
Randolfb0fe9c12023-03-06 14:03:48302For example, on macOS:
303
304```sh
305# Chrome
Randolf Jungbcb3bc82023-06-26 16:30:14306export BROWSER_BIN="/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary"
307export BROWSER_BIN="/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev"
308export BROWSER_BIN="/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta"
309export BROWSER_BIN="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
310export BROWSER_BIN="/Applications/Chromium.app/Contents/MacOS/Chromium"
Randolfb0fe9c12023-03-06 14:03:48311
312# Edge
Randolf Jungbcb3bc82023-06-26 16:30:14313export BROWSER_BIN="/Applications/Microsoft Edge Canary.app/Contents/MacOS/Microsoft Edge Canary"
314export BROWSER_BIN="/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge"
Randolfb0fe9c12023-03-06 14:03:48315```
316
317### Run WPT tests
318
319#### 1. Make sure you have Chrome Dev installed
320
321https://www.google.com/chrome/dev/
322
Randolf55431462023-03-29 13:00:36323#### 2. Build Chromedriver BiDi
Randolfb0fe9c12023-03-06 14:03:48324
325Oneshot:
326
327```sh
328npm run build
329```
330
331Continuously:
332
333```sh
Randolf Jungbcb3bc82023-06-26 16:30:14334npm run build --watch
Randolfb0fe9c12023-03-06 14:03:48335```
336
337#### 3. Run
338
339```sh
Randolf Jungbcb3bc82023-06-26 16:30:14340npm run wpt -- webdriver/tests/bidi/
Randolfb0fe9c12023-03-06 14:03:48341```
342
343### Update WPT expectations if needed
344
Randolfb0fe9c12023-03-06 14:03:48345```sh
Randolf Jungbcb3bc82023-06-26 16:30:14346UPDATE_EXPECTATIONS=true npm run wpt -- webdriver/tests/bidi/
Randolfb0fe9c12023-03-06 14:03:48347```
348
349## How does it work?
350
351The architecture is described in the
352[WebDriver BiDi in Chrome Context implementation plan](https://docs.google.com/document/d/1VfQ9tv0wPSnb5TI-MOobjoQ5CXLnJJx9F_PxOMQc8kY)
353.
354
355There are 2 main modules:
356
3571. backend WS server in `src`. It runs webSocket server, and for each ws connection
358 runs an instance of browser with BiDi Mapper.
3592. front-end BiDi Mapper in `src/bidiMapper`. Gets BiDi commands from the backend,
360 and map them to CDP commands.
361
362### Contributing
363
364The BiDi commands are processed in the `src/bidiMapper/commandProcessor.ts`. To add a
365new command, add it to `_processCommand`, write and call processor for it.
366
367### Publish new `npm` release
368
Randolf Jungbcb3bc82023-06-26 16:30:14369#### Semi-automatic release
370
371Go to [GitHub Actions](https://github.com/GoogleChromeLabs/chromium-bidi/actions/workflows/create-release-pr.yml) and trigger a run with the correct SemVer
372type.
373That will create a PR. Once that is merge a new tag and release will be created.
374
375#### Manual release
376
3771. Dry-run
378
379 ```sh
380 npm publish --dry-run
381 ```
382
Randolf55431462023-03-29 13:00:363831. Open a PR bumping the chromium-bidi version number in `package.json` for review:
Randolfb0fe9c12023-03-06 14:03:48384
385 ```sh
Randolf55431462023-03-29 13:00:36386 npm version patch -m 'Release v%s' --no-git-tag-version
Randolfb0fe9c12023-03-06 14:03:48387 ```
388
389 Instead of `patch`, use `minor` or `major` [as needed](https://semver.org/).
390
Randolf55431462023-03-29 13:00:363911. After the PR is reviewed, [create a GitHub release](https://github.com/GoogleChromeLabs/chromium-bidi/releases/new) specifying the tag name matching the bumped version.
392 Our CI then automatically publishes the new release to npm based on the tag name.