-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core(lightwallet): add resource-summary audit (#8522)
- Loading branch information
1 parent
ed71c9c
commit 9323a55
Showing
8 changed files
with
531 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
/** | ||
* @license Copyright 2019 Google Inc. All Rights Reserved. | ||
* 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. | ||
*/ | ||
'use strict'; | ||
|
||
const Audit = require('./audit.js'); | ||
const ComputedResourceSummary = require('../computed/resource-summary.js'); | ||
const i18n = require('../lib/i18n/i18n.js'); | ||
|
||
const UIStrings = { | ||
/** Imperative title of a Lighthouse audit that tells the user to minimize the size and quantity of resources used to load the page. */ | ||
title: 'Keep request counts low and transfer sizes small', | ||
/** Description of a Lighthouse audit that tells the user that they can setup a budgets for the quantity and size of page resources. No character length limits. */ | ||
description: 'To set budgets for the quantity and size of page resources,' + | ||
' add a budget.json file.', | ||
/** [ICU Syntax] Label for an audit identifying the number of requests and kilobytes used to load the page. */ | ||
displayValue: `{requestCount, plural, =1 {1 request} other {# requests}}` + | ||
` • { byteCount, number, bytes } KB`, | ||
}; | ||
|
||
const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings); | ||
|
||
class ResourceSummary extends Audit { | ||
/** | ||
* @return {LH.Audit.Meta} | ||
*/ | ||
static get meta() { | ||
return { | ||
id: 'resource-summary', | ||
title: str_(UIStrings.title), | ||
description: str_(UIStrings.description), | ||
scoreDisplayMode: Audit.SCORING_MODES.INFORMATIVE, | ||
requiredArtifacts: ['devtoolsLogs', 'URL'], | ||
}; | ||
} | ||
|
||
/** | ||
* @param {LH.Artifacts} artifacts | ||
* @param {LH.Audit.Context} context | ||
* @return {Promise<LH.Audit.Product>} | ||
*/ | ||
static async audit(artifacts, context) { | ||
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS]; | ||
const summary = await ComputedResourceSummary | ||
.request({devtoolsLog, URL: artifacts.URL}, context); | ||
|
||
/** @type {LH.Audit.Details.Table['headings']} */ | ||
const headings = [ | ||
{key: 'label', itemType: 'text', text: 'Resource Type'}, | ||
{key: 'requestCount', itemType: 'numeric', text: 'Requests'}, | ||
{key: 'size', itemType: 'bytes', text: 'Transfer Size'}, | ||
]; | ||
|
||
|
||
/** @type {Record<LH.Budget.ResourceType,string>} */ | ||
const strMappings = { | ||
'total': str_(i18n.UIStrings.totalResourceType), | ||
'document': str_(i18n.UIStrings.documentResourceType), | ||
'script': str_(i18n.UIStrings.scriptResourceType), | ||
'stylesheet': str_(i18n.UIStrings.stylesheetResourceType), | ||
'image': str_(i18n.UIStrings.imageResourceType), | ||
'media': str_(i18n.UIStrings.mediaResourceType), | ||
'font': str_(i18n.UIStrings.fontResourceType), | ||
'other': str_(i18n.UIStrings.otherResourceType), | ||
'third-party': str_(i18n.UIStrings.thirdPartyResourceType), | ||
}; | ||
|
||
const types = /** @type {Array<LH.Budget.ResourceType>} */ (Object.keys(summary)); | ||
const rows = types.map(type => { | ||
return { | ||
// ResourceType is included as an "id" for ease of use. | ||
// It does not appear directly in the table. | ||
resourceType: type, | ||
label: strMappings[type], | ||
requestCount: summary[type].count, | ||
size: summary[type].size, | ||
}; | ||
}); | ||
// Force third-party to be last, descending by size otherwise | ||
const thirdPartyRow = rows.find(r => r.resourceType === 'third-party') || []; | ||
const otherRows = rows.filter(r => r.resourceType !== 'third-party') | ||
.sort((a, b) => { | ||
return b.size - a.size; | ||
}); | ||
const tableItems = otherRows.concat(thirdPartyRow); | ||
|
||
const tableDetails = Audit.makeTableDetails(headings, tableItems); | ||
|
||
return { | ||
details: tableDetails, | ||
score: 1, | ||
displayValue: str_(UIStrings.displayValue, { | ||
requestCount: summary.total.count, | ||
byteCount: summary.total.size, | ||
}), | ||
}; | ||
} | ||
} | ||
|
||
module.exports = ResourceSummary; | ||
module.exports.UIStrings = UIStrings; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/** | ||
* @license Copyright 2019 Google Inc. All Rights Reserved. | ||
* 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. | ||
*/ | ||
'use strict'; | ||
|
||
const ResourceSummaryAudit = require('../../audits/resource-summary.js'); | ||
const networkRecordsToDevtoolsLog = require('../network-records-to-devtools-log.js'); | ||
|
||
/* eslint-env jest */ | ||
|
||
describe('Performance: Resource summary audit', () => { | ||
let artifacts; | ||
let context; | ||
beforeEach(() => { | ||
context = {computedCache: new Map()}; | ||
|
||
artifacts = { | ||
devtoolsLogs: { | ||
defaultPass: networkRecordsToDevtoolsLog([ | ||
{url: 'http://example.com/file.html', resourceType: 'Document', transferSize: 30}, | ||
{url: 'http://example.com/app.js', resourceType: 'Script', transferSize: 10}, | ||
{url: 'http://third-party.com/script.js', resourceType: 'Script', transferSize: 50}, | ||
{url: 'http://third-party.com/file.jpg', resourceType: 'Image', transferSize: 70}, | ||
])}, | ||
URL: {requestedUrl: 'https://example.com', finalUrl: 'https://example.com'}, | ||
}; | ||
}); | ||
|
||
it('has three table columns', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
expect(result.details.headings).toHaveLength(3); | ||
}); | ||
|
||
it('has the correct score', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
expect(result.score).toBe(1); | ||
}); | ||
|
||
it('has the correct display value', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
expect(result.displayValue).toBeDisplayString('4 requests • 0 KB'); | ||
}); | ||
|
||
it('includes the correct properties for each table item', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
const item = result.details.items[0]; | ||
expect(item.resourceType).toEqual('total'); | ||
expect(item.label).toBeDisplayString('Total'); | ||
expect(item.requestCount).toBe(4); | ||
expect(item.size).toBe(160); | ||
}); | ||
|
||
it('includes all resource types, regardless of whether page contains them', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
expect(Object.keys(result.details.items)).toHaveLength(9); | ||
}); | ||
|
||
it('it displays "0" if there are no resources of that type', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
const fontItem = result.details.items.find(item => item.resourceType === 'font'); | ||
expect(fontItem.requestCount).toBe(0); | ||
expect(fontItem.size).toBe(0); | ||
}); | ||
|
||
describe('table ordering', () => { | ||
it('except for the last row, it sorts items by size (descending)', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
const items = result.details.items; | ||
items.slice(0, -2).forEach((item, index) => { | ||
expect(item.size).toBeGreaterThanOrEqual(items[index + 1].size); | ||
}); | ||
}); | ||
|
||
it('"Total" is the first row', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
expect(result.details.items[0].resourceType).toBe('total'); | ||
}); | ||
|
||
it('"Third-party" is the last-row', async () => { | ||
const result = await ResourceSummaryAudit.audit(artifacts, context); | ||
const items = result.details.items; | ||
expect(items[items.length - 1].resourceType).toBe('third-party'); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.