mirror of
https://github.com/puppeteer/puppeteer
synced 2024-06-14 14:02:48 +00:00
chore: implement Puppeteer.connect
for BiDi over CDP browser (#11350)
Co-authored-by: Maksim Sadym <sadym@google.com>
This commit is contained in:
parent
cdf2b4395c
commit
9f161ec76b
@ -18,6 +18,7 @@ import type {
|
|||||||
IsPageTargetCallback,
|
IsPageTargetCallback,
|
||||||
TargetFilterCallback,
|
TargetFilterCallback,
|
||||||
} from '../api/Browser.js';
|
} from '../api/Browser.js';
|
||||||
|
import type {BidiBrowser} from '../bidi/Browser.js';
|
||||||
import type {ConnectionTransport} from '../common/ConnectionTransport.js';
|
import type {ConnectionTransport} from '../common/ConnectionTransport.js';
|
||||||
import {getFetch} from '../common/fetch.js';
|
import {getFetch} from '../common/fetch.js';
|
||||||
import {debugError} from '../common/util.js';
|
import {debugError} from '../common/util.js';
|
||||||
@ -29,6 +30,9 @@ import {isErrorLike} from '../util/ErrorLike.js';
|
|||||||
import {CdpBrowser} from './Browser.js';
|
import {CdpBrowser} from './Browser.js';
|
||||||
import {Connection} from './Connection.js';
|
import {Connection} from './Connection.js';
|
||||||
import type {ConnectOptions} from './ConnectOptions.js';
|
import type {ConnectOptions} from './ConnectOptions.js';
|
||||||
|
|
||||||
|
const DEFAULT_VIEWPORT = Object.freeze({width: 800, height: 600});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic browser options that can be passed when launching any browser or when
|
* Generic browser options that can be passed when launching any browser or when
|
||||||
* connecting to an existing browser instance.
|
* connecting to an existing browser instance.
|
||||||
@ -79,7 +83,7 @@ const getWebSocketTransportClass = async () => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Users should never call this directly; it's called when calling
|
* Users should never call this directly; it's called when calling
|
||||||
* `puppeteer.connect`.
|
* `puppeteer.connect` with `protocol: 'cdp'`.
|
||||||
*
|
*
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@ -87,51 +91,15 @@ export async function _connectToCdpBrowser(
|
|||||||
options: BrowserConnectOptions & ConnectOptions
|
options: BrowserConnectOptions & ConnectOptions
|
||||||
): Promise<CdpBrowser> {
|
): Promise<CdpBrowser> {
|
||||||
const {
|
const {
|
||||||
browserWSEndpoint,
|
|
||||||
browserURL,
|
|
||||||
ignoreHTTPSErrors = false,
|
ignoreHTTPSErrors = false,
|
||||||
defaultViewport = {width: 800, height: 600},
|
defaultViewport = DEFAULT_VIEWPORT,
|
||||||
transport,
|
|
||||||
headers = {},
|
|
||||||
slowMo = 0,
|
|
||||||
targetFilter,
|
targetFilter,
|
||||||
_isPageTarget: isPageTarget,
|
_isPageTarget: isPageTarget,
|
||||||
protocolTimeout,
|
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
assert(
|
const connection = await getCdpConnection(options);
|
||||||
Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) ===
|
|
||||||
1,
|
|
||||||
'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'
|
|
||||||
);
|
|
||||||
|
|
||||||
let connection!: Connection;
|
|
||||||
if (transport) {
|
|
||||||
connection = new Connection('', transport, slowMo, protocolTimeout);
|
|
||||||
} else if (browserWSEndpoint) {
|
|
||||||
const WebSocketClass = await getWebSocketTransportClass();
|
|
||||||
const connectionTransport: ConnectionTransport =
|
|
||||||
await WebSocketClass.create(browserWSEndpoint, headers);
|
|
||||||
connection = new Connection(
|
|
||||||
browserWSEndpoint,
|
|
||||||
connectionTransport,
|
|
||||||
slowMo,
|
|
||||||
protocolTimeout
|
|
||||||
);
|
|
||||||
} else if (browserURL) {
|
|
||||||
const connectionURL = await getWSEndpoint(browserURL);
|
|
||||||
const WebSocketClass = await getWebSocketTransportClass();
|
|
||||||
const connectionTransport: ConnectionTransport =
|
|
||||||
await WebSocketClass.create(connectionURL);
|
|
||||||
connection = new Connection(
|
|
||||||
connectionURL,
|
|
||||||
connectionTransport,
|
|
||||||
slowMo,
|
|
||||||
protocolTimeout
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const version = await connection.send('Browser.getVersion');
|
const version = await connection.send('Browser.getVersion');
|
||||||
|
|
||||||
const product = version.product.toLowerCase().includes('firefox')
|
const product = version.product.toLowerCase().includes('firefox')
|
||||||
? 'firefox'
|
? 'firefox'
|
||||||
: 'chrome';
|
: 'chrome';
|
||||||
@ -155,6 +123,40 @@ export async function _connectToCdpBrowser(
|
|||||||
return browser;
|
return browser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Users should never call this directly; it's called when calling
|
||||||
|
* `puppeteer.connect` with `protocol: 'webDriverBiDi'`.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export async function _connectToBiDiOverCdpBrowser(
|
||||||
|
options: BrowserConnectOptions & ConnectOptions
|
||||||
|
): Promise<BidiBrowser> {
|
||||||
|
const {ignoreHTTPSErrors = false, defaultViewport = DEFAULT_VIEWPORT} =
|
||||||
|
options;
|
||||||
|
|
||||||
|
const connection = await getCdpConnection(options);
|
||||||
|
|
||||||
|
const version = await connection.send('Browser.getVersion');
|
||||||
|
if (version.product.toLowerCase().includes('firefox')) {
|
||||||
|
throw new Error('Firefox is not supported in BiDi over CDP mode.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use other options too.
|
||||||
|
const BiDi = await import(/* webpackIgnore: true */ '../bidi/bidi.js');
|
||||||
|
const bidiConnection = await BiDi.connectBidiOverCdp(connection);
|
||||||
|
const bidiBrowser = await BiDi.BidiBrowser.create({
|
||||||
|
connection: bidiConnection,
|
||||||
|
closeCallback: () => {
|
||||||
|
return connection.send('Browser.close').catch(debugError);
|
||||||
|
},
|
||||||
|
process: undefined,
|
||||||
|
defaultViewport: defaultViewport,
|
||||||
|
ignoreHTTPSErrors: ignoreHTTPSErrors,
|
||||||
|
});
|
||||||
|
return bidiBrowser;
|
||||||
|
}
|
||||||
|
|
||||||
async function getWSEndpoint(browserURL: string): Promise<string> {
|
async function getWSEndpoint(browserURL: string): Promise<string> {
|
||||||
const endpointURL = new URL('/json/version', browserURL);
|
const endpointURL = new URL('/json/version', browserURL);
|
||||||
|
|
||||||
@ -177,3 +179,51 @@ async function getWSEndpoint(browserURL: string): Promise<string> {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a CDP connection for the given options.
|
||||||
|
*/
|
||||||
|
async function getCdpConnection(
|
||||||
|
options: BrowserConnectOptions & ConnectOptions
|
||||||
|
): Promise<Connection> {
|
||||||
|
const {
|
||||||
|
browserWSEndpoint,
|
||||||
|
browserURL,
|
||||||
|
transport,
|
||||||
|
headers = {},
|
||||||
|
slowMo = 0,
|
||||||
|
protocolTimeout,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
assert(
|
||||||
|
Number(!!browserWSEndpoint) + Number(!!browserURL) + Number(!!transport) ===
|
||||||
|
1,
|
||||||
|
'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (transport) {
|
||||||
|
return new Connection('', transport, slowMo, protocolTimeout);
|
||||||
|
} else if (browserWSEndpoint) {
|
||||||
|
const WebSocketClass = await getWebSocketTransportClass();
|
||||||
|
const connectionTransport: ConnectionTransport =
|
||||||
|
await WebSocketClass.create(browserWSEndpoint, headers);
|
||||||
|
return new Connection(
|
||||||
|
browserWSEndpoint,
|
||||||
|
connectionTransport,
|
||||||
|
slowMo,
|
||||||
|
protocolTimeout
|
||||||
|
);
|
||||||
|
} else if (browserURL) {
|
||||||
|
const connectionURL = await getWSEndpoint(browserURL);
|
||||||
|
const WebSocketClass = await getWebSocketTransportClass();
|
||||||
|
const connectionTransport: ConnectionTransport =
|
||||||
|
await WebSocketClass.create(connectionURL);
|
||||||
|
return new Connection(
|
||||||
|
connectionURL,
|
||||||
|
connectionTransport,
|
||||||
|
slowMo,
|
||||||
|
protocolTimeout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw new Error('Invalid connection options');
|
||||||
|
}
|
||||||
|
@ -15,7 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type {Browser} from '../api/Browser.js';
|
import type {Browser} from '../api/Browser.js';
|
||||||
import {_connectToCdpBrowser} from '../cdp/BrowserConnector.js';
|
import {
|
||||||
|
_connectToBiDiOverCdpBrowser,
|
||||||
|
_connectToCdpBrowser,
|
||||||
|
} from '../cdp/BrowserConnector.js';
|
||||||
import type {ConnectOptions} from '../cdp/ConnectOptions.js';
|
import type {ConnectOptions} from '../cdp/ConnectOptions.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@ -129,7 +132,7 @@ export class Puppeteer {
|
|||||||
*/
|
*/
|
||||||
connect(options: ConnectOptions): Promise<Browser> {
|
connect(options: ConnectOptions): Promise<Browser> {
|
||||||
if (options.protocol === 'webDriverBiDi') {
|
if (options.protocol === 'webDriverBiDi') {
|
||||||
throw new Error('Not implemented');
|
return _connectToBiDiOverCdpBrowser(options);
|
||||||
} else {
|
} else {
|
||||||
return _connectToCdpBrowser(options);
|
return _connectToCdpBrowser(options);
|
||||||
}
|
}
|
||||||
|
@ -383,12 +383,6 @@
|
|||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["FAIL"]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"testIdPattern": "[browser.spec] Browser specs Browser.process should not return child_process for remote browser",
|
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
|
||||||
"parameters": ["webDriverBiDi"],
|
|
||||||
"expectations": ["FAIL"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance",
|
"testIdPattern": "[browser.spec] Browser specs Browser.process should return child_process instance",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
@ -645,13 +639,13 @@
|
|||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject navigation when browser closes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject waitForSelector when browser closes",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Browser.disconnect should reject waitForSelector when browser closes",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["webDriverBiDi"],
|
"parameters": ["webDriverBiDi"],
|
||||||
"expectations": ["FAIL", "PASS"]
|
"expectations": ["FAIL", "TIMEOUT"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.executablePath returns executablePath for channel",
|
||||||
@ -2031,19 +2025,19 @@
|
|||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to close remote browser",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to close remote browser",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect multiple times to the same browser",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect multiple times to the same browser",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to a browser with no page targets",
|
||||||
@ -2061,7 +2055,7 @@
|
|||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to the same page simultaneously",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to connect to the same page simultaneously",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["PASS"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should be able to reconnect to a disconnected browser",
|
||||||
@ -2073,7 +2067,7 @@
|
|||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support ignoreHTTPSErrors option",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support ignoreHTTPSErrors option",
|
||||||
"platforms": ["darwin", "linux", "win32"],
|
"platforms": ["darwin", "linux", "win32"],
|
||||||
"parameters": ["chrome", "webDriverBiDi"],
|
"parameters": ["chrome", "webDriverBiDi"],
|
||||||
"expectations": ["FAIL"]
|
"expectations": ["SKIP"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option",
|
"testIdPattern": "[launcher.spec] Launcher specs Puppeteer Puppeteer.connect should support targetFilter option",
|
||||||
|
Loading…
Reference in New Issue
Block a user