Skip to content

Commit

Permalink
feedback.
Browse files Browse the repository at this point in the history
  • Loading branch information
paulirish committed Mar 11, 2017
1 parent 8680289 commit 6018a1b
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 20 deletions.
35 changes: 31 additions & 4 deletions lighthouse-core/audits/load-fast-enough-for-pwa.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,16 @@

'use strict';

/** @fileoverview
* This audit evaluates if a page's load performance is fast enough for it to be considered a PWA.
* We are doublechecking that the network requests were throttled (or slow on their own)
* Afterwards, we report if the TTI is less than 10 seconds.
*/

const Audit = require('./audit');
const TTIMetric = require('./time-to-interactive');
const Emulation = require('../lib/emulation');

const Formatter = require('../formatters/formatter');

// Maximum TTI to be considered "fast" for PWA baseline checklist
Expand All @@ -24,7 +32,7 @@ class LoadFastEnough4Pwa extends Audit {
name: 'load-fast-enough-for-pwa',
description: 'Page load is fast enough on 3G',
helpText: 'Satisfied if the _Time To Interactive_ duration is shorter than _10 seconds_, as defined by the [PWA Baseline Checklist](https://developers.google.com/web/progressive-web-apps/checklist).',
requiredArtifacts: ['traces']
requiredArtifacts: ['traces', 'networkRecords']
};
}

Expand All @@ -33,20 +41,39 @@ class LoadFastEnough4Pwa extends Audit {
* @return {!AuditResult}
*/
static audit(artifacts) {
const networkRecords = artifacts.networkRecords[Audit.DEFAULT_PASS];
const allRequestLatencies = networkRecords.map(record => {
if (!record._timing) return Infinity;
// Use DevTools' definition of Waiting latency: https://github.com/ChromeDevTools/devtools-frontend/blob/66595b8a73a9c873ea7714205b828866630e9e82/front_end/network/RequestTimingView.js#L164
return record._timing.receiveHeadersEnd - record._timing.sendEnd;
});

const latency3gMin = Emulation.settings.TYPICAL_MOBILE_THROTTLING_METRICS.latency - 10;
const areLatenciesAll3G = allRequestLatencies.every(val => val > latency3gMin);

return TTIMetric.audit(artifacts).then(ttiResult => {
const timeToInteractive = ttiResult.extendedInfo.value.timings.timeToInteractive;
const isFast = timeToInteractive < MAXIMUM_TTI;

const extendedInfo = {
formatter: Formatter.SUPPORTED_FORMATS.NULL,
value: {timeToInteractive}
value: {allRequestLatencies, timeToInteractive}
};

if (!areLatenciesAll3G) {
return LoadFastEnough4Pwa.generateAuditResult({
rawValue: false,
// eslint-disable-next-line max-len
debugString: `The Time To Interactive was found at ${ttiResult.displayValue}, however, the network request latencies were not sufficiently realistic, so the performance measurements cannot be trusted.`,
extendedInfo
});
}

if (!isFast) {
return LoadFastEnough4Pwa.generateAuditResult({
rawValue: false,
debugString: `Under mobile conditions, the TTI was at ${ttiResult.displayValue}. ` +
'More details in "Performance" section.',
// eslint-disable-next-line max-len
debugString: `Under 3G conditions, the Time To Interactive was at ${ttiResult.displayValue}. More details in the "Performance" section.`,
extendedInfo
});
}
Expand Down
11 changes: 10 additions & 1 deletion lighthouse-core/lib/emulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,14 @@ module.exports = {
enableCPUThrottling,
disableCPUThrottling,
goOffline,
getEmulationDesc
getEmulationDesc,
settings: {
NEXUS5X_EMULATION_METRICS,
NEXUS5X_USERAGENT,
TYPICAL_MOBILE_THROTTLING_METRICS,
OFFLINE_METRICS,
NO_THROTTLING_METRICS,
NO_CPU_THROTTLE_METRICS,
CPU_THROTTLE_METRICS
}
};
46 changes: 31 additions & 15 deletions lighthouse-core/test/audits/load-fast-enough-for-pwa-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,54 @@ const FastPWAAudit = require('../../audits/load-fast-enough-for-pwa');
const TTIAudit = require('../../audits/time-to-interactive');
const Audit = require('../../audits/audit.js');
const assert = require('assert');
const traceEvents = require('../fixtures/traces/progressive-app.json');

const GatherRunner = require('../../gather/gather-runner.js');
const computedArtifacts = GatherRunner.instantiateComputedArtifacts();
function generateTTIResults(ttiValue) {
const ttiResult = {
rawValue: ttiValue,
extendedInfo: {
value: {
timings: {
timeToInteractive: ttiValue
}
}
}
};
return Promise.resolve.bind(Promise, ttiResult);
}


function generateArtifactsWithTrace(trace) {
return Object.assign(computedArtifacts, {
function generateArtifacts() {
return {
networkRecords: {
[Audit.DEFAULT_PASS]: []
},
traces: {
[Audit.DEFAULT_PASS]: {traceEvents: Array.isArray(trace) ? trace : trace.traceEvents}
[Audit.DEFAULT_PASS]: {traceEvents: []}
}
});
};
}

/* eslint-env mocha */
describe('PWA: load-fast-enough-for-pwa audit', () => {
// monkeypatch TTI to for a more focused test
let origTTI;
beforeEach(() => origTTI = TTIAudit.audit);
afterEach(() => TTIAudit.audit = origTTI);

it('returns boolean based on TTI value', () => {
return FastPWAAudit.audit(generateArtifactsWithTrace(traceEvents)).then(result => {
TTIAudit.audit = generateTTIResults(5000);
return FastPWAAudit.audit(generateArtifacts()).then(result => {
assert.equal(result.rawValue, true, 'fixture trace is not passing audit');
}).catch(err => {
assert.ok(false, err);
});
});

it('fails a bad TTI value', () => {
// mock a return for the TTI Audit
const origTTI = TTIAudit.audit;
const mockTTIResult = {extendedInfo: {value: {timings: {timeToInteractive: 15000}}}};
TTIAudit.audit = _ => Promise.resolve(mockTTIResult);

return FastPWAAudit.audit(generateArtifactsWithTrace(traceEvents)).then(result => {
TTIAudit.audit = generateTTIResults(15000);
return FastPWAAudit.audit(generateArtifacts()).then(result => {
assert.equal(result.rawValue, false, 'not failing a long TTI value');
TTIAudit.audit = origTTI;
assert.ok(result.debugString);
}).catch(err => {
assert.ok(false, err);
});
Expand Down

0 comments on commit 6018a1b

Please sign in to comment.