always construct networkRecords from devtoolsLog (#2133)

simplify devtoolsLog recording, url redirect tracking, and eliminate explicit network recording
This commit is contained in:
Brendan Kenny 2017-05-04 21:35:04 -07:00 коммит произвёл Paul Irish
Родитель 75d8f4d1f1
Коммит d7e4d1bb09
10 изменённых файлов: 402 добавлений и 210 удалений

Просмотреть файл

@ -44,13 +44,28 @@ class Driver {
this._connection = connection;
// currently only used by WPT where just Page and Network are needed
this._devtoolsLog = new DevtoolsLog(/^(Page|Network)\./);
connection.on('notification', event => {
this._devtoolsLog.record(event);
this.recordNetworkEvent(event.method, event.params);
this._eventEmitter.emit(event.method, event.params);
});
this.online = true;
this._domainEnabledCounts = new Map();
/**
* Used for monitoring network status events during gotoURL.
* @private {?NetworkRecorder}
*/
this._networkStatusMonitor = null;
/**
* Used for monitoring url redirects during gotoURL.
* @private {?string}
*/
this._monitoredUrl = null;
connection.on('notification', event => {
this._devtoolsLog.record(event);
if (this._networkStatusMonitor) {
this._networkStatusMonitor.dispatch(event.method, event.params);
}
this._eventEmitter.emit(event.method, event.params);
});
}
static get traceCategories() {
@ -73,13 +88,6 @@ class Driver {
];
}
/**
* @return {!Array<{method: string, params: !Object}>}
*/
get devtoolsLog() {
return this._devtoolsLog.messages;
}
/**
* @return {!Promise<string>}
*/
@ -346,25 +354,6 @@ class Driver {
});
}
/**
* If our main document URL redirects, we will update options.url accordingly
* As such, options.url will always represent the post-redirected URL.
* options.initialUrl is the pre-redirect URL that things started with
* @param {!Object} opts
*/
enableUrlUpdateIfRedirected(opts) {
this._networkRecorder.on('requestloaded', redirectRequest => {
// Quit if this is not a redirected request
if (!redirectRequest.redirectSource) {
return;
}
const earlierRequest = redirectRequest.redirectSource;
if (earlierRequest.url === opts.url) {
opts.url = redirectRequest.url;
}
});
}
/**
* Returns a promise that resolves when the network has been idle for
* `pauseAfterLoadMs` ms and a method to cancel internal network listeners and
@ -380,7 +369,7 @@ class Driver {
const promise = new Promise((resolve, reject) => {
const onIdle = () => {
// eslint-disable-next-line no-use-before-define
this._networkRecorder.once('networkbusy', onBusy);
this._networkStatusMonitor.once('networkbusy', onBusy);
idleTimeout = setTimeout(_ => {
cancel();
resolve();
@ -388,17 +377,17 @@ class Driver {
};
const onBusy = () => {
this._networkRecorder.once('networkidle', onIdle);
this._networkStatusMonitor.once('networkidle', onIdle);
clearTimeout(idleTimeout);
};
cancel = () => {
clearTimeout(idleTimeout);
this._networkRecorder.removeListener('networkbusy', onBusy);
this._networkRecorder.removeListener('networkidle', onIdle);
this._networkStatusMonitor.removeListener('networkbusy', onBusy);
this._networkStatusMonitor.removeListener('networkidle', onIdle);
};
if (this._networkRecorder.isIdle()) {
if (this._networkStatusMonitor.isIdle()) {
onIdle();
} else {
onBusy();
@ -490,14 +479,55 @@ class Driver {
}
/**
* Navigate to the given URL. Use of this method directly isn't advised: if
* Set up listener for network quiet events and URL redirects. Passed in URL
* will be monitored for redirects, with the final loaded URL passed back in
* _endNetworkStatusMonitoring.
* @param {string} startingUrl
* @return {!Promise}
* @private
*/
_beginNetworkStatusMonitoring(startingUrl) {
this._networkStatusMonitor = new NetworkRecorder([]);
// Update startingUrl if it's ever redirected.
this._monitoredUrl = startingUrl;
this._networkStatusMonitor.on('requestloaded', redirectRequest => {
// Ignore if this is not a redirected request.
if (!redirectRequest.redirectSource) {
return;
}
const earlierRequest = redirectRequest.redirectSource;
if (earlierRequest.url === this._monitoredUrl) {
this._monitoredUrl = redirectRequest.url;
}
});
return this.sendCommand('Network.enable');
}
/**
* End network status listening. Returns the final, possibly redirected,
* loaded URL starting with the one passed into _endNetworkStatusMonitoring.
* @return {string}
* @private
*/
_endNetworkStatusMonitoring() {
this._networkStatusMonitor = null;
const finalUrl = this._monitoredUrl;
this._monitoredUrl = null;
return finalUrl;
}
/**
* Navigate to the given URL. Direct use of this method isn't advised: if
* the current page is already at the given URL, navigation will not occur and
* so the returned promise will only resolve after the MAX_WAIT_FOR_FULLY_LOADED
* timeout. See https://github.com/GoogleChrome/lighthouse/pull/185 for one
* possible workaround.
* Resolves on the url of the loaded page, taking into account any redirects.
* @param {string} url
* @param {!Object} options
* @return {!Promise}
* @return {!Promise<string>}
*/
gotoURL(url, options = {}) {
const waitForLoad = options.waitForLoad || false;
@ -506,16 +536,18 @@ class Driver {
const maxWaitMs = (options.flags && options.flags.maxWaitForLoad) ||
Driver.MAX_WAIT_FOR_FULLY_LOADED;
return this.sendCommand('Page.enable')
return this._beginNetworkStatusMonitoring(url)
.then(_ => this.sendCommand('Page.enable'))
.then(_ => this.sendCommand('Emulation.setScriptExecutionDisabled', {value: disableJS}))
.then(_ => this.sendCommand('Page.navigate', {url}))
.then(_ => waitForLoad && this._waitForFullyLoaded(pauseAfterLoadMs, maxWaitMs));
.then(_ => waitForLoad && this._waitForFullyLoaded(pauseAfterLoadMs, maxWaitMs))
.then(_ => this._endNetworkStatusMonitoring());
}
/**
* @param {string} objectId Object ID for the resolved DOM node
* @param {string} propName Name of the property
* @return {!Promise<string>} The property value, or null, if property not found
* @param {string} objectId Object ID for the resolved DOM node
* @param {string} propName Name of the property
* @return {!Promise<string>} The property value, or null, if property not found
*/
getObjectProperty(objectId, propName) {
return new Promise((resolve, reject) => {
@ -538,6 +570,18 @@ class Driver {
});
}
/**
* Return the body of the response with the given ID.
* @param {string} requestId
* @return {string}
*/
getRequestContent(requestId) {
return this.sendCommand('Network.getResponseBody', {
requestId,
// Ignoring result.base64Encoded, which indicates if body is already encoded
}).then(result => result.body);
}
/**
* @param {string} name The name of API whose permission you wish to query
* @return {!Promise<string>} The state of permissions, resolved in a promise.
@ -618,9 +662,6 @@ class Driver {
throw new Error('DOM domain enabled when starting trace');
}
this._devtoolsLog.reset();
this._devtoolsLog.beginRecording();
// Enable Page domain to wait for Page.loadEventFired
return this.sendCommand('Page.enable')
.then(_ => this.sendCommand('Tracing.start', tracingOpts));
@ -633,7 +674,6 @@ class Driver {
return new Promise((resolve, reject) => {
// When the tracing has ended this will fire with a stream handle.
this.once('Tracing.tracingComplete', streamHandle => {
this._devtoolsLog.endRecording();
this._readTraceFromStream(streamHandle)
.then(traceContents => resolve(traceContents), reject);
});
@ -672,34 +712,21 @@ class Driver {
});
}
beginNetworkCollect(opts) {
return new Promise((resolve, reject) => {
this._networkRecords = [];
this._networkRecorder = new NetworkRecorder(this._networkRecords, this);
this.enableUrlUpdateIfRedirected(opts);
this.sendCommand('Network.enable').then(resolve, reject);
});
/**
* Begin recording devtools protocol messages.
*/
beginDevtoolsLog() {
this._devtoolsLog.reset();
this._devtoolsLog.beginRecording();
}
/**
* @param {!string} method
* @param {!Object<string, *>=} params
* Stop recording to devtoolsLog and return log contents.
* @return {!Array<{method: string, params: (!Object<string, *>|undefined)}>}
*/
recordNetworkEvent(method, params) {
if (!this._networkRecorder) return;
const regexFilter = /^Network\./;
if (!regexFilter.test(method)) return;
this._networkRecorder.dispatch(method, params);
}
endNetworkCollect() {
return new Promise((resolve, reject) => {
resolve(this._networkRecords);
this._networkRecorder = null;
this._networkRecords = [];
});
endDevtoolsLog() {
this._devtoolsLog.endRecording();
return this._devtoolsLog.messages;
}
enableRuntimeEvents() {

Просмотреть файл

@ -19,6 +19,7 @@
const log = require('../lib/log.js');
const Audit = require('../audits/audit');
const URL = require('../lib/url-shim');
const NetworkRecorder = require('../lib/network-recorder.js');
/**
* @typedef {!Object<string, !Array<!Promise<*>>>}
@ -44,15 +45,15 @@ let GathererResults; // eslint-disable-line no-unused-vars
* 2. For each pass in the config:
* A. GatherRunner.beforePass()
* i. navigate to about:blank
* ii. all gatherer's beforePass()
* ii. all gatherers' beforePass()
* B. GatherRunner.pass()
* i. GatherRunner.loadPage()
* b. beginTrace (if requested) & beginNetworkCollect
* c. navigate to options.url (and wait for onload)
* ii. all gatherer's pass()
* i. beginTrace (if requested) & beginDevtoolsLog
* ii. GatherRunner.loadPage()
* a. navigate to options.url (and wait for onload)
* iii. all gatherers' pass()
* C. GatherRunner.afterPass()
* i. endTrace (if requested) & endNetworkCollect & endThrottling
* ii. all gatherer's afterPass()
* i. endTrace (if requested) & endDevtoolsLog & endThrottling
* ii. all gatherers' afterPass()
*
* 3. Teardown
* A. GatherRunner.disposeDriver()
@ -76,23 +77,22 @@ class GatherRunner {
}
/**
* Loads options.url with specified options.
* Loads options.url with specified options. If the main document URL
* redirects, options.url will be updated accordingly. As such, options.url
* will always represent the post-redirected URL. options.initialUrl is the
* pre-redirect starting URL.
* @param {!Driver} driver
* @param {!Object} options
* @return {!Promise}
*/
static loadPage(driver, options) {
return Promise.resolve()
// Begin tracing only if requested by config.
.then(_ => options.config.recordTrace && driver.beginTrace(options.flags))
// Network is always recorded for internal use, even if not saved as artifact.
.then(_ => driver.beginNetworkCollect(options))
// Navigate.
.then(_ => driver.gotoURL(options.url, {
waitForLoad: true,
disableJavaScript: !!options.disableJavaScript,
flags: options.flags,
}));
return driver.gotoURL(options.url, {
waitForLoad: true,
disableJavaScript: !!options.disableJavaScript,
flags: options.flags,
}).then(finalUrl => {
options.url = finalUrl;
});
}
/**
@ -199,9 +199,15 @@ class GatherRunner {
const status = 'Loading page & waiting for onload';
log.log('status', status, gatherernames);
const pass = GatherRunner.loadPage(driver, options).then(_ => {
log.log('statusEnd', status);
});
// Always record devtoolsLog.
driver.beginDevtoolsLog();
const pass = Promise.resolve()
// Begin tracing only if requested by config.
.then(_ => config.recordTrace && driver.beginTrace(options.flags))
// Navigate.
.then(_ => GatherRunner.loadPage(driver, options))
.then(_ => log.log('statusEnd', status));
return gatherers.reduce((chain, gatherer) => {
return chain.then(_ => {
@ -242,17 +248,17 @@ class GatherRunner {
});
}
const status = 'Retrieving network records';
pass = pass.then(_ => {
passData.devtoolsLog = driver.devtoolsLog;
const status = 'Retrieving devtoolsLog and network records';
log.log('status', status);
return driver.endNetworkCollect();
}).then(networkRecords => {
const devtoolsLog = driver.endDevtoolsLog();
const networkRecords = NetworkRecorder.recordsFromLogs(devtoolsLog);
GatherRunner.assertPageLoaded(options.url, driver, networkRecords);
// expose devtoolsLog & networkRecords to gatherers
passData.devtoolsLog = driver.devtoolsLog;
passData.networkRecords = networkRecords;
log.verbose('statusEnd', status);
// Expose devtoolsLog and networkRecords to gatherers
passData.devtoolsLog = devtoolsLog;
passData.networkRecords = networkRecords;
});
// Disable throttling so the afterPass analysis isn't throttled
@ -351,9 +357,12 @@ class GatherRunner {
.then(_ => GatherRunner.pass(runOptions, gathererResults))
.then(_ => GatherRunner.afterPass(runOptions, gathererResults))
.then(passData => {
// If requested by config, merge trace and network data for this
// pass into tracingData.
const passName = config.passName || Audit.DEFAULT_PASS;
// networkRecords are discarded and not added onto artifacts.
tracingData.devtoolsLogs[passName] = passData.devtoolsLog;
// If requested by config, add trace to pass's tracingData
if (config.recordTrace) {
tracingData.traces[passName] = passData.trace;
}

Просмотреть файл

@ -47,7 +47,7 @@ class ResponseCompression extends Gatherer {
if (!isContentEncoded) {
unoptimizedResponses.push({
record: record,
requestId: record.requestId,
url: record.url,
mimeType: record.mimeType,
resourceSize: record.resourceSize,
@ -62,8 +62,9 @@ class ResponseCompression extends Gatherer {
const networkRecords = traceData.networkRecords;
const textRecords = ResponseCompression.filterUnoptimizedResponses(networkRecords);
const driver = options.driver;
return Promise.all(textRecords.map(record => {
return record.record.requestContent().then(content => {
return driver.getRequestContent(record.requestId).then(content => {
// if we don't have any content gzipSize is set to 0
if (!content) {
record.gzipSize = 0;

Просмотреть файл

@ -24,13 +24,12 @@ class NetworkRecorder extends EventEmitter {
/**
* Creates an instance of NetworkRecorder.
* @param {!Array} recordArray
* @param {!Driver=} driver
*/
constructor(recordArray, driver) {
constructor(recordArray) {
super();
this._records = recordArray;
this.networkManager = NetworkManager.createWithFakeTarget(driver);
this.networkManager = NetworkManager.createWithFakeTarget();
this.startedRequestCount = 0;
this.finishedRequestCount = 0;
@ -39,14 +38,6 @@ class NetworkRecorder extends EventEmitter {
this.onRequestStarted.bind(this));
this.networkManager.addEventListener(this.EventTypes.RequestFinished,
this.onRequestFinished.bind(this));
this.onRequestWillBeSent = this.onRequestWillBeSent.bind(this);
this.onRequestServedFromCache = this.onRequestServedFromCache.bind(this);
this.onResponseReceived = this.onResponseReceived.bind(this);
this.onDataReceived = this.onDataReceived.bind(this);
this.onLoadingFinished = this.onLoadingFinished.bind(this);
this.onLoadingFailed = this.onLoadingFailed.bind(this);
this.onResourceChangedPriority = this.onResourceChangedPriority.bind(this);
}
get EventTypes() {
@ -155,6 +146,10 @@ class NetworkRecorder extends EventEmitter {
* @param {!Object<string, *>=} params
*/
dispatch(method, params) {
if (!method.startsWith('Network.')) {
return;
}
switch (method) {
case 'Network.requestWillBeSent': return this.onRequestWillBeSent(params);
case 'Network.requestServedFromCache': return this.onRequestServedFromCache(params);
@ -169,14 +164,14 @@ class NetworkRecorder extends EventEmitter {
/**
* Construct network records from a log of devtools protocol messages.
* @param {!DevtoolsLog} log
* @param {!DevtoolsLog} devtoolsLog
* @return {!Array<!WebInspector.NetworkRequest>}
*/
static recordsFromLogs(log) {
static recordsFromLogs(devtoolsLog) {
const records = [];
const nr = new NetworkRecorder(records);
log.forEach(event => {
nr.dispatch(event.method, event.params);
devtoolsLog.forEach(message => {
nr.dispatch(message.method, message.params);
});
return records;
}

Просмотреть файл

@ -239,16 +239,12 @@ module.exports = (function() {
* Creates a new WebInspector NetworkManager using a mocked Target.
* @return {!WebInspector.NetworkManager}
*/
WebInspector.NetworkManager.createWithFakeTarget = function(driver) {
WebInspector.NetworkManager.createWithFakeTarget = function() {
// Mocked-up WebInspector Target for NetworkManager
const fakeNetworkAgent = {
enable() {},
getResponseBody(requestId, onComplete) {
driver.sendCommand('Network.getResponseBody', {
requestId,
})
.then(response => onComplete(null, response.body, response.base64Encoded))
.catch(err => onComplete(err));
getResponseBody() {
throw new Error('Use driver.getRequestContent() for network request content');
}
};
const fakeConsoleModel = {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -22,12 +22,14 @@ let sendCommandParams = [];
const Driver = require('../../gather/driver.js');
const Connection = require('../../gather/connections/connection.js');
const Element = require('../../lib/element.js');
const NetworkRecorder = require('../../lib/network-recorder');
const assert = require('assert');
const EventEmitter = require('events').EventEmitter;
const connection = new Connection();
const driverStub = new Driver(connection);
const redirectDevtoolsLog = require('../fixtures/wikipedia-redirect.devtoolslog.json');
function createOnceStub(events) {
return (eventName, cb) => {
if (events[eventName]) {
@ -89,20 +91,6 @@ connection.sendCommand = function(command, params) {
}
};
// mock redirects to test out enableUrlUpdateIfRedirected
const req1 = {
url: 'http://aliexpress.com/'
};
const req2 = {
redirectSource: req1,
url: 'http://www.aliexpress.com/'
};
const req3 = {
redirectSource: req2,
url: 'http://m.aliexpress.com/?tracelog=wwwhome2mobilesitehome'
};
const mockRedirects = [req1, req2, req3];
/* eslint-env mocha */
describe('Browser Driver', () => {
@ -153,20 +141,49 @@ describe('Browser Driver', () => {
});
});
it('will update the options.url through redirects', () => {
const networkRecorder = driverStub._networkRecorder = new NetworkRecorder([]);
const opts = {url: req1.url};
driverStub.enableUrlUpdateIfRedirected(opts);
it('will track redirects through gotoURL load', () => {
const delay = _ => new Promise(resolve => setTimeout(resolve));
// Fake some reqFinished events
const networkManager = networkRecorder.networkManager;
mockRedirects.forEach(request => {
networkManager.dispatchEventToListeners(networkRecorder.EventTypes.RequestFinished, request);
class ReplayConnection extends EventEmitter {
connect() {
return Promise.resolve();
}
disconnect() {
return Promise.resolve();
}
replayLog() {
redirectDevtoolsLog.forEach(msg => this.emit('notification', msg));
}
sendCommand(method) {
const resolve = Promise.resolve();
// If navigating, wait, then replay devtools log in parallel to resolve.
if (method === 'Page.navigate') {
resolve.then(delay).then(_ => this.replayLog());
}
return resolve;
}
}
const replayConnection = new ReplayConnection();
const driver = new Driver(replayConnection);
// Redirect in log will go through
const startUrl = 'http://en.wikipedia.org/';
// then https://en.wikipedia.org/
// then https://en.wikipedia.org/wiki/Main_Page
const finalUrl = 'https://en.m.wikipedia.org/wiki/Main_Page';
const loadOptions = {
waitForLoad: true,
flags: {
pauseAfterLoad: 1
}
};
return driver.gotoURL(startUrl, loadOptions).then(loadedUrl => {
assert.equal(loadedUrl, finalUrl);
});
// The above event is handled synchronously by enableUrlUpdateIfRedirected and will be all set
assert.notEqual(opts.url, req1.url, 'opts.url changed after the redirects');
assert.equal(opts.url, req3.url, 'opts.url matches the last redirect');
});
it('will request default traceCategories', () => {

Просмотреть файл

@ -16,8 +16,6 @@
'use strict';
const recordsFromLogs = require('../../lib/network-recorder').recordsFromLogs;
module.exports = {
getUserAgent() {
return Promise.resolve('Fake user agent');
@ -29,7 +27,7 @@ module.exports = {
return Promise.resolve();
},
gotoURL() {
return Promise.resolve();
return Promise.resolve('https://example.com');
},
beginEmulation() {
return Promise.resolve();
@ -62,13 +60,8 @@ module.exports = {
require('../fixtures/traces/progressive-app.json')
);
},
beginNetworkCollect() {},
endNetworkCollect() {
return Promise.resolve(
recordsFromLogs(require('../fixtures/perflog.json'))
);
},
get devtoolsLog() {
beginDevtoolsLog() {},
endDevtoolsLog() {
return require('../fixtures/perflog.json');
},
getSecurityState() {

Просмотреть файл

@ -23,7 +23,6 @@ const GatherRunner = require('../../gather/gather-runner');
const assert = require('assert');
const Config = require('../../config/config');
const path = require('path');
const recordsFromLogs = require('../../lib/network-recorder').recordsFromLogs;
const unresolvedPerfLog = require('./../fixtures/unresolved-perflog.json');
class TestGatherer extends Gatherer {
@ -92,21 +91,23 @@ function getMockedEmulationDriver(emulationFn, netThrottleFn, cpuThrottleFn, blo
}
describe('GatherRunner', function() {
it('loads a page', () => {
it('loads a page and updates URL on redirect', () => {
const url1 = 'https://example.com';
const url2 = 'https://example.com/interstitial';
const driver = {
gotoURL() {
return Promise.resolve(true);
return Promise.resolve(url2);
},
beginNetworkCollect() {
return Promise.resolve();
}
};
return GatherRunner.loadPage(driver, {
const options = {
url: url1,
flags: {},
config: {}
}).then(res => {
assert.equal(res, true);
};
return GatherRunner.loadPage(driver, options).then(_ => {
assert.equal(options.url, url2);
});
});
@ -328,20 +329,22 @@ describe('GatherRunner', function() {
calledTrace = true;
return Promise.resolve();
},
beginDevtoolsLog() {
return Promise.resolve();
},
gotoURL() {
return Promise.resolve();
},
beginNetworkCollect() {
return Promise.resolve();
}
};
const config = {
recordTrace: true,
gatherers: [{}]
gatherers: [
new TestGatherer()
]
};
return GatherRunner.loadPage(driver, {config}).then(_ => {
return GatherRunner.pass({driver, config}, {TestGatherer: []}).then(_ => {
assert.equal(calledTrace, true);
});
});
@ -371,11 +374,11 @@ describe('GatherRunner', function() {
});
});
it('tells the driver to begin network collection', () => {
let calledNetworkCollect = false;
it('tells the driver to begin devtoolsLog collection', () => {
let calledDevtoolsLogCollect = false;
const driver = {
beginNetworkCollect() {
calledNetworkCollect = true;
beginDevtoolsLog() {
calledDevtoolsLogCollect = true;
return Promise.resolve();
},
gotoURL() {
@ -384,26 +387,27 @@ describe('GatherRunner', function() {
};
const config = {
gatherers: [{}]
gatherers: [
new TestGatherer()
]
};
return GatherRunner.loadPage(driver, {config}).then(_ => {
assert.equal(calledNetworkCollect, true);
return GatherRunner.pass({driver, config}, {TestGatherer: []}).then(_ => {
assert.equal(calledDevtoolsLogCollect, true);
});
});
it('tells the driver to end network collection', () => {
it('tells the driver to end devtoolsLog collection', () => {
const url = 'https://example.com';
let calledNetworkCollect = false;
let calledDevtoolsLogCollect = false;
const fakeDevtoolsMessage = {method: 'Network.FakeThing', params: {}};
const driver = Object.assign({}, fakeDriver, {
endNetworkCollect() {
calledNetworkCollect = true;
return fakeDriver.endNetworkCollect()
.then(records => {
records.marker = 'mocked';
return records;
});
endDevtoolsLog() {
calledDevtoolsLogCollect = true;
return [
fakeDevtoolsMessage
];
}
});
@ -414,8 +418,8 @@ describe('GatherRunner', function() {
};
return GatherRunner.afterPass({url, driver, config}, {TestGatherer: []}).then(vals => {
assert.equal(calledNetworkCollect, true);
assert.strictEqual(vals.networkRecords.marker, 'mocked');
assert.equal(calledDevtoolsLogCollect, true);
assert.strictEqual(vals.devtoolsLog[0], fakeDevtoolsMessage);
});
});
@ -492,13 +496,11 @@ describe('GatherRunner', function() {
it('doesn\'t leave networkRecords as an artifact', () => {
const passes = [{
blankDuration: 0,
recordNetwork: true,
recordTrace: true,
passName: 'firstPass',
gatherers: [new TestGatherer()]
}, {
blankDuration: 0,
recordNetwork: true,
recordTrace: true,
passName: 'secondPass',
gatherers: [new TestGatherer()]
@ -827,16 +829,20 @@ describe('GatherRunner', function() {
}];
// Arrange for driver to return unresolved request.
const url = 'http://www.some-non-existing-domain.com/';
const unresolvedDriver = Object.assign({}, fakeDriver, {
online: true,
endNetworkCollect() {
return Promise.resolve(recordsFromLogs(unresolvedPerfLog));
}
gotoURL() {
return Promise.resolve(url);
},
endDevtoolsLog() {
return unresolvedPerfLog;
},
});
return GatherRunner.run(passes, {
driver: unresolvedDriver,
url: 'http://www.some-non-existing-domain.com/',
url,
flags: {},
config: new Config({})
})
@ -857,16 +863,20 @@ describe('GatherRunner', function() {
}];
// Arrange for driver to return unresolved request.
const url = 'http://www.some-non-existing-domain.com/';
const unresolvedDriver = Object.assign({}, fakeDriver, {
online: false,
endNetworkCollect() {
return Promise.resolve(recordsFromLogs(unresolvedPerfLog));
gotoURL() {
return Promise.resolve(url);
},
endDevtoolsLog() {
return unresolvedPerfLog;
}
});
return GatherRunner.run(passes, {
driver: unresolvedDriver,
url: 'http://www.some-non-existing-domain.com/',
url,
flags: {},
config: new Config({})
})

Просмотреть файл

@ -20,14 +20,16 @@
const ResponseCompression =
require('../../../../gather/gatherers/dobetterweb/response-compression');
const assert = require('assert');
const mockDriver = require('../../fake-driver.js');
let options;
let optimizedResponses;
let responseCompression;
const traceData = {
networkRecords: [
{
_url: 'http://google.com/index.js',
_mimeType: 'text/javascript',
_requestId: 0,
_resourceSize: 9,
_resourceType: {
_isTextType: true,
@ -41,6 +43,7 @@ const traceData = {
{
_url: 'http://google.com/index.css',
_mimeType: 'text/css',
_requestId: 1,
_resourceSize: 6,
_resourceType: {
_isTextType: true,
@ -51,6 +54,7 @@ const traceData = {
{
_url: 'http://google.com/index.json',
_mimeType: 'application/json',
_requestId: 2,
_resourceSize: 7,
_resourceType: {
_isTextType: true,
@ -61,6 +65,7 @@ const traceData = {
{
_url: 'http://google.com/index.jpg',
_mimeType: 'images/jpg',
_requestId: 3,
_resourceSize: 10,
_resourceType: {
_isTextType: false,
@ -74,14 +79,21 @@ const traceData = {
describe('Optimized responses', () => {
// Reset the Gatherer before each test.
beforeEach(() => {
optimizedResponses = new ResponseCompression();
responseCompression = new ResponseCompression();
const driver = Object.assign({}, mockDriver, {
getRequestContent(id) {
return Promise.resolve(traceData.networkRecords[id].content);
},
});
options = {
url: 'http://google.com/',
driver,
};
});
it('returns only text and non encoded responses', () => {
return optimizedResponses.afterPass(options, createNetworkRequests(traceData))
return responseCompression.afterPass(options, createNetworkRequests(traceData))
.then(artifact => {
assert.equal(artifact.length, 2);
assert.ok(/index\.css$/.test(artifact[0].url));
@ -90,7 +102,7 @@ describe('Optimized responses', () => {
});
it('computes sizes', () => {
return optimizedResponses.afterPass(options, createNetworkRequests(traceData))
return responseCompression.afterPass(options, createNetworkRequests(traceData))
.then(artifact => {
assert.equal(artifact.length, 2);
assert.equal(artifact[0].resourceSize, 6);
@ -98,14 +110,14 @@ describe('Optimized responses', () => {
});
});
// Change into SDK.networkRequest when examples are ready
// Change into SDK.networkRequest when examples are ready
function createNetworkRequests(traceData) {
traceData.networkRecords = traceData.networkRecords.map(record => {
record.url = record._url;
record.mimeType = record._mimeType;
record.resourceSize = record._resourceSize;
record.responseHeaders = record._responseHeaders;
record.requestContent = () => Promise.resolve(record.content);
record.requestId = record._requestId;
record.resourceType = () => {
return Object.assign(
{