feat(worker): report workers network activity (#545)
This commit is contained in:
parent
c3e4f092d3
commit
ddf47bc291
|
|
@ -20,10 +20,10 @@ import * as js from '../javascript';
|
||||||
import * as frames from '../frames';
|
import * as frames from '../frames';
|
||||||
import { debugError, helper, RegisteredListener } from '../helper';
|
import { debugError, helper, RegisteredListener } from '../helper';
|
||||||
import * as network from '../network';
|
import * as network from '../network';
|
||||||
import { CRSession } from './crConnection';
|
import { CRSession, CRConnection } from './crConnection';
|
||||||
import { EVALUATION_SCRIPT_URL, CRExecutionContext } from './crExecutionContext';
|
import { EVALUATION_SCRIPT_URL, CRExecutionContext } from './crExecutionContext';
|
||||||
import { CRNetworkManager } from './crNetworkManager';
|
import { CRNetworkManager } from './crNetworkManager';
|
||||||
import { Page, Coverage } from '../page';
|
import { Page, Coverage, Worker } from '../page';
|
||||||
import { Protocol } from './protocol';
|
import { Protocol } from './protocol';
|
||||||
import { Events } from '../events';
|
import { Events } from '../events';
|
||||||
import { toConsoleMessageLocation, exceptionToError, releaseObject } from './crProtocolHelper';
|
import { toConsoleMessageLocation, exceptionToError, releaseObject } from './crProtocolHelper';
|
||||||
|
|
@ -33,7 +33,6 @@ import { RawMouseImpl, RawKeyboardImpl } from './crInput';
|
||||||
import { getAccessibilityTree } from './crAccessibility';
|
import { getAccessibilityTree } from './crAccessibility';
|
||||||
import { CRCoverage } from './crCoverage';
|
import { CRCoverage } from './crCoverage';
|
||||||
import { CRPDF } from './crPdf';
|
import { CRPDF } from './crPdf';
|
||||||
import { CRWorkers } from './crWorkers';
|
|
||||||
import { CRBrowser } from './crBrowser';
|
import { CRBrowser } from './crBrowser';
|
||||||
import { BrowserContext } from '../browserContext';
|
import { BrowserContext } from '../browserContext';
|
||||||
import * as types from '../types';
|
import * as types from '../types';
|
||||||
|
|
@ -46,7 +45,6 @@ export class CRPage implements PageDelegate {
|
||||||
_client: CRSession;
|
_client: CRSession;
|
||||||
private readonly _page: Page;
|
private readonly _page: Page;
|
||||||
readonly _networkManager: CRNetworkManager;
|
readonly _networkManager: CRNetworkManager;
|
||||||
private _workers: CRWorkers;
|
|
||||||
private _contextIdToContext = new Map<number, dom.FrameExecutionContext>();
|
private _contextIdToContext = new Map<number, dom.FrameExecutionContext>();
|
||||||
private _isolatedWorlds = new Set<string>();
|
private _isolatedWorlds = new Set<string>();
|
||||||
private _eventListeners: RegisteredListener[];
|
private _eventListeners: RegisteredListener[];
|
||||||
|
|
@ -65,7 +63,6 @@ export class CRPage implements PageDelegate {
|
||||||
this._coverage = new CRCoverage(client);
|
this._coverage = new CRCoverage(client);
|
||||||
this._page = new Page(this, browserContext);
|
this._page = new Page(this, browserContext);
|
||||||
this._networkManager = new CRNetworkManager(client, this._page);
|
this._networkManager = new CRNetworkManager(client, this._page);
|
||||||
this._workers = new CRWorkers(client, this._page);
|
|
||||||
|
|
||||||
this._eventListeners = [
|
this._eventListeners = [
|
||||||
helper.addEventListener(client, 'Inspector.targetCrashed', event => this._onTargetCrashed()),
|
helper.addEventListener(client, 'Inspector.targetCrashed', event => this._onTargetCrashed()),
|
||||||
|
|
@ -84,6 +81,8 @@ export class CRPage implements PageDelegate {
|
||||||
helper.addEventListener(client, 'Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context)),
|
helper.addEventListener(client, 'Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context)),
|
||||||
helper.addEventListener(client, 'Runtime.executionContextDestroyed', event => this._onExecutionContextDestroyed(event.executionContextId)),
|
helper.addEventListener(client, 'Runtime.executionContextDestroyed', event => this._onExecutionContextDestroyed(event.executionContextId)),
|
||||||
helper.addEventListener(client, 'Runtime.executionContextsCleared', event => this._onExecutionContextsCleared()),
|
helper.addEventListener(client, 'Runtime.executionContextsCleared', event => this._onExecutionContextsCleared()),
|
||||||
|
helper.addEventListener(client, 'Target.attachedToTarget', event => this._onAttachedToTarget(event)),
|
||||||
|
helper.addEventListener(client, 'Target.detachedFromTarget', event => this._onDetachedFromTarget(event)),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,6 +222,37 @@ export class CRPage implements PageDelegate {
|
||||||
this._onExecutionContextDestroyed(contextId);
|
this._onExecutionContextDestroyed(contextId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onAttachedToTarget(event: Protocol.Target.attachedToTargetPayload) {
|
||||||
|
if (event.targetInfo.type !== 'worker')
|
||||||
|
return;
|
||||||
|
const url = event.targetInfo.url;
|
||||||
|
const session = CRConnection.fromSession(this._client).session(event.sessionId)!;
|
||||||
|
const worker = new Worker(url);
|
||||||
|
this._page._addWorker(event.sessionId, worker);
|
||||||
|
session.once('Runtime.executionContextCreated', async event => {
|
||||||
|
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
||||||
|
});
|
||||||
|
Promise.all([
|
||||||
|
session.send('Runtime.enable'),
|
||||||
|
session.send('Network.enable'),
|
||||||
|
]).catch(debugError); // This might fail if the target is closed before we initialize.
|
||||||
|
session.on('Runtime.consoleAPICalled', event => {
|
||||||
|
const args = event.args.map(o => worker._existingExecutionContext!._createHandle(o));
|
||||||
|
this._page._addConsoleMessage(event.type, args, toConsoleMessageLocation(event.stackTrace));
|
||||||
|
});
|
||||||
|
session.on('Runtime.exceptionThrown', exception => this._page.emit(Events.Page.PageError, exceptionToError(exception.exceptionDetails)));
|
||||||
|
session.on('Fetch.requestPaused', event => this._networkManager._onRequestPaused(event));
|
||||||
|
session.on('Fetch.authRequired', event => this._networkManager._onAuthRequired(event));
|
||||||
|
session.on('Network.requestWillBeSent', event => this._networkManager._onRequestWillBeSent(event));
|
||||||
|
session.on('Network.responseReceived', event => this._networkManager._onResponseReceived(event));
|
||||||
|
session.on('Network.loadingFinished', event => this._networkManager._onLoadingFinished(event));
|
||||||
|
session.on('Network.loadingFailed', event => this._networkManager._onLoadingFailed(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDetachedFromTarget(event: Protocol.Target.detachedFromTargetPayload) {
|
||||||
|
this._page._removeWorker(event.sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
async _onConsoleAPI(event: Protocol.Runtime.consoleAPICalledPayload) {
|
async _onConsoleAPI(event: Protocol.Runtime.consoleAPICalledPayload) {
|
||||||
if (event.executionContextId === 0) {
|
if (event.executionContextId === 0) {
|
||||||
// DevTools protocol stores the last 1000 console messages. These
|
// DevTools protocol stores the last 1000 console messages. These
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2018 Google Inc. All rights reserved.
|
|
||||||
* Modifications copyright (c) Microsoft Corporation.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Events } from '../events';
|
|
||||||
import { debugError } from '../helper';
|
|
||||||
import { Page, Worker } from '../page';
|
|
||||||
import { CRConnection, CRSession } from './crConnection';
|
|
||||||
import { CRExecutionContext } from './crExecutionContext';
|
|
||||||
import { exceptionToError, toConsoleMessageLocation } from './crProtocolHelper';
|
|
||||||
|
|
||||||
export class CRWorkers {
|
|
||||||
constructor(client: CRSession, page: Page) {
|
|
||||||
client.on('Target.attachedToTarget', event => {
|
|
||||||
if (event.targetInfo.type !== 'worker')
|
|
||||||
return;
|
|
||||||
const url = event.targetInfo.url;
|
|
||||||
const session = CRConnection.fromSession(client).session(event.sessionId)!;
|
|
||||||
const worker = new Worker(url);
|
|
||||||
page._addWorker(event.sessionId, worker);
|
|
||||||
session.once('Runtime.executionContextCreated', async event => {
|
|
||||||
worker._createExecutionContext(new CRExecutionContext(session, event.context));
|
|
||||||
});
|
|
||||||
// This might fail if the target is closed before we recieve all execution contexts.
|
|
||||||
session.send('Runtime.enable', {}).catch(debugError);
|
|
||||||
session.on('Runtime.consoleAPICalled', event => page._addConsoleMessage(event.type, event.args.map(o => worker._existingExecutionContext!._createHandle(o)), toConsoleMessageLocation(event.stackTrace)));
|
|
||||||
session.on('Runtime.exceptionThrown', exception => page.emit(Events.Page.PageError, exceptionToError(exception.exceptionDetails)));
|
|
||||||
});
|
|
||||||
client.on('Target.detachedFromTarget', event => page._removeWorker(event.sessionId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -83,5 +83,35 @@ module.exports.describe = function({testRunner, expect, FFOX, CHROMIUM, WEBKIT})
|
||||||
await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
|
await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
|
||||||
expect(page.workers().length).toBe(0);
|
expect(page.workers().length).toBe(0);
|
||||||
});
|
});
|
||||||
|
it('should report network activity', async function({page, server}) {
|
||||||
|
const [worker] = await Promise.all([
|
||||||
|
page.waitForEvent('workercreated'),
|
||||||
|
page.goto(server.PREFIX + '/worker/worker.html'),
|
||||||
|
]);
|
||||||
|
const url = server.PREFIX + '/one-style.css';
|
||||||
|
const requestPromise = page.waitForRequest(url);
|
||||||
|
const responsePromise = page.waitForResponse(url);
|
||||||
|
await worker.evaluate(url => fetch(url).then(response => response.text()).then(console.log), url);
|
||||||
|
const request = await requestPromise;
|
||||||
|
const response = await responsePromise;
|
||||||
|
expect(request.url()).toBe(url);
|
||||||
|
expect(response.request()).toBe(request);
|
||||||
|
expect(response.ok()).toBe(true);
|
||||||
|
});
|
||||||
|
it.skip(CHROMIUM)('should report network activity on worker creation', async function({page, server}) {
|
||||||
|
// Chromium needs waitForDebugger enabled for this one.
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
const url = server.PREFIX + '/one-style.css';
|
||||||
|
const requestPromise = page.waitForRequest(url);
|
||||||
|
const responsePromise = page.waitForResponse(url);
|
||||||
|
await page.evaluate(url => new Worker(URL.createObjectURL(new Blob([`
|
||||||
|
fetch("${url}").then(response => response.text()).then(console.log);
|
||||||
|
`], {type: 'application/javascript'}))), url);
|
||||||
|
const request = await requestPromise;
|
||||||
|
const response = await responsePromise;
|
||||||
|
expect(request.url()).toBe(url);
|
||||||
|
expect(response.request()).toBe(request);
|
||||||
|
expect(response.ok()).toBe(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue