feat(launcher): add browserUrl option to puppeteer.connect (#3558)
The `browserURL` option allows to connect to a browser that exposed it's remote debugging protocol on a known port. Fixes #3537
This commit is contained in:
parent
81cf579275
commit
15af75f9a2
@ -444,7 +444,8 @@ puppeteer.launch().then(async browser => {
|
||||
|
||||
#### puppeteer.connect(options)
|
||||
- `options` <[Object]>
|
||||
- `browserWSEndpoint` <[string]> a [browser websocket endpoint](#browserwsendpoint) to connect to.
|
||||
- `browserWSEndpoint` <?[string]> a [browser websocket endpoint](#browserwsendpoint) to connect to.
|
||||
- `browserUrl` <?[string]> a browser url to connect to, in format `http://${host}:${port}`. Use interchangeably with `browserWSEndpoint` to let Puppeteer fetch it from [metadata endpoint](https://chromedevtools.github.io/devtools-protocol/#how-do-i-access-the-browser-target).
|
||||
- `ignoreHTTPSErrors` <[boolean]> Whether to ignore HTTPS errors during navigation. Defaults to `false`.
|
||||
- `defaultViewport` <?[Object]> Sets a consistent viewport for each page. Defaults to an 800x600 viewport. `null` disables the default viewport.
|
||||
- `width` <[number]> page width in pixels.
|
||||
|
@ -15,6 +15,8 @@
|
||||
*/
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const http = require('http');
|
||||
const URL = require('url');
|
||||
const removeFolder = require('rimraf');
|
||||
const childProcess = require('child_process');
|
||||
const BrowserFetcher = require('./BrowserFetcher');
|
||||
@ -276,18 +278,33 @@ class Launcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!(Launcher.BrowserOptions & {browserWSEndpoint: string, transport?: !Puppeteer.ConnectionTransport})} options
|
||||
* @param {!(Launcher.BrowserOptions & {browserWSEndpoint?: string, browserUrl?: string, transport?: !Puppeteer.ConnectionTransport})} options
|
||||
* @return {!Promise<!Browser>}
|
||||
*/
|
||||
async connect(options) {
|
||||
const {
|
||||
browserWSEndpoint,
|
||||
browserUrl,
|
||||
ignoreHTTPSErrors = false,
|
||||
defaultViewport = {width: 800, height: 600},
|
||||
transport = await WebSocketTransport.create(browserWSEndpoint),
|
||||
transport,
|
||||
slowMo = 0,
|
||||
} = options;
|
||||
const connection = new Connection(browserWSEndpoint, transport, slowMo);
|
||||
|
||||
let connectionUrl;
|
||||
let connectionTransport;
|
||||
|
||||
if (browserWSEndpoint)
|
||||
connectionUrl = browserWSEndpoint;
|
||||
else if (!browserWSEndpoint && browserUrl)
|
||||
connectionUrl = await getWSEndpoint(browserUrl);
|
||||
|
||||
if (transport)
|
||||
connectionTransport = transport;
|
||||
else
|
||||
connectionTransport = await WebSocketTransport.create(connectionUrl);
|
||||
|
||||
const connection = new Connection(connectionUrl, connectionTransport, slowMo);
|
||||
const {browserContextIds} = await connection.send('Target.getBrowserContexts');
|
||||
return Browser.create(connection, browserContextIds, ignoreHTTPSErrors, defaultViewport, null, () => connection.send('Browser.close').catch(debugError));
|
||||
}
|
||||
@ -375,6 +392,48 @@ function waitForWSEndpoint(chromeProcess, timeout, preferredRevision) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} browserUrl
|
||||
* @return {!Promise<string>}
|
||||
*/
|
||||
function getWSEndpoint(browserUrl) {
|
||||
let resolve, reject;
|
||||
const endpointUrl = URL.resolve(browserUrl, '/json/version');
|
||||
const requestOptions = Object.assign(URL.parse(endpointUrl), { method: 'GET' });
|
||||
const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
|
||||
|
||||
function handleRequestEnd(data) {
|
||||
try {
|
||||
const {webSocketDebuggerUrl} = JSON.parse(data);
|
||||
resolve(webSocketDebuggerUrl);
|
||||
} catch (e) {
|
||||
handleRequestError(e);
|
||||
}
|
||||
}
|
||||
|
||||
function handleRequestError(err) {
|
||||
reject(new Error(`Failed to fetch browser webSocket url from ${endpointUrl}: ${err}`));
|
||||
}
|
||||
|
||||
const request = http.request(requestOptions, res => {
|
||||
let data = '';
|
||||
if (res.statusCode !== 200) {
|
||||
// consume response data to free up memory
|
||||
res.resume();
|
||||
handleRequestError(res.statusCode);
|
||||
return;
|
||||
}
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', chunk => data += chunk);
|
||||
res.on('end', () => handleRequestEnd(data));
|
||||
});
|
||||
|
||||
request.on('error', handleRequestError);
|
||||
request.end();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {Object} Launcher.ChromeArgOptions
|
||||
* @property {boolean=} headless
|
||||
|
@ -37,7 +37,7 @@ module.exports = class {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!(Launcher.BrowserOptions & {browserWSEndpoint: string, transport?: !Puppeteer.ConnectionTransport})} options
|
||||
* @param {!(Launcher.BrowserOptions & {browserWSEndpoint?: string, browserUrl?: string, transport?: !Puppeteer.ConnectionTransport})} options
|
||||
* @return {!Promise<!Puppeteer.Browser>}
|
||||
*/
|
||||
connect(options) {
|
||||
|
@ -344,6 +344,24 @@ module.exports.addTests = function({testRunner, expect, defaultBrowserOptions})
|
||||
expect(await restoredPage.evaluate(() => 7 * 8)).toBe(56);
|
||||
await browser.close();
|
||||
});
|
||||
it('should be able to connect using browserUrl, with and without trailing slash', async({server}) => {
|
||||
const originalBrowser = await puppeteer.launch(Object.assign({}, defaultBrowserOptions, {
|
||||
args: ['--remote-debugging-port=21222']
|
||||
}));
|
||||
const browserUrl = 'http://127.0.0.1:21222';
|
||||
|
||||
const browser1 = await puppeteer.connect({browserUrl});
|
||||
const page1 = await browser1.newPage();
|
||||
expect(await page1.evaluate(() => 7 * 8)).toBe(56);
|
||||
browser1.disconnect();
|
||||
|
||||
const browser2 = await puppeteer.connect({browserUrl: browserUrl + '/'});
|
||||
const page2 = await browser2.newPage();
|
||||
expect(await page2.evaluate(() => 8 * 7)).toBe(56);
|
||||
browser2.disconnect();
|
||||
|
||||
originalBrowser.close();
|
||||
});
|
||||
});
|
||||
describe('Puppeteer.executablePath', function() {
|
||||
it('should work', async({server}) => {
|
||||
|
Loading…
Reference in New Issue
Block a user