Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tests: add networkRecord-to-devtoolsLog mocking utility #6171

Merged
merged 2 commits into from
Oct 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const TotalByteWeight = require('../../../audits/byte-efficiency/total-byte-weig
const assert = require('assert');
const URL = require('url').URL;
const options = TotalByteWeight.defaultOptions;
const Runner = require('../../../runner.js');
const networkRecordsToDevtoolsLog = require('../../network-records-to-devtools-log.js');

/* eslint-env jest */

Expand All @@ -32,10 +34,9 @@ function generateArtifacts(records) {
records = records.map(args => generateRequest(...args));
}

return {
devtoolsLogs: {defaultPass: []},
requestNetworkRecords: () => Promise.resolve(records),
};
return Object.assign(Runner.instantiateComputedArtifacts(), {
devtoolsLogs: {defaultPass: networkRecordsToDevtoolsLog(records)},
});
}

describe('Total byte weight audit', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

const UnusedCSSAudit = require('../../../audits/byte-efficiency/unused-css-rules.js');
const assert = require('assert');
const Runner = require('../../../runner.js');
const networkRecordsToDevtoolsLog = require('../../network-records-to-devtools-log.js');

/* eslint-env jest */

Expand Down Expand Up @@ -117,33 +119,32 @@ describe('Best Practices: unused css rules audit', () => {
});

describe('#audit', () => {
const devtoolsLogs = {defaultPass: []};
const requestNetworkRecords = () => {
return Promise.resolve([
{
url: 'file://a.css',
transferSize: 10 * 1024,
resourceType: 'Stylesheet',
},
]);
};
const networkRecords = [
{
url: 'file://a.css',
transferSize: 10 * 1024,
resourceType: 'Stylesheet',
},
];

function getArtifacts({CSSUsage}) {
return Object.assign(Runner.instantiateComputedArtifacts(), {
devtoolsLogs: {defaultPass: networkRecordsToDevtoolsLog(networkRecords)},
URL: {finalUrl: ''},
CSSUsage,
});
}

it('ignores missing stylesheets', () => {
return UnusedCSSAudit.audit_({
devtoolsLogs,
requestNetworkRecords,
URL: {finalUrl: ''},
return UnusedCSSAudit.audit_(getArtifacts({
CSSUsage: {rules: [{styleSheetId: 'a', used: false}], stylesheets: []},
}).then(result => {
})).then(result => {
assert.equal(result.items.length, 0);
});
});

it('ignores stylesheets that are 100% used', () => {
return UnusedCSSAudit.audit_({
devtoolsLogs,
requestNetworkRecords,
URL: {finalUrl: ''},
return UnusedCSSAudit.audit_(getArtifacts({
CSSUsage: {rules: [
{styleSheetId: 'a', used: true},
{styleSheetId: 'a', used: true},
Expand All @@ -158,16 +159,13 @@ describe('Best Practices: unused css rules audit', () => {
content: '.my.favorite.selector { rule: content; }',
},
]},
}).then(result => {
})).then(result => {
assert.equal(result.items.length, 0);
});
});

it('fails when lots of rules are unused', () => {
return UnusedCSSAudit.audit_({
devtoolsLogs,
requestNetworkRecords,
URL: {finalUrl: ''},
return UnusedCSSAudit.audit_(getArtifacts({
CSSUsage: {rules: [
{styleSheetId: 'a', used: true, startOffset: 0, endOffset: 11}, // 44 * 1 / 4
{styleSheetId: 'b', used: true, startOffset: 0, endOffset: 6000}, // 4000 * 3 / 2
Expand All @@ -185,7 +183,7 @@ describe('Best Practices: unused css rules audit', () => {
content: `${generate('123', 450)}`, // will be filtered out
},
]},
}).then(result => {
})).then(result => {
assert.equal(result.items.length, 2);
assert.equal(result.items[0].totalBytes, 10 * 1024);
assert.equal(result.items[1].totalBytes, 6000);
Expand All @@ -195,10 +193,7 @@ describe('Best Practices: unused css rules audit', () => {
});

it('does not include empty or small sheets', () => {
return UnusedCSSAudit.audit_({
devtoolsLogs,
requestNetworkRecords,
URL: {finalUrl: ''},
return UnusedCSSAudit.audit_(getArtifacts({
CSSUsage: {rules: [
{styleSheetId: 'a', used: true, startOffset: 0, endOffset: 8000}, // 4000 * 3 / 2
{styleSheetId: 'b', used: true, startOffset: 0, endOffset: 500}, // 500 * 3 / 3
Expand All @@ -224,7 +219,7 @@ describe('Best Practices: unused css rules audit', () => {
content: ' ',
},
]},
}).then(result => {
})).then(result => {
assert.equal(result.items.length, 1);
assert.equal(Math.floor(result.items[0].wastedPercent), 33);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ const CacheHeadersAudit = require('../../../audits/byte-efficiency/uses-long-cac
const assert = require('assert');
const NetworkRequest = require('../../../lib/network-request');
const options = CacheHeadersAudit.defaultOptions;
const Runner = require('../../../runner.js');
const networkRecordsToDevtoolsLog = require('../../network-records-to-devtools-log.js');

/* eslint-env jest */

Expand All @@ -28,20 +30,20 @@ function networkRecord(options = {}) {
}

describe('Cache headers audit', () => {
let artifacts;
let networkRecords;
function getArtifacts(networkRecords) {
const devtoolLogs = networkRecordsToDevtoolsLog(networkRecords);

beforeEach(() => {
artifacts = {
devtoolsLogs: {},
requestNetworkRecords: () => Promise.resolve(networkRecords),
return Object.assign(Runner.instantiateComputedArtifacts(), {
devtoolsLogs: {
[CacheHeadersAudit.DEFAULT_PASS]: devtoolLogs,
},
requestNetworkThroughput: () => Promise.resolve(1000),
};
});
});
}

it('detects missing cache headers', () => {
networkRecords = [networkRecord()];
return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
const networkRecords = [networkRecord()];
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
const items = result.extendedInfo.value.results;
assert.equal(items.length, 1);
assert.equal(items[0].cacheLifetimeMs, 0);
Expand All @@ -51,14 +53,14 @@ describe('Cache headers audit', () => {
});

it('detects low value max-age headers', () => {
networkRecords = [
const networkRecords = [
networkRecord({headers: {'cache-control': 'max-age=3600'}}), // an hour
networkRecord({headers: {'cache-control': 'max-age=3600'}, transferSize: 100000}), // an hour
networkRecord({headers: {'cache-control': 'max-age=86400'}}), // a day
networkRecord({headers: {'cache-control': 'max-age=31536000'}}), // a year
];

return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
const items = result.details.items;
assert.equal(items.length, 3);
assert.equal(items[0].cacheLifetimeMs, 3600 * 1000);
Expand All @@ -76,14 +78,14 @@ describe('Cache headers audit', () => {
const expiresIn = seconds => new Date(Date.now() + seconds * 1000).toGMTString();
const closeEnough = (actual, exp) => assert.ok(Math.abs(actual - exp) <= 1, 'invalid expires');

networkRecords = [
const networkRecords = [
networkRecord({headers: {expires: expiresIn(86400 * 365)}}), // a year
networkRecord({headers: {expires: expiresIn(86400 * 90)}}), // 3 months
networkRecord({headers: {expires: expiresIn(86400)}}), // a day
networkRecord({headers: {expires: expiresIn(3600)}}), // an hour
];

return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
const items = result.extendedInfo.value.results;
assert.equal(items.length, 3);
closeEnough(items[0].cacheLifetimeMs, 3600 * 1000);
Expand All @@ -98,7 +100,7 @@ describe('Cache headers audit', () => {
it('respects expires/cache-control priority', () => {
const expiresIn = seconds => new Date(Date.now() + seconds * 1000).toGMTString();

networkRecords = [
const networkRecords = [
networkRecord({headers: {
'cache-control': 'must-revalidate,max-age=3600',
'expires': expiresIn(86400),
Expand All @@ -109,7 +111,7 @@ describe('Cache headers audit', () => {
}}),
];

return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
const items = result.extendedInfo.value.results;
assert.equal(items.length, 2);
assert.ok(Math.abs(items[0].cacheLifetimeMs - 3600 * 1000) <= 1, 'invalid expires parsing');
Expand All @@ -120,7 +122,7 @@ describe('Cache headers audit', () => {
});

it('respects multiple cache-control headers', () => {
networkRecords = [
const networkRecords = [
networkRecord({headers: {
'cache-control': 'max-age=31536000, public',
'Cache-control': 'no-transform',
Expand All @@ -132,49 +134,49 @@ describe('Cache headers audit', () => {
}}),
];

return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
const items = result.extendedInfo.value.results;
assert.equal(items.length, 1);
});
});

it('catches records with Etags', () => {
networkRecords = [
const networkRecords = [
networkRecord({headers: {etag: 'md5hashhere'}}),
networkRecord({headers: {'etag': 'md5hashhere', 'cache-control': 'max-age=60'}}),
];

return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
const items = result.extendedInfo.value.results;
assert.equal(items.length, 2);
});
});

it('ignores explicit no-cache policies', () => {
networkRecords = [
const networkRecords = [
networkRecord({headers: {expires: '-1'}}),
networkRecord({headers: {'cache-control': 'no-store'}}),
networkRecord({headers: {'cache-control': 'no-cache'}}),
networkRecord({headers: {'cache-control': 'max-age=0'}}),
networkRecord({headers: {pragma: 'no-cache'}}),
];

return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
const items = result.extendedInfo.value.results;
assert.equal(result.score, 1);
assert.equal(items.length, 0);
});
});

it('ignores potentially uncacheable records', () => {
networkRecords = [
const networkRecords = [
networkRecord({statusCode: 500}),
networkRecord({url: 'https://example.com/dynamic.js?userId=crazy', transferSize: 10}),
networkRecord({url: 'data:image/jpeg;base64,what'}),
networkRecord({resourceType: NetworkRequest.TYPES.XHR}),
];

return CacheHeadersAudit.audit(artifacts, {options}).then(result => {
return CacheHeadersAudit.audit(getArtifacts(networkRecords), {options}).then(result => {
assert.equal(result.score, 1);
const items = result.extendedInfo.value.results;
assert.equal(items.length, 1);
Expand Down
8 changes: 3 additions & 5 deletions lighthouse-core/test/audits/critical-request-chains-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

/* eslint-env jest */

const Runner = require('../../runner.js');
const CriticalRequestChains = require('../../audits/critical-request-chains.js');
const assert = require('assert');

Expand Down Expand Up @@ -70,17 +71,14 @@ const PASSING_REQUEST_CHAIN_2 = {
const EMPTY_REQUEST_CHAIN = {};

const mockArtifacts = (mockChain) => {
return {
return Object.assign(Runner.instantiateComputedArtifacts(), {
devtoolsLogs: {
[CriticalRequestChains.DEFAULT_PASS]: [],
},
requestNetworkRecords: () => {
return Promise.resolve([]);
},
requestCriticalRequestChains: function() {
return Promise.resolve(mockChain);
},
};
});
};

describe('Performance: critical-request-chains audit', () => {
Expand Down
36 changes: 21 additions & 15 deletions lighthouse-core/test/audits/dobetterweb/uses-http2-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@
*/
'use strict';

const Runner = require('../../../runner.js');
const UsesHTTP2Audit = require('../../../audits/dobetterweb/uses-http2.js');
const assert = require('assert');
const networkRecordsToDevtoolsLog = require('../../network-records-to-devtools-log.js');

const URL = 'https://webtide.com/http2-push-demo/';
const networkRecords = require('../../fixtures/networkRecords-mix.json');

/* eslint-env jest */

describe('Resources are fetched over http/2', () => {
function getArtifacts(networkRecords, finalUrl) {
// networkRecords-mix.json is an old network request format, so don't verify round-trip.
const devtoolsLog = networkRecordsToDevtoolsLog(networkRecords, {skipVerification: true});
Copy link
Member Author

@brendankenny brendankenny Oct 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using a real networkRecord as input has a few problems with verification of the output, namely that we've already snipped a bunch of circular references in the fixture and replaced them with strings and we've changed a few NetworkRequest properties since that old version of NetworkRecorder. The subset of properties needed for this test generates correctly, so it seemed better to just not verify rather than edit the json file.


return Object.assign(Runner.instantiateComputedArtifacts(), {
URL: {finalUrl},
devtoolsLogs: {[UsesHTTP2Audit.DEFAULT_PASS]: devtoolsLog},
});
}

it('fails when some resources were requested via http/1.x', () => {
return UsesHTTP2Audit.audit({
URL: {finalUrl: URL},
devtoolsLogs: {[UsesHTTP2Audit.DEFAULT_PASS]: []},
requestNetworkRecords: () => Promise.resolve(networkRecords),
}).then(auditResult => {
return UsesHTTP2Audit.audit(
getArtifacts(networkRecords, URL)
).then(auditResult => {
assert.equal(auditResult.rawValue, false);
assert.ok(auditResult.displayValue.match('3 requests not'));
assert.equal(auditResult.details.items.length, 3);
Expand All @@ -32,11 +42,9 @@ describe('Resources are fetched over http/2', () => {

it('displayValue is correct when only one resource fails', () => {
const entryWithHTTP1 = networkRecords.slice(1, 2);
return UsesHTTP2Audit.audit({
URL: {finalUrl: URL},
devtoolsLogs: {[UsesHTTP2Audit.DEFAULT_PASS]: []},
requestNetworkRecords: () => Promise.resolve(entryWithHTTP1),
}).then(auditResult => {
return UsesHTTP2Audit.audit(
getArtifacts(entryWithHTTP1, URL)
).then(auditResult => {
assert.ok(auditResult.displayValue.match('1 request not'));
});
});
Expand All @@ -47,11 +55,9 @@ describe('Resources are fetched over http/2', () => {
record.protocol = 'h2';
});

return UsesHTTP2Audit.audit({
URL: {finalUrl: URL},
devtoolsLogs: {[UsesHTTP2Audit.DEFAULT_PASS]: []},
requestNetworkRecords: () => Promise.resolve(h2Records),
}).then(auditResult => {
return UsesHTTP2Audit.audit(
getArtifacts(h2Records, URL)
).then(auditResult => {
assert.equal(auditResult.rawValue, true);
assert.ok(auditResult.displayValue === '');
});
Expand Down
Loading