feat: add option to filter targets (#7192)

* feat: add option to filter targets

Co-authored-by: Mathias Bynens <mathias@qiwi.be>
This commit is contained in:
Jan Scheffler 2021-05-03 13:48:31 +02:00 committed by GitHub
parent a293b96952
commit ec3fc2e035
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 5 deletions

View File

@ -516,6 +516,7 @@ Clears all registered handlers.
- `slowMo` <[number]> Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.
- `transport` <[ConnectionTransport]> **Experimental** Specify a custom transport object for Puppeteer to use.
- `product` <[string]> Possible values are: `chrome`, `firefox`. Defaults to `chrome`.
- `targetFilter` <?[function]\([Protocol.Target.TargetInfo]\):[Promise]<[boolean]>|[boolean]> Use this function to decide if Puppeteer should connect to the given target. If a `targetFilter` is provided, Puppeteer only connects to targets for which `targetFilter` returns `true`. By default, Puppeteer connects to all available targets.
- returns: <[Promise]<[Browser]>>
This methods attaches Puppeteer to an existing browser instance.
@ -623,6 +624,7 @@ try {
- `devtools` <[boolean]> Whether to auto-open a DevTools panel for each tab. If this option is `true`, the `headless` option will be set `false`.
- `pipe` <[boolean]> Connects to the browser over a pipe instead of a WebSocket. Defaults to `false`.
- `extraPrefsFirefox` <[Object]> Additional [preferences](https://developer.mozilla.org/en-US/docs/Mozilla/Preferences/Preference_reference) that can be passed to Firefox (see `PUPPETEER_PRODUCT`)
- `targetFilter` <?[function]\([Protocol.Target.TargetInfo]\):[Promise]<[boolean]>|[boolean]> Use this function to decide if Puppeteer should connect to the given target. If a `targetFilter` is provided, Puppeteer only connects to targets for which `targetFilter` returns `true`. By default, Puppeteer connects to all available targets.
- returns: <[Promise]<[Browser]>> Promise which resolves to browser instance.
You can use `ignoreDefaultArgs` to filter out `--mute-audio` from default arguments:

View File

@ -29,6 +29,13 @@ import { Viewport } from './PuppeteerViewport.js';
*/
export type BrowserCloseCallback = () => Promise<void> | void;
/**
* @public
*/
export type TargetFilterCallback = (
target: Protocol.Target.TargetInfo
) => Promise<boolean> | boolean;
const WEB_PERMISSION_TO_PROTOCOL_PERMISSION = new Map<
Permission,
Protocol.Browser.PermissionType
@ -189,7 +196,8 @@ export class Browser extends EventEmitter {
ignoreHTTPSErrors: boolean,
defaultViewport?: Viewport | null,
process?: ChildProcess,
closeCallback?: BrowserCloseCallback
closeCallback?: BrowserCloseCallback,
targetFilterCallback?: TargetFilterCallback
): Promise<Browser> {
const browser = new Browser(
connection,
@ -197,7 +205,8 @@ export class Browser extends EventEmitter {
ignoreHTTPSErrors,
defaultViewport,
process,
closeCallback
closeCallback,
targetFilterCallback
);
await connection.send('Target.setDiscoverTargets', { discover: true });
return browser;
@ -207,6 +216,7 @@ export class Browser extends EventEmitter {
private _process?: ChildProcess;
private _connection: Connection;
private _closeCallback: BrowserCloseCallback;
private _targetFilterCallback: TargetFilterCallback;
private _defaultContext: BrowserContext;
private _contexts: Map<string, BrowserContext>;
/**
@ -224,7 +234,8 @@ export class Browser extends EventEmitter {
ignoreHTTPSErrors: boolean,
defaultViewport?: Viewport | null,
process?: ChildProcess,
closeCallback?: BrowserCloseCallback
closeCallback?: BrowserCloseCallback,
targetFilterCallback?: TargetFilterCallback
) {
super();
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
@ -232,6 +243,7 @@ export class Browser extends EventEmitter {
this._process = process;
this._connection = connection;
this._closeCallback = closeCallback || function (): void {};
this._targetFilterCallback = targetFilterCallback || ((): boolean => true);
this._defaultContext = new BrowserContext(this._connection, this, null);
this._contexts = new Map();
@ -330,6 +342,11 @@ export class Browser extends EventEmitter {
? this._contexts.get(browserContextId)
: this._defaultContext;
const shouldAttachToTarget = await this._targetFilterCallback(targetInfo);
if (!shouldAttachToTarget) {
return;
}
const target = new Target(
targetInfo,
context,

View File

@ -15,7 +15,7 @@
*/
import { ConnectionTransport } from './ConnectionTransport.js';
import { Browser } from './Browser.js';
import { Browser, TargetFilterCallback } from './Browser.js';
import { assert } from './assert.js';
import { debugError } from '../common/helper.js';
import { Connection } from './Connection.js';
@ -43,6 +43,10 @@ export interface BrowserConnectOptions {
* aid debugging.
*/
slowMo?: number;
/**
* Callback to decide if Puppeteer should connect to a given target or not.
*/
targetFilter?: TargetFilterCallback;
}
const getWebSocketTransportClass = async () => {
@ -71,6 +75,7 @@ export const connectToBrowser = async (
defaultViewport = { width: 800, height: 600 },
transport,
slowMo = 0,
targetFilter,
} = options;
assert(
@ -106,7 +111,8 @@ export const connectToBrowser = async (
ignoreHTTPSErrors,
defaultViewport,
null,
() => connection.send('Browser.close').catch(debugError)
() => connection.send('Browser.close').catch(debugError),
targetFilter
);
};

View File

@ -18,6 +18,7 @@ import os from 'os';
import path from 'path';
import sinon from 'sinon';
import { promisify } from 'util';
import Protocol from 'devtools-protocol';
import {
getTestState,
itFailsFirefox,
@ -538,6 +539,35 @@ describe('Launcher specs', function () {
await page.close();
await browser.close();
});
it('should support targetFilter option', async () => {
const { server, puppeteer, defaultBrowserOptions } = getTestState();
const originalBrowser = await puppeteer.launch(defaultBrowserOptions);
const browserWSEndpoint = originalBrowser.wsEndpoint();
const page1 = await originalBrowser.newPage();
await page1.goto(server.EMPTY_PAGE);
const page2 = await originalBrowser.newPage();
await page2.goto(server.EMPTY_PAGE + '?should-be-ignored');
const browser = await puppeteer.connect({
browserWSEndpoint,
targetFilter: (targetInfo: Protocol.Target.TargetInfo) =>
!targetInfo.url.includes('should-be-ignored'),
});
const pages = await browser.pages();
await page2.close();
await page1.close();
await browser.close();
expect(pages.map((p: Page) => p.url()).sort()).toEqual([
'about:blank',
server.EMPTY_PAGE,
]);
});
itFailsFirefox(
'should be able to reconnect to a disconnected browser',
async () => {