Skip to content

Commit

Permalink
feat: experimental WebDriver BiDi support with Firefox (#11412)
Browse files Browse the repository at this point in the history
Co-authored-by: Jecelyn Yeen <5917927+jecfish@users.noreply.github.com>
  • Loading branch information
OrKoN and jecfish committed Nov 28, 2023
1 parent 6a944bf commit 8aba033
Show file tree
Hide file tree
Showing 23 changed files with 269 additions and 485 deletions.
1 change: 1 addition & 0 deletions docs/api/index.md
Expand Up @@ -198,6 +198,7 @@ sidebar_label: API
| [Predicate](./puppeteer.predicate.md) | |
| [Product](./puppeteer.product.md) | Supported products. |
| [ProtocolLifeCycleEvent](./puppeteer.protocollifecycleevent.md) | |
| [ProtocolType](./puppeteer.protocoltype.md) | |
| [PuppeteerLifeCycleEvent](./puppeteer.puppeteerlifecycleevent.md) | |
| [PuppeteerNodeLaunchOptions](./puppeteer.puppeteernodelaunchoptions.md) | Utility type exposed to enable users to define options that can be passed to <code>puppeteer.launch</code> without having to list the set of all types. |
| [Quad](./puppeteer.quad.md) | |
Expand Down
1 change: 1 addition & 0 deletions docs/api/puppeteer.browserconnectoptions.md
Expand Up @@ -18,6 +18,7 @@ export interface BrowserConnectOptions
| ----------------- | --------------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------- |
| defaultViewport | <code>optional</code> | [Viewport](./puppeteer.viewport.md) \| null | Sets the viewport for each page. | '{width: 800, height: 600}' |
| ignoreHTTPSErrors | <code>optional</code> | boolean | Whether to ignore HTTPS errors during navigation. | <code>false</code> |
| protocol | <code>optional</code> | [ProtocolType](./puppeteer.protocoltype.md) | | 'cdp' |
| protocolTimeout | <code>optional</code> | number | Timeout setting for individual protocol (CDP) calls. | <code>180_000</code> |
| slowMo | <code>optional</code> | number | Slows down Puppeteer operations by the specified amount of milliseconds to aid debugging. | |
| targetFilter | <code>optional</code> | [TargetFilterCallback](./puppeteer.targetfiltercallback.md) | Callback to decide if Puppeteer should connect to a given target or not. | |
2 changes: 2 additions & 0 deletions docs/api/puppeteer.page.emulate.md
Expand Up @@ -28,6 +28,8 @@ Promise&lt;void&gt;

## Remarks

This method is a shortcut for calling two methods: [Page.setUserAgent()](./puppeteer.page.setuseragent.md) and [Page.setViewport()](./puppeteer.page.setviewport.md).

This method will resize the page. A lot of websites don't expect phones to change size, so you should emulate before navigating to the page.

## Example
Expand Down
2 changes: 0 additions & 2 deletions docs/api/puppeteer.page.type.md
Expand Up @@ -32,8 +32,6 @@ class Page {

Promise&lt;void&gt;

## Remarks

## Example

```ts
Expand Down
11 changes: 11 additions & 0 deletions docs/api/puppeteer.protocoltype.md
@@ -0,0 +1,11 @@
---
sidebar_label: ProtocolType
---

# ProtocolType type

#### Signature:

```typescript
export type ProtocolType = 'cdp' | 'webDriverBiDi';
```
10 changes: 10 additions & 0 deletions docs/faq.md
Expand Up @@ -27,6 +27,16 @@ support to browsers such as Safari. This effort includes exploration of a
standard for executing cross-browser commands (instead of relying on the
non-standard DevTools Protocol used by Chrome).

Update 2023-11-17: Puppeteer has experimental support for the new
[WebDriverBiDi](https://w3c.github.io/webdriver-bidi/) protocol that can be used
to automate Firefox. The WebDriver BiDi implementation in Firefox will replace
the current CDP implementation in Firefox in the future. See
https://pptr.dev/webdriver-bidi for more details.

## Q: Does Puppeteer support WebDriver BiDi?

Puppeteer has experimental support for WebDriver BiDi. See https://pptr.dev/webdriver-bidi.

## Q: What are Puppeteer’s goals and principles?

The goals of the project are:
Expand Down
189 changes: 189 additions & 0 deletions docs/webdriver-bidi.md
@@ -0,0 +1,189 @@
# Experimental WebDriver BiDi Support

[WebDriver BiDi](https://w3c.github.io/webdriver-bidi/) is a new cross-browser
automation protocol that adds browser-driven events to WebDriver. Here are the
resources if you want to learn more about WebDriver BiDi:

- [WebDriver BiDi - The future of cross-browser automation](https://developer.chrome.com/articles/webdriver-bidi/)
- [WebDriver BiDi: 2023 status update](https://developer.chrome.com/blog/webdriver-bidi-2023/)

## Automate with Chrome and Firefox

Firefox support has almost reaching feature parity with the previous CDP-based
implementation. To see which features are fully supported with WebDriver BiDi we
used the [Puppeteer test suite](https://puppeteer.github.io/ispuppeteerwebdriverbidiready/). Currently,
we still have fewer than
[60](https://puppeteer.github.io/ispuppeteerwebdriverbidiready/firefox-delta.json)
tests that are failing with Firefox and WebDriver BiDi compared to the previous
CDP implementation in Firefox but we also have more than
[82](https://puppeteer.github.io/ispuppeteerwebdriverbidiready/firefox-delta.json)
new tests that work with WebDriver BiDi and that didn't work with CDP.

For Chrome, around 68% of the tests are currently passing with WebDriver BiDi so
the CDP-based implementation remains more powerful. Some of the Puppeteer
functionality is relying on CDP even with WebDriver BiDi enabled. Therefore, the
test pass rate is currently higher than that one of Firefox.

Example of launching Firefox with WebDriver BiDi:

```ts
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
product: 'firefox',
protocol: 'webDriverBiDi',
});
const page = await browser.newPage();
...
await browser.close();
```

Example of launching Chrome with WebDriver BiDi:

```ts
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
product: 'chrome',
protocol: 'webDriverBiDi',
});
const page = await browser.newPage();
...
await browser.close();
```

## Puppeteer features supported over WebDriver BiDi

- Browser and page automation

- Browser.close
- Frame.goto() (except `referer` and `referrerPolicy`)
- Page.bringToFront
- Page.goto (except `referer` and `referrerPolicy`)
- Page.reload (except for `ignoreCache` parameter)
- Page.setViewport (`width`, `height`, `deviceScaleFactor` only)
- Puppeteer.launch

- [Script evaluation](https://pptr.dev/guides/evaluate-javascript):

- JSHandle.evaluate
- JSHandle.evaluateHandle
- Page.evaluate
- Page.exposeFunction

- [Selectors](https://pptr.dev/guides/query-selectors) and [locators](https://pptr.dev/guides/locators) except for ARIA:

- Page.$ (ARIA selectors supported in Chrome)
- Page.$$ (ARIA selectors supported in Chrome)
- Page.$$eval (ARIA selectors supported in Chrome)
- Page.$eval (ARIA selectors supported in Chrome)
- Page.waitForSelector (ARIA selectors supported in Chrome)

- Input

- ElementHandle.click
- Keyboard.down
- Keyboard.press
- Keyboard.sendCharacter
- Keyboard.type
- Keyboard.up
- Mouse events (except for dedicated drag'n'drop API methods)
- Page.tap
- TouchScreen.\*

- JavaScript dialog interception

- page.on('dialog')
- Dialog.\*

- Screenshots (not all parameters are supported)

- Page.screenshot (supported parameters `clip`, `encoding`, `fullPage`)

- PDF generation (not all parameters are supported)

- Page.pdf (only `format`, `height`, `landscape`, `margin`, `pageRanges`, `printBackground`, `scale`, `width` are supported)
- Page.createPDFStream (only `format`, `height`, `landscape`, `margin`, `pageRanges`, `printBackground`, `scale`, `width` are supported)

## Puppeteer features not yet supported over WebDriver BiDi

- [Request interception](https://pptr.dev/guides/request-interception)

- HTTPRequest.abort()
- HTTPRequest.abortErrorReason()
- HTTPRequest.client()
- HTTPRequest.continue()
- HTTPRequest.continueRequestOverrides()
- HTTPRequest.failure()
- HTTPRequest.finalizeInterceptions()
- HTTPRequest.interceptResolutionState()
- HTTPRequest.isInterceptResolutionHandled()
- HTTPRequest.respond()
- HTTPRequest.responseForRequest()
- Page.setRequestInterception()

- Permissions

- BrowserContext.clearPermissionOverrides()
- BrowserContext.overridePermissions()

- Various emulations (most are supported with Chrome)

- Page.emulate() (supported only in Chrome)
- Page.emulateCPUThrottling() (supported only in Chrome)
- Page.emulateIdleState() (supported only in Chrome)
- Page.emulateMediaFeatures() (supported only in Chrome)
- Page.emulateMediaType() (supported only in Chrome)
- Page.emulateTimezone() (supported only in Chrome)
- Page.emulateVisionDeficiency() (supported only in Chrome)
- Page.setBypassCSP() (supported only in Chrome)
- Page.setCacheEnabled() (supported only in Chrome)
- Page.setGeolocation() (supported only in Chrome)
- Page.setJavaScriptEnabled() (supported only in Chrome)

- CDP-specific features

- Page.createCDPSession() (supported only in Chrome)

- Tracing (supported only in Chrome)
- Coverage (supported only in Chrome)
- Accessibility (supported only in Chrome)

- Other methods:

- Browser.userAgent()
- ElementHandle.uploadFile()
- Frame.isOOPFrame()
- Frame.waitForDevicePrompt()
- HTTPResponse.buffer()
- HTTPResponse.fromServiceWorker()
- HTTPResponse.securityDetails()
- Input.drag()
- Input.dragAndDrop()
- Input.dragOver()
- Input.drop()
- Page.authenticate()
- Page.cookies()
- Page.deleteCookie()
- Page.emulateNetworkConditions()
- Page.goBack()
- Page.goForward()
- Page.isDragInterceptionEnabled()
- Page.isJavaScriptEnabled() (supported only in Chrome)
- Page.isServiceWorkerBypassed()
- Page.metrics()
- Page.queryObjects() (supported only in Chrome)
- Page.screencast() (supported only in Chrome)
- Page.setBypassServiceWorker()
- Page.setCookie()
- Page.setDragInterception()
- Page.setExtraHTTPHeaders()
- Page.setOfflineMode()
- Page.setUserAgent()
- Page.waitForDevicePrompt()
- Page.waitForFileChooser()
- Page.workers()
- PageEvent.popup
- PageEvent.WorkerCreated
- PageEvent.WorkerDestroyed
- Target.opener()
4 changes: 0 additions & 4 deletions packages/puppeteer-core/src/api/Browser.ts
Expand Up @@ -401,10 +401,6 @@ export abstract class Browser extends EventEmitter<BrowserEvents> {
* {@link Page | Pages} can override the user agent with
* {@link Page.setUserAgent}.
*
* @privateRemarks BiDi
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | CDP}: Supported
*
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | BiDi}: Unsupported
*/
abstract userAgent(): Promise<string>;

Expand Down
10 changes: 0 additions & 10 deletions packages/puppeteer-core/src/api/BrowserContext.ts
Expand Up @@ -164,11 +164,6 @@ export abstract class BrowserContext extends EventEmitter<BrowserContextEvents>
* "https://example.com".
* @param permissions - An array of permissions to grant. All permissions that
* are not listed here will be automatically denied.
*
* @privateRemarks BiDi
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | CDP}: Supported
*
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | BiDi}: Unsupported
*/
abstract overridePermissions(
origin: string,
Expand All @@ -188,11 +183,6 @@ export abstract class BrowserContext extends EventEmitter<BrowserContextEvents>
* // do stuff ..
* context.clearPermissionOverrides();
* ```
*
* @privateRemarks BiDi
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | CDP}: Supported
*
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | BiDi}: Unsupported
*/
abstract clearPermissionOverrides(): Promise<void>;

