diff --git a/lighthouse-core/config/default.json b/lighthouse-core/config/default.json index ca03fd3b4b8f..82483dc07f48 100644 --- a/lighthouse-core/config/default.json +++ b/lighthouse-core/config/default.json @@ -18,6 +18,7 @@ }, { "loadPage": true, + "network": true, "gatherers": [ "service-worker", "offline" diff --git a/lighthouse-core/gather/gatherers/offline.js b/lighthouse-core/gather/gatherers/offline.js index 34e87e7bb726..b13fb553704d 100644 --- a/lighthouse-core/gather/gatherers/offline.js +++ b/lighthouse-core/gather/gatherers/offline.js @@ -15,27 +15,10 @@ * limitations under the License. */ -/* global XMLHttpRequest, __returnResults */ - 'use strict'; const Gatherer = require('./gatherer'); -// *WARNING* do not use fetch.. due to it requiring window focus to fire. -// Request the current page by issuing a XMLHttpRequest request to '' -// and storing the status code on the window. -// This runs in the context of the page, so we don't cover it with unit tests. -/* istanbul ignore next */ -const requestPage = function() { - const oReq = new XMLHttpRequest(); - oReq.onload = oReq.onerror = e => { - // __returnResults is injected by driver.evaluateAsync - __returnResults(e.currentTarget.status); - }; - oReq.open('GET', ''); - oReq.send(); -}; - class Offline extends Gatherer { static config(opts) { @@ -59,23 +42,28 @@ class Offline extends Gatherer { return driver.sendCommand('Network.emulateNetworkConditions', Offline.config({offline: false})); } - afterPass(options) { + beforePass(options) { const driver = options.driver; - // TODO eventually we will want to walk all network - // requests that the page initially made and retry them. - return Offline - .goOffline(driver) - .then(_ => driver.evaluateAsync(`(${requestPage.toString()}())`)) - .then(offlineResponseCode => { - this.artifact = offlineResponseCode; - }) - .then(_ => Offline.goOnline(driver)) - .catch(_ => { - this.artifact = { - offlineResponseCode: -1 - }; - }); + return driver.gotoURL(options.url, {waitForLoad: true}) + .then(_ => Offline.goOffline(driver)) + // Navigate away, then back, to allow a service worker that doesn't call + // clients.claim() to take control of the page load. + .then(_ => driver.gotoURL('about:blank')) + .then(_ => driver.gotoURL(options.url, {waitForLoad: true})) + .then(_ => Offline.goOnline(driver)); + } + + afterPass(options, tracingData) { + const navigationRecord = tracingData.networkRecords.filter(record => { + // If options.url is just an origin without a path, the Chrome will + // implicitly add in a path of '/'. + return (record._url === options.url || record._url === options.url + '/') && + record._initiator.type === 'other' && + record._fetchedViaServiceWorker; + })[0]; + + this.artifact = navigationRecord ? navigationRecord.statusCode : -1; } } diff --git a/lighthouse-core/lib/network-recorder.js b/lighthouse-core/lib/network-recorder.js index 9b8903db108d..1b6cff9a4f0c 100644 --- a/lighthouse-core/lib/network-recorder.js +++ b/lighthouse-core/lib/network-recorder.js @@ -87,8 +87,14 @@ class NetworkRecorder extends EventEmitter { } onResourceChangedPriority(data) { - this.networkManager._dispatcher.resourceChangedPriority(data.requestId, - data.newPriority, data.timestamp); + // TODO: this.networkManager._dispatcher.resourceChangedPriority is set to + // undefined when onResourceChangedPriority is triggered in + // gatherers/offline.js. The underlying cause may need to be investigated. + // In the meantime, explicitly check that it's a function. + if (typeof this.networkManager._dispatcher.resourceChangedPriority === 'function') { + this.networkManager._dispatcher.resourceChangedPriority(data.requestId, + data.newPriority, data.timestamp); + } } static recordsFromLogs(logs) { diff --git a/lighthouse-core/test/gather/gatherers/offline-test.js b/lighthouse-core/test/gather/gatherers/offline-test.js index aed67e2fb63a..c6a5a88d2cdb 100644 --- a/lighthouse-core/test/gather/gatherers/offline-test.js +++ b/lighthouse-core/test/gather/gatherers/offline-test.js @@ -55,21 +55,4 @@ describe('HTTP Redirect gatherer', () => { assert.deepEqual(offlineGather.artifact, {offlineResponseCode: -1}); }); }); - - it('handles driver evaluateAsync() failure', () => { - return offlineGather.afterPass({ - driver: { - sendCommand() { - return Promise.resolve(); - }, - evaluateAsync() { - return Promise.reject(); - } - } - }).then(_ => { - assert(false); - }).catch(_ => { - assert.deepEqual(offlineGather.artifact, {offlineResponseCode: -1}); - }); - }); });