feat: expose raw devtools protocol connection (#1770)
feat: expose raw devtools protocol connection This patch introduces `target.createCDPSession` method that allows directly communicating with the target over the Chrome DevTools Protocol. Fixes #31.
This commit is contained in:
parent
ec8e40f1cb
commit
5368051610
48
docs/api.md
48
docs/api.md
@ -87,6 +87,7 @@
|
||||
* [page.setUserAgent(userAgent)](#pagesetuseragentuseragent)
|
||||
* [page.setViewport(viewport)](#pagesetviewportviewport)
|
||||
* [page.tap(selector)](#pagetapselector)
|
||||
* [page.target()](#pagetarget)
|
||||
* [page.title()](#pagetitle)
|
||||
* [page.touchscreen](#pagetouchscreen)
|
||||
* [page.tracing](#pagetracing)
|
||||
@ -198,9 +199,13 @@
|
||||
* [response.text()](#responsetext)
|
||||
* [response.url()](#responseurl)
|
||||
- [class: Target](#class-target)
|
||||
* [target.createCDPSession()](#targetcreatecdpsession)
|
||||
* [target.page()](#targetpage)
|
||||
* [target.type()](#targettype)
|
||||
* [target.url()](#targeturl)
|
||||
- [class: CDPSession](#class-cdpsession)
|
||||
* [cdpSession.detach()](#cdpsessiondetach)
|
||||
* [cdpSession.send(method[, params])](#cdpsessionsendmethod-params)
|
||||
- [class: Coverage](#class-coverage)
|
||||
* [coverage.startCSSCoverage(options)](#coveragestartcsscoverageoptions)
|
||||
* [coverage.startJSCoverage(options)](#coveragestartjscoverageoptions)
|
||||
@ -1139,6 +1144,9 @@ In the case of multiple pages in a single browser, each page can have its own vi
|
||||
This method fetches an element with `selector`, scrolls it into view if needed, and then uses [page.touchscreen](#pagetouchscreen) to tap in the center of the element.
|
||||
If there's no element matching `selector`, the method throws an error.
|
||||
|
||||
#### page.target()
|
||||
- returns: <[Target]> a target this page was created from.
|
||||
|
||||
#### page.title()
|
||||
- returns: <[Promise]<[string]>> Returns page's title.
|
||||
|
||||
@ -2166,6 +2174,11 @@ Contains the URL of the response.
|
||||
|
||||
### class: Target
|
||||
|
||||
#### target.createCDPSession()
|
||||
- returns: <[Promise]<[CDPSession]>>
|
||||
|
||||
Creates a Chrome Devtools Protocol session attached to the target.
|
||||
|
||||
#### target.page()
|
||||
- returns: <[Promise]<?[Page]>>
|
||||
|
||||
@ -2179,6 +2192,40 @@ Identifies what kind of target this is. Can be `"page"`, `"service_worker"`, or
|
||||
#### target.url()
|
||||
- returns: <[string]>
|
||||
|
||||
|
||||
### class: CDPSession
|
||||
|
||||
* extends: [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter)
|
||||
|
||||
The `CDPSession` instances are used to talk raw Chrome Devtools Protocol:
|
||||
- protocol methods can be called with `session.send` method.
|
||||
- protocol events can be subscribed to with `session.on` method.
|
||||
|
||||
Documentation on DevTools Protocol can be found here: [DevTools Protocol Viewer](https://chromedevtools.github.io/devtools-protocol/).
|
||||
|
||||
```js
|
||||
const client = await page.target().createCDPSession();
|
||||
await client.send('Animation.enable');
|
||||
await client.on('Animation.animationCreated', () => console.log('Animation created!'));
|
||||
const response = await client.send('Animation.getPlaybackRate');
|
||||
console.log('playback rate is ' + response.playbackRate);
|
||||
await client.send('Animation.setPlaybackRate', {
|
||||
playbackRate: response.playbackRate / 2
|
||||
});
|
||||
```
|
||||
|
||||
#### cdpSession.detach()
|
||||
- returns: <[Promise]>
|
||||
|
||||
Detaches session from target. Once detached, session won't emit any events and can't be used
|
||||
to send messages.
|
||||
|
||||
#### cdpSession.send(method[, params])
|
||||
- `method` <[string]> protocol method name
|
||||
- `params` <[Object]> Optional method parameters
|
||||
- returns: <[Promise]<[Object]>>
|
||||
|
||||
|
||||
### class: Coverage
|
||||
|
||||
Coverage gathers information about parts of JavaScript and CSS that were used by the page.
|
||||
@ -2253,6 +2300,7 @@ reported.
|
||||
[Promise]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise "Promise"
|
||||
[string]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type "String"
|
||||
[stream.Readable]: https://nodejs.org/api/stream.html#stream_class_stream_readable "stream.Readable"
|
||||
[CDPSession]: #class-cdpsession "CDPSession"
|
||||
[Error]: https://nodejs.org/api/errors.html#errors_class_error "Error"
|
||||
[Frame]: #class-frame "Frame"
|
||||
[ConsoleMessage]: #class-consolemessage "ConsoleMessage"
|
||||
|
@ -193,6 +193,7 @@ class Target {
|
||||
*/
|
||||
constructor(browser, targetInfo) {
|
||||
this._browser = browser;
|
||||
this._targetId = targetInfo.targetId;
|
||||
this._targetInfo = targetInfo;
|
||||
/** @type {?Promise<!Page>} */
|
||||
this._pagePromise = null;
|
||||
@ -202,13 +203,20 @@ class Target {
|
||||
this._initializedCallback(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<!Puppeteer.CDPSession>}
|
||||
*/
|
||||
createCDPSession() {
|
||||
return this._browser._connection.createSession(this._targetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Promise<?Page>}
|
||||
*/
|
||||
async page() {
|
||||
if (this._targetInfo.type === 'page' && !this._pagePromise) {
|
||||
this._pagePromise = this._browser._connection.createSession(this._targetInfo.targetId)
|
||||
.then(client => Page.create(client, this._browser._ignoreHTTPSErrors, this._browser._appMode, this._browser._screenshotTaskQueue));
|
||||
this._pagePromise = this._browser._connection.createSession(this._targetId)
|
||||
.then(client => Page.create(client, this, this._browser._ignoreHTTPSErrors, this._browser._appMode, this._browser._screenshotTaskQueue));
|
||||
}
|
||||
return this._pagePromise;
|
||||
}
|
||||
@ -258,4 +266,4 @@ helper.tracePublicAPI(Target);
|
||||
* @property {boolean} attached
|
||||
*/
|
||||
|
||||
module.exports = { Browser, TaskQueue };
|
||||
module.exports = { Browser, TaskQueue, Target };
|
||||
|
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
const {helper} = require('./helper');
|
||||
const debugProtocol = require('debug')('puppeteer:protocol');
|
||||
const debugSession = require('debug')('puppeteer:session');
|
||||
|
||||
@ -49,7 +50,7 @@ class Connection extends EventEmitter {
|
||||
this._ws = ws;
|
||||
this._ws.on('message', this._onMessage.bind(this));
|
||||
this._ws.on('close', this._onClose.bind(this));
|
||||
/** @type {!Map<string, !Session>}*/
|
||||
/** @type {!Map<string, !CDPSession>}*/
|
||||
this._sessions = new Map();
|
||||
}
|
||||
|
||||
@ -135,17 +136,17 @@ class Connection extends EventEmitter {
|
||||
|
||||
/**
|
||||
* @param {string} targetId
|
||||
* @return {!Promise<!Session>}
|
||||
* @return {!Promise<!CDPSession>}
|
||||
*/
|
||||
async createSession(targetId) {
|
||||
const {sessionId} = await this.send('Target.attachToTarget', {targetId});
|
||||
const session = new Session(this, targetId, sessionId);
|
||||
const session = new CDPSession(this, targetId, sessionId);
|
||||
this._sessions.set(sessionId, session);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
class Session extends EventEmitter {
|
||||
class CDPSession extends EventEmitter {
|
||||
/**
|
||||
* @param {!Connection} connection
|
||||
* @param {string} targetId
|
||||
@ -161,13 +162,6 @@ class Session extends EventEmitter {
|
||||
this._sessionId = sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
targetId() {
|
||||
return this._targetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} method
|
||||
* @param {!Object=} params
|
||||
@ -211,9 +205,8 @@ class Session extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
async dispose() {
|
||||
console.assert(!!this._connection, 'Protocol error: Connection closed. Most likely the page has been closed.');
|
||||
await this._connection.send('Target.closeTarget', {targetId: this._targetId});
|
||||
async detach() {
|
||||
await this._connection.send('Target.detachFromTarget', {sessionId: this._sessionId});
|
||||
}
|
||||
|
||||
_onClosed() {
|
||||
@ -223,6 +216,7 @@ class Session extends EventEmitter {
|
||||
this._connection = null;
|
||||
}
|
||||
}
|
||||
helper.tracePublicAPI(CDPSession);
|
||||
|
||||
/**
|
||||
* @param {!Error} error
|
||||
@ -234,4 +228,4 @@ function rewriteError(error, message) {
|
||||
return error;
|
||||
}
|
||||
|
||||
module.exports = {Connection, Session};
|
||||
module.exports = {Connection, CDPSession};
|
||||
|
@ -25,7 +25,7 @@ const {helper, debugError} = require('./helper');
|
||||
|
||||
class Coverage {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
*/
|
||||
constructor(client) {
|
||||
this._jsCoverage = new JSCoverage(client);
|
||||
@ -66,7 +66,7 @@ helper.tracePublicAPI(Coverage);
|
||||
|
||||
class JSCoverage {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
*/
|
||||
constructor(client) {
|
||||
this._client = client;
|
||||
@ -154,7 +154,7 @@ class JSCoverage {
|
||||
|
||||
class CSSCoverage {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
*/
|
||||
constructor(client) {
|
||||
this._client = client;
|
||||
|
@ -18,7 +18,7 @@ const {helper} = require('./helper');
|
||||
|
||||
class Dialog {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {string} type
|
||||
* @param {string} message
|
||||
* @param {(string|undefined)} defaultValue
|
||||
|
@ -20,7 +20,7 @@ const {helper, debugError} = require('./helper');
|
||||
class ElementHandle extends JSHandle {
|
||||
/**
|
||||
* @param {!Puppeteer.ExecutionContext} context
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Object} remoteObject
|
||||
* @param {!Puppeteer.Page} page
|
||||
*/
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
class EmulationManager {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
*/
|
||||
constructor(client) {
|
||||
this._client = client;
|
||||
|
@ -18,7 +18,7 @@ const {helper} = require('./helper');
|
||||
|
||||
class ExecutionContext {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Object} contextPayload
|
||||
* @param {function(*):!JSHandle} objectHandleFactory
|
||||
*/
|
||||
@ -117,7 +117,7 @@ class ExecutionContext {
|
||||
class JSHandle {
|
||||
/**
|
||||
* @param {!ExecutionContext} context
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Object} remoteObject
|
||||
*/
|
||||
constructor(context, client, remoteObject) {
|
||||
|
@ -24,7 +24,7 @@ const readFileAsync = helper.promisify(fs.readFile);
|
||||
|
||||
class FrameManager extends EventEmitter {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {{frame: Object, childFrames: ?Array}} frameTree
|
||||
* @param {!Puppeteer.Page} page
|
||||
*/
|
||||
@ -226,7 +226,7 @@ FrameManager.Events = {
|
||||
*/
|
||||
class Frame {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {?Frame} parentFrame
|
||||
* @param {string} frameId
|
||||
*/
|
||||
|
@ -28,7 +28,7 @@ const keyDefinitions = require('./USKeyboardLayout');
|
||||
|
||||
class Keyboard {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
*/
|
||||
constructor(client) {
|
||||
this._client = client;
|
||||
@ -189,7 +189,7 @@ class Keyboard {
|
||||
|
||||
class Mouse {
|
||||
/**
|
||||
* @param {Puppeteer.Session} client
|
||||
* @param {Puppeteer.CDPSession} client
|
||||
* @param {!Keyboard} keyboard
|
||||
*/
|
||||
constructor(client, keyboard) {
|
||||
@ -268,7 +268,7 @@ class Mouse {
|
||||
|
||||
class Touchscreen {
|
||||
/**
|
||||
* @param {Puppeteer.Session} client
|
||||
* @param {Puppeteer.CDPSession} client
|
||||
* @param {Keyboard} keyboard
|
||||
*/
|
||||
constructor(client, keyboard) {
|
||||
|
@ -19,7 +19,7 @@ const Multimap = require('./Multimap');
|
||||
|
||||
class NetworkManager extends EventEmitter {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Puppeteer.FrameManager} frameManager
|
||||
*/
|
||||
constructor(client, frameManager) {
|
||||
@ -281,7 +281,7 @@ class NetworkManager extends EventEmitter {
|
||||
|
||||
class Request {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {?string} requestId
|
||||
* @param {string} interceptionId
|
||||
* @param {boolean} allowInterception
|
||||
@ -479,7 +479,7 @@ helper.tracePublicAPI(Request);
|
||||
|
||||
class Response {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Request} request
|
||||
* @param {number} status
|
||||
* @param {!Object} headers
|
||||
|
27
lib/Page.js
27
lib/Page.js
@ -31,17 +31,18 @@ const writeFileAsync = helper.promisify(fs.writeFile);
|
||||
|
||||
class Page extends EventEmitter {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Puppeteer.Target} target
|
||||
* @param {boolean} ignoreHTTPSErrors
|
||||
* @param {boolean} appMode
|
||||
* @param {!Puppeteer.TaskQueue} screenshotTaskQueue
|
||||
* @return {!Promise<!Page>}
|
||||
*/
|
||||
static async create(client, ignoreHTTPSErrors, appMode, screenshotTaskQueue) {
|
||||
static async create(client, target, ignoreHTTPSErrors, appMode, screenshotTaskQueue) {
|
||||
|
||||
await client.send('Page.enable');
|
||||
const {frameTree} = await client.send('Page.getFrameTree');
|
||||
const page = new Page(client, frameTree, ignoreHTTPSErrors, screenshotTaskQueue);
|
||||
const page = new Page(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue);
|
||||
|
||||
await Promise.all([
|
||||
client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
|
||||
@ -60,14 +61,16 @@ class Page extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Puppeteer.Target} target
|
||||
* @param {{frame: Object, childFrames: ?Array}} frameTree
|
||||
* @param {boolean} ignoreHTTPSErrors
|
||||
* @param {!Puppeteer.TaskQueue} screenshotTaskQueue
|
||||
*/
|
||||
constructor(client, frameTree, ignoreHTTPSErrors, screenshotTaskQueue) {
|
||||
constructor(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue) {
|
||||
super();
|
||||
this._client = client;
|
||||
this._target = target;
|
||||
this._keyboard = new Keyboard(client);
|
||||
this._mouse = new Mouse(client, this._keyboard);
|
||||
this._touchscreen = new Touchscreen(client, this._keyboard);
|
||||
@ -101,6 +104,13 @@ class Page extends EventEmitter {
|
||||
client.on('Performance.metrics', event => this._emitMetrics(event));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!Puppeteer.Target}
|
||||
*/
|
||||
target() {
|
||||
return this._target;
|
||||
}
|
||||
|
||||
_onTargetCrashed() {
|
||||
this.emit('error', new Error('Page crashed!'));
|
||||
}
|
||||
@ -505,7 +515,7 @@ class Page extends EventEmitter {
|
||||
return request ? request.response() : null;
|
||||
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {string} url
|
||||
* @param {string} referrer
|
||||
* @return {!Promise<?Error>}
|
||||
@ -691,7 +701,7 @@ class Page extends EventEmitter {
|
||||
* @return {!Promise<!Buffer>}
|
||||
*/
|
||||
async _screenshotTask(format, options) {
|
||||
await this._client.send('Target.activateTarget', {targetId: this._client.targetId()});
|
||||
await this._client.send('Target.activateTarget', {targetId: this._target._targetId});
|
||||
let clip = options.clip ? Object.assign({}, options['clip']) : undefined;
|
||||
if (clip)
|
||||
clip.scale = 1;
|
||||
@ -785,7 +795,8 @@ class Page extends EventEmitter {
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this._client.dispose();
|
||||
console.assert(!!this._client._connection, 'Protocol error: Connection closed. Most likely the page has been closed.');
|
||||
await this._client._connection.send('Target.closeTarget', {targetId: this._target._targetId});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@ const closeAsync = helper.promisify(fs.close);
|
||||
|
||||
class Tracing {
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
*/
|
||||
constructor(client) {
|
||||
this._client = client;
|
||||
|
7
lib/externs.d.ts
vendored
7
lib/externs.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import { Connection as RealConnection, Session as RealSession } from './Connection.js';
|
||||
import {Browser as RealBrowser, TaskQueue as RealTaskQueue} from './Browser.js';
|
||||
import { Connection as RealConnection, CDPSession as RealCDPSession } from './Connection.js';
|
||||
import {Browser as RealBrowser, TaskQueue as RealTaskQueue, Target as RealTarget} from './Browser.js';
|
||||
import * as RealPage from './Page.js';
|
||||
import {Mouse as RealMouse, Keyboard as RealKeyboard, Touchscreen as RealTouchscreen} from './Input.js';
|
||||
import {Frame as RealFrame, FrameManager as RealFrameManager} from './FrameManager.js';
|
||||
@ -10,12 +10,13 @@ import * as child_process from 'child_process';
|
||||
export as namespace Puppeteer;
|
||||
|
||||
export class Connection extends RealConnection {}
|
||||
export class Session extends RealSession {}
|
||||
export class CDPSession extends RealCDPSession {}
|
||||
export class Mouse extends RealMouse {}
|
||||
export class Keyboard extends RealKeyboard {}
|
||||
export class Touchscreen extends RealTouchscreen {}
|
||||
export class TaskQueue extends RealTaskQueue {}
|
||||
export class Browser extends RealBrowser {}
|
||||
export class Target extends RealTarget {}
|
||||
export class Frame extends RealFrame {}
|
||||
export class FrameManager extends RealFrameManager {}
|
||||
export class NetworkManager extends RealNetworkManager {}
|
||||
|
@ -83,7 +83,7 @@ class Helper {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Puppeteer.Session} client
|
||||
* @param {!Puppeteer.CDPSession} client
|
||||
* @param {!Object} remoteObject
|
||||
*/
|
||||
static async releaseObject(client, remoteObject) {
|
||||
|
56
test/test.js
56
test/test.js
@ -3474,6 +3474,56 @@ describe('Page', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Target.createCDPSession', function() {
|
||||
it('should work', async function({page, server}) {
|
||||
const client = await page.target().createCDPSession();
|
||||
|
||||
await Promise.all([
|
||||
client.send('Runtime.enable'),
|
||||
client.send('Runtime.evaluate', { expression: 'window.foo = "bar"' })
|
||||
]);
|
||||
const foo = await page.evaluate(() => window.foo);
|
||||
expect(foo).toBe('bar');
|
||||
});
|
||||
it('should send events', async function({page, server}) {
|
||||
const client = await page.target().createCDPSession();
|
||||
await client.send('Network.enable');
|
||||
const events = [];
|
||||
client.on('Network.requestWillBeSent', event => events.push(event));
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
expect(events.length).toBe(1);
|
||||
});
|
||||
it('should enable and disable domains independently', async function({page, server}) {
|
||||
const client = await page.target().createCDPSession();
|
||||
await client.send('Runtime.enable');
|
||||
await client.send('Debugger.enable');
|
||||
// JS coverage enables and then disables Debugger domain.
|
||||
await page.coverage.startJSCoverage();
|
||||
await page.coverage.stopJSCoverage();
|
||||
// generate a script in page and wait for the event.
|
||||
const [event] = await Promise.all([
|
||||
waitForEvents(client, 'Debugger.scriptParsed'),
|
||||
page.evaluate('//# sourceURL=foo.js')
|
||||
]);
|
||||
// expect events to be dispatched.
|
||||
expect(event.url).toBe('foo.js');
|
||||
});
|
||||
it('should be able to detach session', async function({page, server}) {
|
||||
const client = await page.target().createCDPSession();
|
||||
await client.send('Runtime.enable');
|
||||
const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true});
|
||||
expect(evalResponse.result.value).toBe(3);
|
||||
await client.detach();
|
||||
let error = null;
|
||||
try {
|
||||
await client.send('Runtime.evaluate', {expression: '3 + 1', returnByValue: true});
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
expect(error.message).toContain('Session closed.');
|
||||
});
|
||||
});
|
||||
|
||||
describe('JSCoverage', function() {
|
||||
it('should work', async function({page, server}) {
|
||||
await page.coverage.startJSCoverage();
|
||||
@ -3656,7 +3706,7 @@ runner.run();
|
||||
* @param {!EventEmitter} emitter
|
||||
* @param {string} eventName
|
||||
* @param {number=} eventCount
|
||||
* @return {!Promise}
|
||||
* @return {!Promise<!Object>}
|
||||
*/
|
||||
function waitForEvents(emitter, eventName, eventCount = 1) {
|
||||
let fulfill;
|
||||
@ -3664,12 +3714,12 @@ function waitForEvents(emitter, eventName, eventCount = 1) {
|
||||
emitter.on(eventName, onEvent);
|
||||
return promise;
|
||||
|
||||
function onEvent() {
|
||||
function onEvent(event) {
|
||||
--eventCount;
|
||||
if (eventCount)
|
||||
return;
|
||||
emitter.removeListener(eventName, onEvent);
|
||||
fulfill();
|
||||
fulfill(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@ const EXCLUDE_CLASSES = new Set([
|
||||
'Multimap',
|
||||
'NavigatorWatcher',
|
||||
'NetworkManager',
|
||||
'Session',
|
||||
'TaskQueue',
|
||||
'WaitTask',
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user