Expand Down
5 changes: 0 additions & 5 deletions packages/puppeteer-core/src/api/ElementHandle.ts
Expand Up @@ -962,11 +962,6 @@ export abstract class ElementHandle<
* {@link https://nodejs.org/api/process.html#process_process_cwd | current working directory}.
* For locals script connecting to remote chrome environments, paths must be
* absolute.
*
* @privateRemarks BiDi
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | CDP}: Supported
*
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | BiDi}: Unsupported
*/
abstract uploadFile(
this: ElementHandle<HTMLInputElement>,
Expand Down
18 changes: 0 additions & 18 deletions packages/puppeteer-core/src/api/Frame.ts
Expand Up @@ -311,11 +311,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> {
/**
* Is `true` if the frame is an out-of-process (OOP) frame. Otherwise,
* `false`.
*
* @privateRemarks BiDi
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | CDP}: Supported
*
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | BiDi}: Unsupported
*/
abstract isOOPFrame(): boolean;

Expand Down Expand Up @@ -352,14 +347,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> {
* returned by the remote server, including 404 "Not Found" and 500 "Internal
* Server Error". The status code for such responses can be retrieved by
* calling {@link HTTPResponse.status}.
*
* @privateRemarks BiDi
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | CDP}: Supported
*
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | BiDi}: Partial support
*
* - `referer` not supported
* - `referrerPolicy` not supported
*/
abstract goto(
url: string,
Expand Down Expand Up @@ -1209,11 +1196,6 @@ export abstract class Frame extends EventEmitter<FrameEvents> {
* );
* ```
*
* @privateRemarks BiDi
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | CDP}: Supported
*
* {@link PROTOCOL_GET_STARTED_LINK_TEMPLATE | BiDi}: Unsupported
*
* @internal
*/
abstract waitForDevicePrompt(
Expand Down

0 comments on commit 8aba033

Please sign in to comment.