From 5618037ec7c6bacaa8cc4643c4252b908da85323 Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Tue, 23 Nov 2021 18:06:47 -0600 Subject: [PATCH] core: add original location to most usages of source-location (#13393) --- lighthouse-core/audits/audit.js | 46 ++++++-- .../byte-efficiency/legacy-javascript.js | 27 +---- lighthouse-core/audits/deprecations.js | 24 ++-- .../dobetterweb/geolocation-on-start.js | 9 +- .../audits/dobetterweb/no-document-write.js | 10 +- .../dobetterweb/notification-on-start.js | 10 +- .../uses-passive-event-listeners.js | 10 +- lighthouse-core/audits/errors-in-console.js | 11 +- lighthouse-core/audits/no-unload-listeners.js | 19 ++- lighthouse-core/audits/seo/font-size.js | 6 +- lighthouse-core/audits/violation-audit.js | 13 ++- .../test/audits/deprecations-test.js | 36 ++++-- .../dobetterweb/geolocation-on-start-test.js | 18 ++- .../dobetterweb/no-document-write-test.js | 16 ++- .../dobetterweb/notification-on-start-test.js | 18 ++- .../uses-passive-event-listeners-test.js | 18 ++- .../test/audits/errors-in-console-test.js | 108 ++++++++++++------ .../test/audits/no-unload-listeners-test.js | 49 ++++++-- .../test/audits/seo/font-size-test.js | 4 + .../fraggle-rock/scenarios/api-test-pptr.js | 2 +- lighthouse-core/test/results/sample_v2.json | 26 ++++- .../lighthouse-successful-run-expected.txt | 2 + 22 files changed, 311 insertions(+), 171 deletions(-) diff --git a/lighthouse-core/audits/audit.js b/lighthouse-core/audits/audit.js index a2a386cc56c5..8dab32e89584 100644 --- a/lighthouse-core/audits/audit.js +++ b/lighthouse-core/audits/audit.js @@ -233,21 +233,53 @@ class Audit { } /** - * @param {LH.Artifacts.ConsoleMessage} entry - * @return {LH.Audit.Details.SourceLocationValue | undefined} + * @param {LH.Artifacts.Bundle} bundle + * @param {number} generatedLine + * @param {number} generatedColumn + * @return {LH.Audit.Details.SourceLocationValue['original']} */ - static makeSourceLocationFromConsoleMessage(entry) { - if (!entry.url) return; + static _findOriginalLocation(bundle, generatedLine, generatedColumn) { + const entry = bundle?.map.findEntry(generatedLine, generatedColumn); + if (!entry) return; + return { + file: entry.sourceURL || '', + line: entry.sourceLineNumber || 0, + column: entry.sourceColumnNumber || 0, + }; + } + + /** + * @param {string} url + * @param {number} line 0-indexed + * @param {number} column 0-indexed + * @param {LH.Artifacts.Bundle=} bundle + * @return {LH.Audit.Details.SourceLocationValue} + */ + static makeSourceLocation(url, line, column, bundle) { return { type: 'source-location', - url: entry.url, + url, urlProvider: 'network', - line: entry.lineNumber || 0, - column: entry.columnNumber || 0, + line, + column, + original: bundle && this._findOriginalLocation(bundle, line, column), }; } + /** + * @param {LH.Artifacts.ConsoleMessage} entry + * @param {LH.Artifacts.Bundle=} bundle + * @return {LH.Audit.Details.SourceLocationValue | undefined} + */ + static makeSourceLocationFromConsoleMessage(entry, bundle) { + if (!entry.url) return; + + const line = entry.lineNumber || 0; + const column = entry.columnNumber || 0; + return this.makeSourceLocation(entry.url, line, column, bundle); + } + /** * @param {number|null} score * @param {LH.Audit.ScoreDisplayMode} scoreDisplayMode diff --git a/lighthouse-core/audits/byte-efficiency/legacy-javascript.js b/lighthouse-core/audits/byte-efficiency/legacy-javascript.js index 60b29e0b1f47..2d1ed076533d 100644 --- a/lighthouse-core/audits/byte-efficiency/legacy-javascript.js +++ b/lighthouse-core/audits/byte-efficiency/legacy-javascript.js @@ -397,23 +397,6 @@ class LegacyJavascript extends ByteEfficiencyAudit { return transferRatio; } - /** - * @param {LH.Artifacts.Bundle} bundle - * @param {number} generatedLine - * @param {number} generatedColumn - * @return {LH.Audit.Details.SourceLocationValue['original']} - */ - static _findOriginalLocation(bundle, generatedLine, generatedColumn) { - const entry = bundle && bundle.map.findEntry(generatedLine, generatedColumn); - if (!entry) return; - - return { - file: entry.sourceURL || '', - line: entry.sourceLineNumber || 0, - column: entry.sourceColumnNumber || 0, - }; - } - /** * @param {LH.Artifacts} artifacts * @param {Array} networkRecords @@ -456,18 +439,10 @@ class LegacyJavascript extends ByteEfficiencyAudit { const bundle = bundles.find(bundle => bundle.script.src === url); for (const match of matches) { const {name, line, column} = match; - /** @type {SubItem} */ const subItem = { signal: name, - location: { - type: 'source-location', - url, - line, - column, - original: bundle && this._findOriginalLocation(bundle, line, column), - urlProvider: 'network', - }, + location: ByteEfficiencyAudit.makeSourceLocation(url, line, column, bundle), }; item.subItems.items.push(subItem); } diff --git a/lighthouse-core/audits/deprecations.js b/lighthouse-core/audits/deprecations.js index 038e41c91b8e..ec6b03955dfe 100644 --- a/lighthouse-core/audits/deprecations.js +++ b/lighthouse-core/audits/deprecations.js @@ -14,6 +14,7 @@ // TODO: when M97 is sufficiently old, drop support for console messages const Audit = require('./audit.js'); +const JsBundles = require('../computed/js-bundles.js'); const i18n = require('../lib/i18n/i18n.js'); const UIStrings = { @@ -47,34 +48,29 @@ class Deprecations extends Audit { title: str_(UIStrings.title), failureTitle: str_(UIStrings.failureTitle), description: str_(UIStrings.description), - requiredArtifacts: ['ConsoleMessages', 'InspectorIssues'], + requiredArtifacts: ['ConsoleMessages', 'InspectorIssues', 'SourceMaps', 'ScriptElements'], }; } /** * @param {LH.Artifacts} artifacts - * @return {LH.Audit.Product} + * @param {LH.Audit.Context} context + * @return {Promise} */ - static audit(artifacts) { + static async audit(artifacts, context) { const entries = artifacts.ConsoleMessages; + const bundles = await JsBundles.request(artifacts, context); let deprecations; - if (artifacts.InspectorIssues.deprecations.length) { deprecations = artifacts.InspectorIssues.deprecations .map(deprecation => { + const {url, lineNumber, columnNumber} = deprecation.sourceCodeLocation; + const bundle = bundles.find(bundle => bundle.script.src === url); return { value: deprecation.message || '', - /** @type {LH.Audit.Details.SourceLocationValue} */ - source: { - type: 'source-location', - url: deprecation.sourceCodeLocation.url, - urlProvider: 'network', - line: deprecation.sourceCodeLocation.lineNumber, - // Protocol.Audits.SourceCodeLocation.columnNumber is 1-indexed, - // but we use 0-indexed. - column: deprecation.sourceCodeLocation.columnNumber - 1, - }, + // Protocol.Audits.SourceCodeLocation.columnNumber is 1-indexed, but we use 0-indexed. + source: Audit.makeSourceLocation(url, lineNumber, columnNumber - 1, bundle), }; }); } else { diff --git a/lighthouse-core/audits/dobetterweb/geolocation-on-start.js b/lighthouse-core/audits/dobetterweb/geolocation-on-start.js index 0c04104ae1d2..0ab08f645eda 100644 --- a/lighthouse-core/audits/dobetterweb/geolocation-on-start.js +++ b/lighthouse-core/audits/dobetterweb/geolocation-on-start.js @@ -38,17 +38,18 @@ class GeolocationOnStart extends ViolationAudit { failureTitle: str_(UIStrings.failureTitle), description: str_(UIStrings.description), supportedModes: ['navigation'], - requiredArtifacts: ['ConsoleMessages'], + requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'ScriptElements'], }; } /** * @param {LH.Artifacts} artifacts - * @return {LH.Audit.Product} + * @param {LH.Audit.Context} context + * @return {Promise} */ - static audit(artifacts) { + static async audit(artifacts, context) { // 'Only request geolocation information in response to a user gesture.' - const results = ViolationAudit.getViolationResults(artifacts, /geolocation/); + const results = await ViolationAudit.getViolationResults(artifacts, context, /geolocation/); /** @type {LH.Audit.Details.Table['headings']} */ const headings = [ diff --git a/lighthouse-core/audits/dobetterweb/no-document-write.js b/lighthouse-core/audits/dobetterweb/no-document-write.js index 36190e6c6890..840c77f24ccf 100644 --- a/lighthouse-core/audits/dobetterweb/no-document-write.js +++ b/lighthouse-core/audits/dobetterweb/no-document-write.js @@ -54,16 +54,18 @@ class NoDocWriteAudit extends ViolationAudit { title: str_(UIStrings.title), failureTitle: str_(UIStrings.failureTitle), description: str_(UIStrings.description), - requiredArtifacts: ['ConsoleMessages'], + requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'ScriptElements'], }; } /** * @param {LH.Artifacts} artifacts - * @return {LH.Audit.Product} + * @param {LH.Audit.Context} context + * @return {Promise} */ - static audit(artifacts) { - const results = ViolationAudit.getViolationResults(artifacts, /document\.write/); + static async audit(artifacts, context) { + const results = + await ViolationAudit.getViolationResults(artifacts, context, /document\.write/); /** @type {LH.Audit.Details.Table['headings']} */ const headings = [ diff --git a/lighthouse-core/audits/dobetterweb/notification-on-start.js b/lighthouse-core/audits/dobetterweb/notification-on-start.js index 4959cb18010d..47577f649022 100644 --- a/lighthouse-core/audits/dobetterweb/notification-on-start.js +++ b/lighthouse-core/audits/dobetterweb/notification-on-start.js @@ -38,16 +38,18 @@ class NotificationOnStart extends ViolationAudit { failureTitle: str_(UIStrings.failureTitle), description: str_(UIStrings.description), supportedModes: ['navigation'], - requiredArtifacts: ['ConsoleMessages'], + requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'ScriptElements'], }; } /** * @param {LH.Artifacts} artifacts - * @return {LH.Audit.Product} + * @param {LH.Audit.Context} context + * @return {Promise} */ - static audit(artifacts) { - const results = ViolationAudit.getViolationResults(artifacts, /notification permission/); + static async audit(artifacts, context) { + const results = + await ViolationAudit.getViolationResults(artifacts, context, /notification permission/); /** @type {LH.Audit.Details.Table['headings']} */ const headings = [ diff --git a/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js b/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js index c5fe2a07c7b6..558ab9b0ffff 100644 --- a/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js +++ b/lighthouse-core/audits/dobetterweb/uses-passive-event-listeners.js @@ -37,16 +37,18 @@ class PassiveEventsAudit extends ViolationAudit { title: str_(UIStrings.title), failureTitle: str_(UIStrings.failureTitle), description: str_(UIStrings.description), - requiredArtifacts: ['ConsoleMessages'], + requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'ScriptElements'], }; } /** * @param {LH.Artifacts} artifacts - * @return {LH.Audit.Product} + * @param {LH.Audit.Context} context + * @return {Promise} */ - static audit(artifacts) { - const results = ViolationAudit.getViolationResults(artifacts, /passive event listener/); + static async audit(artifacts, context) { + const results = + await ViolationAudit.getViolationResults(artifacts, context, /passive event listener/); /** @type {LH.Audit.Details.Table['headings']} */ const headings = [ diff --git a/lighthouse-core/audits/errors-in-console.js b/lighthouse-core/audits/errors-in-console.js index 0f10d5ef97cc..6177d7bee434 100644 --- a/lighthouse-core/audits/errors-in-console.js +++ b/lighthouse-core/audits/errors-in-console.js @@ -12,6 +12,7 @@ const log = require('lighthouse-logger'); const Audit = require('./audit.js'); +const JsBundles = require('../computed/js-bundles.js'); const i18n = require('../lib/i18n/i18n.js'); const UIStrings = { @@ -39,7 +40,7 @@ class ErrorLogs extends Audit { title: str_(UIStrings.title), failureTitle: str_(UIStrings.failureTitle), description: str_(UIStrings.description), - requiredArtifacts: ['ConsoleMessages'], + requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'ScriptElements'], }; } @@ -75,20 +76,22 @@ class ErrorLogs extends Audit { /** * @param {LH.Artifacts} artifacts * @param {LH.Audit.Context} context - * @return {LH.Audit.Product} + * @return {Promise} */ - static audit(artifacts, context) { + static async audit(artifacts, context) { /** @type {AuditOptions} */ const auditOptions = context.options; + const bundles = await JsBundles.request(artifacts, context); /** @type {Array<{source: string, description: string|undefined, sourceLocation: LH.Audit.Details.SourceLocationValue|undefined}>} */ const consoleRows = artifacts.ConsoleMessages .filter(item => item.level === 'error') .map(item => { + const bundle = bundles.find(bundle => bundle.script.src === item.url); return { source: item.source, description: item.text, - sourceLocation: Audit.makeSourceLocationFromConsoleMessage(item), + sourceLocation: Audit.makeSourceLocationFromConsoleMessage(item, bundle), }; }); diff --git a/lighthouse-core/audits/no-unload-listeners.js b/lighthouse-core/audits/no-unload-listeners.js index 1561870d7e06..809bf9e6cc3f 100644 --- a/lighthouse-core/audits/no-unload-listeners.js +++ b/lighthouse-core/audits/no-unload-listeners.js @@ -6,6 +6,7 @@ 'use strict'; const Audit = require('./audit.js'); +const JsBundles = require('../computed/js-bundles.js'); const i18n = require('./../lib/i18n/i18n.js'); const UIStrings = { @@ -29,15 +30,16 @@ class NoUnloadListeners extends Audit { title: str_(UIStrings.title), failureTitle: str_(UIStrings.failureTitle), description: str_(UIStrings.description), - requiredArtifacts: ['GlobalListeners', 'JsUsage'], + requiredArtifacts: ['GlobalListeners', 'JsUsage', 'SourceMaps', 'ScriptElements'], }; } /** * @param {LH.Artifacts} artifacts - * @return {LH.Audit.Product} + * @param {LH.Audit.Context} context + * @return {Promise} */ - static audit(artifacts) { + static async audit(artifacts, context) { const unloadListeners = artifacts.GlobalListeners.filter(l => l.type === 'unload'); if (!unloadListeners.length) { return { @@ -45,6 +47,8 @@ class NoUnloadListeners extends Audit { }; } + const bundles = await JsBundles.request(artifacts, context); + /** @type {LH.Audit.Details.Table['headings']} */ const headings = [ {key: 'source', itemType: 'source-location', text: str_(i18n.UIStrings.columnSource)}, @@ -74,14 +78,9 @@ class NoUnloadListeners extends Audit { }; } + const bundle = bundles.find(bundle => bundle.script.src === url); return { - source: { - type: 'source-location', - url, - urlProvider: 'network', - line: listener.lineNumber, - column: listener.columnNumber, - }, + source: Audit.makeSourceLocation(url, listener.lineNumber, listener.columnNumber, bundle), }; }); diff --git a/lighthouse-core/audits/seo/font-size.js b/lighthouse-core/audits/seo/font-size.js index 0e06f0c79d85..0a212c080234 100644 --- a/lighthouse-core/audits/seo/font-size.js +++ b/lighthouse-core/audits/seo/font-size.js @@ -196,9 +196,11 @@ function findStyleRuleSource(baseURL, styleDeclaration, parentNode) { } } - const url = stylesheet.sourceURL; + const source = Audit.makeSourceLocation(stylesheet.sourceURL, line, column); + source.urlProvider = urlProvider; + return { - source: {type: 'source-location', url, urlProvider, line, column}, + source, selector, }; } diff --git a/lighthouse-core/audits/violation-audit.js b/lighthouse-core/audits/violation-audit.js index 4fd688d3d8e9..882d272e7dbe 100644 --- a/lighthouse-core/audits/violation-audit.js +++ b/lighthouse-core/audits/violation-audit.js @@ -6,14 +6,18 @@ 'use strict'; const Audit = require('./audit.js'); +const JsBundles = require('../computed/js-bundles.js'); class ViolationAudit extends Audit { /** * @param {LH.Artifacts} artifacts + * @param {LH.Audit.Context} context * @param {RegExp} pattern - * @return {Array<{source: LH.Audit.Details.SourceLocationValue}>} + * @return {Promise>} */ - static getViolationResults(artifacts, pattern) { + static async getViolationResults(artifacts, context, pattern) { + const bundles = await JsBundles.request(artifacts, context); + /** * @template T * @param {T} value @@ -26,7 +30,10 @@ class ViolationAudit extends Audit { const seen = new Set(); return artifacts.ConsoleMessages .filter(entry => entry.url && entry.source === 'violation' && pattern.test(entry.text)) - .map(Audit.makeSourceLocationFromConsoleMessage) + .map(entry => { + const bundle = bundles.find(bundle => bundle.script.src === entry.url); + return Audit.makeSourceLocationFromConsoleMessage(entry, bundle); + }) .filter(filterUndefined) .filter(source => { // Filter out duplicate entries since they are not differentiable to the user diff --git a/lighthouse-core/test/audits/deprecations-test.js b/lighthouse-core/test/audits/deprecations-test.js index 3418f588f8cf..230514d7ee9f 100644 --- a/lighthouse-core/test/audits/deprecations-test.js +++ b/lighthouse-core/test/audits/deprecations-test.js @@ -11,17 +11,21 @@ const assert = require('assert').strict; /* eslint-env jest */ describe('ConsoleMessages deprecations audit', () => { - it('passes when no console messages were found', () => { - const auditResult = DeprecationsAudit.audit({ + it('passes when no console messages were found', async () => { + const context = {computedCache: new Map()}; + const auditResult = await DeprecationsAudit.audit({ ConsoleMessages: [], InspectorIssues: {deprecations: []}, - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 1); assert.equal(auditResult.details.items.length, 0); }); - it('handles deprecations that do not have url or line numbers', () => { - const auditResult = DeprecationsAudit.audit({ + it('handles deprecations that do not have url or line numbers', async () => { + const context = {computedCache: new Map()}; + const auditResult = await DeprecationsAudit.audit({ ConsoleMessages: [ { source: 'deprecation', @@ -29,17 +33,20 @@ describe('ConsoleMessages deprecations audit', () => { }, ], InspectorIssues: {deprecations: []}, - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); expect(auditResult.displayValue).toBeDisplayString('1 warning found'); assert.equal(auditResult.details.items.length, 1); assert.equal(auditResult.details.items[0].source, undefined); }); - it('fails when deprecation messages are found (ConsoleMessages)', () => { + it('fails when deprecation messages are found (ConsoleMessages)', async () => { const URL = 'http://example.com'; - const auditResult = DeprecationsAudit.audit({ + const context = {computedCache: new Map()}; + const auditResult = await DeprecationsAudit.audit({ ConsoleMessages: [ { source: 'deprecation', @@ -59,7 +66,9 @@ describe('ConsoleMessages deprecations audit', () => { }, ], InspectorIssues: {deprecations: []}, - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); expect(auditResult.displayValue).toBeDisplayString('2 warnings found'); assert.equal(auditResult.details.items.length, 2); @@ -67,10 +76,11 @@ describe('ConsoleMessages deprecations audit', () => { assert.equal(auditResult.details.items[0].source.line, 123); }); - it('fails when deprecation messages are found', () => { + it('fails when deprecation messages are found', async () => { const URL = 'http://example.com'; - const auditResult = DeprecationsAudit.audit({ + const context = {computedCache: new Map()}; + const auditResult = await DeprecationsAudit.audit({ ConsoleMessages: [ { source: 'deprecation', @@ -99,7 +109,9 @@ describe('ConsoleMessages deprecations audit', () => { }, ], }, - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); expect(auditResult.displayValue).toBeDisplayString('2 warnings found'); diff --git a/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js b/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js index 89b134e5937e..d8790c52b316 100644 --- a/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js +++ b/lighthouse-core/test/audits/dobetterweb/geolocation-on-start-test.js @@ -11,25 +11,31 @@ const assert = require('assert').strict; /* eslint-env jest */ describe('UX: geolocation audit', () => { - it('fails when geolocation has been automatically requested', () => { + it('fails when geolocation has been automatically requested', async () => { const text = 'Do not request geolocation permission without a user action.'; - const auditResult = GeolocationOnStartAudit.audit({ + const context = {computedCache: new Map()}; + const auditResult = await GeolocationOnStartAudit.audit({ ConsoleMessages: [ {source: 'violation', url: 'https://example.com/', text}, {source: 'violation', url: 'https://example2.com/two', text}, {source: 'violation', url: 'http://abc.com/', text: 'No document.write'}, {source: 'deprecation', url: 'https://example.com/two'}, ], - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); assert.equal(auditResult.details.items.length, 2); }); - it('passes when geolocation has not been automatically requested', () => { - const auditResult = GeolocationOnStartAudit.audit({ + it('passes when geolocation has not been automatically requested', async () => { + const context = {computedCache: new Map()}; + const auditResult = await GeolocationOnStartAudit.audit({ ConsoleMessages: [], - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 1); assert.equal(auditResult.details.items.length, 0); }); diff --git a/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js b/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js index 37e721bc3812..fb73abc4f390 100644 --- a/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js +++ b/lighthouse-core/test/audits/dobetterweb/no-document-write-test.js @@ -13,18 +13,20 @@ const URL = 'https://example.com'; /* eslint-env jest */ describe('Page does not use document.write()', () => { - it('passes when document.write() is not used', () => { - const auditResult = DocWriteUseAudit.audit({ + it('passes when document.write() is not used', async () => { + const auditResult = await DocWriteUseAudit.audit({ ConsoleMessages: [], URL: {finalUrl: URL}, - }); + SourceMaps: [], + ScriptElements: [], + }, {computedCache: new Map()}); assert.equal(auditResult.score, 1); assert.equal(auditResult.details.items.length, 0); }); - it('fails when document.write() is used', () => { + it('fails when document.write() is used', async () => { const text = 'Do not use document.write'; - const auditResult = DocWriteUseAudit.audit({ + const auditResult = await DocWriteUseAudit.audit({ URL: {finalUrl: URL}, ConsoleMessages: [ {source: 'violation', url: 'https://example.com/', text}, @@ -32,7 +34,9 @@ describe('Page does not use document.write()', () => { {source: 'violation', url: 'http://abc.com/', text: 'Long event handler!'}, {source: 'deprecation', url: 'https://example.com/two'}, ], - }); + SourceMaps: [], + ScriptElements: [], + }, {computedCache: new Map()}); assert.equal(auditResult.score, 0); assert.equal(auditResult.details.items.length, 2); }); diff --git a/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js b/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js index bca4dfbe962f..b3a7bc83d2d6 100644 --- a/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js +++ b/lighthouse-core/test/audits/dobetterweb/notification-on-start-test.js @@ -11,24 +11,30 @@ const assert = require('assert').strict; /* eslint-env jest */ describe('UX: notification audit', () => { - it('fails when notification has been automatically requested', () => { + it('fails when notification has been automatically requested', async () => { const text = 'Do not request notification permission without a user action.'; - const auditResult = NotificationOnStart.audit({ + const context = {computedCache: new Map()}; + const auditResult = await NotificationOnStart.audit({ ConsoleMessages: [ {source: 'violation', url: 'https://example.com/', text}, {source: 'violation', url: 'https://example2.com/two', text}, {source: 'violation', url: 'http://abc.com/', text: 'No document.write'}, {source: 'deprecation', url: 'https://example.com/two'}, ], - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); assert.equal(auditResult.details.items.length, 2); }); - it('passes when notification has not been automatically requested', () => { - const auditResult = NotificationOnStart.audit({ + it('passes when notification has not been automatically requested', async () => { + const context = {computedCache: new Map()}; + const auditResult = await NotificationOnStart.audit({ ConsoleMessages: [], - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 1); assert.equal(auditResult.details.items.length, 0); }); diff --git a/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js b/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js index 8ef37698ff29..c39a6e77dba1 100644 --- a/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js +++ b/lighthouse-core/test/audits/dobetterweb/uses-passive-event-listeners-test.js @@ -11,10 +11,11 @@ const assert = require('assert').strict; /* eslint-env jest */ describe('Page uses passive events listeners where applicable', () => { - it('fails when scroll blocking listeners should be passive', () => { + it('fails when scroll blocking listeners should be passive', async () => { const text = 'Use passive event listeners when you do not use preventDefault'; - const auditResult = PassiveEventsAudit.audit({ + const context = {computedCache: new Map()}; + const auditResult = await PassiveEventsAudit.audit({ ConsoleMessages: [ {source: 'violation', url: 'https://example.com/', text}, {source: 'violation', url: 'https://example2.com/two', text}, @@ -22,16 +23,21 @@ describe('Page uses passive events listeners where applicable', () => { {source: 'violation', url: 'http://abc.com/', text: 'No document.write'}, {source: 'deprecation', url: 'https://example.com/two'}, ], - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); assert.equal(auditResult.details.items.length, 2); }); - it('passes scroll blocking listeners should be passive', () => { - const auditResult = PassiveEventsAudit.audit({ + it('passes scroll blocking listeners should be passive', async () => { + const context = {computedCache: new Map()}; + const auditResult = await PassiveEventsAudit.audit({ ConsoleMessages: [], - }); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 1); assert.equal(auditResult.details.items.length, 0); }); diff --git a/lighthouse-core/test/audits/errors-in-console-test.js b/lighthouse-core/test/audits/errors-in-console-test.js index c8aaf23d83c4..1160b0bc376b 100644 --- a/lighthouse-core/test/audits/errors-in-console-test.js +++ b/lighthouse-core/test/audits/errors-in-console-test.js @@ -11,17 +11,21 @@ const ErrorLogsAudit = require('../../audits/errors-in-console.js'); const assert = require('assert').strict; describe('ConsoleMessages error logs audit', () => { - it('passes when no console messages were found', () => { - const auditResult = ErrorLogsAudit.audit({ + it('passes when no console messages were found', async () => { + const context = {options: {}, computedCache: new Map()}; + const auditResult = await ErrorLogsAudit.audit({ ConsoleMessages: [], - }, {options: {}}); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 1); assert.ok(!auditResult.displayValue, 0); assert.equal(auditResult.details.items.length, 0); }); - it('filter out the non error logs', () => { - const auditResult = ErrorLogsAudit.audit({ + it('filter out the non error logs', async () => { + const context = {options: {}, computedCache: new Map()}; + const auditResult = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'info', @@ -29,13 +33,16 @@ describe('ConsoleMessages error logs audit', () => { text: 'This is a simple info msg', }, ], - }, {options: {}}); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 1); assert.equal(auditResult.details.items.length, 0); }); - it('fails when error logs are found ', () => { - const auditResult = ErrorLogsAudit.audit({ + it('fails when error logs are found ', async () => { + const context = {options: {}, computedCache: new Map()}; + const auditResult = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'error', @@ -65,7 +72,9 @@ describe('ConsoleMessages error logs audit', () => { }, }, ], - }, {options: {}}); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); assert.equal(auditResult.details.items.length, 3); @@ -83,14 +92,17 @@ describe('ConsoleMessages error logs audit', () => { 'WebSocket connection failed: Unexpected response code: 500'); }); - it('handle the case when some logs fields are undefined', () => { - const auditResult = ErrorLogsAudit.audit({ + it('handle the case when some logs fields are undefined', async () => { + const context = {options: {}, computedCache: new Map()}; + const auditResult = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'error', }, ], - }, {options: {}}); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); assert.equal(auditResult.details.items.length, 1); // sourceLocation is undefined @@ -100,8 +112,9 @@ describe('ConsoleMessages error logs audit', () => { }); // Checks bug #4188 - it('handle the case when exception info is not present', () => { - const auditResult = ErrorLogsAudit.audit({ + it('handle the case when exception info is not present', async () => { + const context = {options: {}, computedCache: new Map()}; + const auditResult = await ErrorLogsAudit.audit({ ConsoleMessages: [{ 'source': 'exception', 'level': 'error', @@ -118,7 +131,9 @@ describe('ConsoleMessages error logs audit', () => { ], }, }], - }, {options: {}}); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 0); assert.equal(auditResult.details.items.length, 1); assert.strictEqual( @@ -128,9 +143,10 @@ describe('ConsoleMessages error logs audit', () => { }); describe('options', () => { - it('does nothing with an empty pattern', () => { + it('does nothing with an empty pattern', async () => { const options = {ignoredPatterns: ''}; - const result = ErrorLogsAudit.audit({ + const context = {options, computedCache: new Map()}; + const result = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'error', @@ -138,43 +154,52 @@ describe('ConsoleMessages error logs audit', () => { text: 'This is a simple error msg', }, ], - }, {options}); + SourceMaps: [], + ScriptElements: [], + }, context); expect(result.score).toBe(0); expect(result.details.items).toHaveLength(1); }); - it('does nothing with an empty description', () => { + it('does nothing with an empty description', async () => { const options = {ignoredPatterns: 'pattern'}; - const result = ErrorLogsAudit.audit({ + const context = {options, computedCache: new Map()}; + const result = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'error', }, ], - }, {options}); + SourceMaps: [], + ScriptElements: [], + }, context); expect(result.score).toBe(0); expect(result.details.items).toHaveLength(1); }); - it('does nothing with an empty description', () => { + it('does nothing with an empty description', async () => { const options = {ignoredPatterns: 'pattern'}; - const result = ErrorLogsAudit.audit({ + const context = {options, computedCache: new Map()}; + const result = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'error', }, ], - }, {options}); + SourceMaps: [], + ScriptElements: [], + }, context); expect(result.score).toBe(0); expect(result.details.items).toHaveLength(1); }); - it('filters console messages as a string', () => { + it('filters console messages as a string', async () => { const options = {ignoredPatterns: ['simple']}; - const result = ErrorLogsAudit.audit({ + const context = {options, computedCache: new Map()}; + const result = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'error', @@ -182,15 +207,18 @@ describe('ConsoleMessages error logs audit', () => { text: 'This is a simple error msg', }, ], - }, {options}); + SourceMaps: [], + ScriptElements: [], + }, context); expect(result.score).toBe(1); expect(result.details.items).toHaveLength(0); }); - it('filters console messages as a regex', () => { + it('filters console messages as a regex', async () => { const options = {ignoredPatterns: [/simple.*msg/]}; - const result = ErrorLogsAudit.audit({ + const context = {options, computedCache: new Map()}; + const result = await ErrorLogsAudit.audit({ ConsoleMessages: [ { level: 'error', @@ -198,15 +226,18 @@ describe('ConsoleMessages error logs audit', () => { text: 'This is a simple error msg', }, ], - }, {options}); + SourceMaps: [], + ScriptElements: [], + }, context); expect(result.score).toBe(1); expect(result.details.items).toHaveLength(0); }); - it('filters exceptions with both regex and strings', () => { + it('filters exceptions with both regex and strings', async () => { const options = {ignoredPatterns: [/s.mple/i, 'really']}; - const result = ErrorLogsAudit.audit({ + const context = {options, computedCache: new Map()}; + const result = await ErrorLogsAudit.audit({ ConsoleMessages: [ { source: 'exception', @@ -221,7 +252,9 @@ describe('ConsoleMessages error logs audit', () => { text: 'Bad Error: You really messed up', }, ], - }, {options}); + SourceMaps: [], + ScriptElements: [], + }, context); expect(result.score).toBe(1); expect(result.details.items).toHaveLength(0); @@ -230,8 +263,9 @@ describe('ConsoleMessages error logs audit', () => { describe('defaultOptions', () => { // See https://github.com/GoogleChrome/lighthouse/issues/10198 - it('filters out blocked_by_client.inspector messages by default', () => { - const auditResult = ErrorLogsAudit.audit({ + it('filters out blocked_by_client.inspector messages by default', async () => { + const context = {options: ErrorLogsAudit.defaultOptions, computedCache: new Map()}; + const auditResult = await ErrorLogsAudit.audit({ ConsoleMessages: [{ 'source': 'exception', 'level': 'error', @@ -239,7 +273,9 @@ describe('ConsoleMessages error logs audit', () => { 'url': 'https://www.facebook.com/tr/', 'text': 'Failed to load resource: net::ERR_BLOCKED_BY_CLIENT.Inspector', }], - }, {options: ErrorLogsAudit.defaultOptions}); + SourceMaps: [], + ScriptElements: [], + }, context); assert.equal(auditResult.score, 1); assert.equal(auditResult.details.items.length, 0); }); diff --git a/lighthouse-core/test/audits/no-unload-listeners-test.js b/lighthouse-core/test/audits/no-unload-listeners-test.js index 7834113c4d99..6f1110c25ff2 100644 --- a/lighthouse-core/test/audits/no-unload-listeners-test.js +++ b/lighthouse-core/test/audits/no-unload-listeners-test.js @@ -25,28 +25,46 @@ const testJsUsage = { }; describe('No Unload Listeners', () => { - it('passes when there were no listeners', () => { - const artifacts = {JsUsage: testJsUsage, GlobalListeners: []}; - const result = NoUnloadListeners.audit(artifacts); + it('passes when there were no listeners', async () => { + const artifacts = { + JsUsage: testJsUsage, + GlobalListeners: [], + SourceMaps: [], + ScriptElements: [], + }; + const context = {computedCache: new Map()}; + const result = await NoUnloadListeners.audit(artifacts, context); expect(result).toEqual({score: 1}); }); - it('passes when there were no `unload` listeners', () => { + it('passes when there were no `unload` listeners', async () => { const GlobalListeners = [{ type: 'DOMContentLoaded', scriptId: '12', lineNumber: 5, columnNumber: 0, }]; - const artifacts = {JsUsage: testJsUsage, GlobalListeners}; - const result = NoUnloadListeners.audit(artifacts); + const artifacts = { + JsUsage: testJsUsage, + GlobalListeners, + SourceMaps: [], + ScriptElements: [], + }; + const context = {computedCache: new Map()}; + const result = await NoUnloadListeners.audit(artifacts, context); expect(result).toEqual({score: 1}); }); - it('fails when there are unload listeners and matches them to script locations', () => { + it('fails when there are unload listeners and matches them to script locations', async () => { const GlobalListeners = [ {type: 'unload', scriptId: '16', lineNumber: 10, columnNumber: 30}, {type: 'unload', scriptId: '23', lineNumber: 0, columnNumber: 0}, ]; - const artifacts = {JsUsage: testJsUsage, GlobalListeners}; - const result = NoUnloadListeners.audit(artifacts); + const artifacts = { + JsUsage: testJsUsage, + GlobalListeners, + SourceMaps: [], + ScriptElements: [], + }; + const context = {computedCache: new Map()}; + const result = await NoUnloadListeners.audit(artifacts, context); expect(result.score).toEqual(0); expect(result.details.items).toMatchObject([ { @@ -57,14 +75,21 @@ describe('No Unload Listeners', () => { ]); }); - it('fails when there are unload listeners and has a fallback if script URL is not found', () => { + // eslint-disable-next-line max-len + it('fails when there are unload listeners and has a fallback if script URL is not found', async () => { const GlobalListeners = [ {type: 'DOMContentLoaded', scriptId: '12', lineNumber: 5, columnNumber: 0}, {type: 'unload', scriptId: 'notascriptid', lineNumber: 10, columnNumber: 30}, {type: 'unload', scriptId: '22', lineNumber: 1, columnNumber: 100}, ]; - const artifacts = {JsUsage: testJsUsage, GlobalListeners}; - const result = NoUnloadListeners.audit(artifacts); + const artifacts = { + JsUsage: testJsUsage, + GlobalListeners, + SourceMaps: [], + ScriptElements: [], + }; + const context = {computedCache: new Map()}; + const result = await NoUnloadListeners.audit(artifacts, context); expect(result.score).toEqual(0); expect(result.details.items).toMatchObject([ { diff --git a/lighthouse-core/test/audits/seo/font-size-test.js b/lighthouse-core/test/audits/seo/font-size-test.js index 0ee9761d4c72..d6174e041733 100644 --- a/lighthouse-core/test/audits/seo/font-size-test.js +++ b/lighthouse-core/test/audits/seo/font-size-test.js @@ -335,6 +335,7 @@ describe('SEO: Font size audit', () => { urlProvider: 'network', line: 50, column: 50, + original: undefined, }); }); @@ -360,6 +361,7 @@ describe('SEO: Font size audit', () => { urlProvider: 'network', line: 15, column: 10, + original: undefined, }); }); @@ -385,6 +387,7 @@ describe('SEO: Font size audit', () => { urlProvider: 'network', line: 5, column: 15, + original: undefined, }); }); @@ -411,6 +414,7 @@ describe('SEO: Font size audit', () => { urlProvider: 'comment', line: 10, column: 10, + original: undefined, }); }); }); diff --git a/lighthouse-core/test/fraggle-rock/scenarios/api-test-pptr.js b/lighthouse-core/test/fraggle-rock/scenarios/api-test-pptr.js index b07bb67b42b2..e4b9ca06a2f3 100644 --- a/lighthouse-core/test/fraggle-rock/scenarios/api-test-pptr.js +++ b/lighthouse-core/test/fraggle-rock/scenarios/api-test-pptr.js @@ -47,7 +47,7 @@ describe('Fraggle Rock API', () => { const {auditResults, erroredAudits, failedAudits} = getAuditsBreakdown(lhr); // TODO(FR-COMPAT): This assertion can be removed when full compatibility is reached. - expect(auditResults.length).toMatchInlineSnapshot(`74`); + expect(auditResults.length).toMatchInlineSnapshot(`73`); expect(erroredAudits).toHaveLength(0); expect(failedAudits.map(audit => audit.id)).toContain('label'); diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json index 9e7a94744f9f..10b090c81fe4 100644 --- a/lighthouse-core/test/results/sample_v2.json +++ b/lighthouse-core/test/results/sample_v2.json @@ -5084,9 +5084,9 @@ "location": { "type": "source-location", "url": "http://localhost:10200/dobetterweb/third_party/aggressive-promise-polyfill.js", + "urlProvider": "network", "line": 2613, - "column": 8, - "urlProvider": "network" + "column": 8 } }, { @@ -5094,9 +5094,9 @@ "location": { "type": "source-location", "url": "http://localhost:10200/dobetterweb/third_party/aggressive-promise-polyfill.js", + "urlProvider": "network", "line": 2623, - "column": 8, - "urlProvider": "network" + "column": 8 } } ] @@ -7020,6 +7020,12 @@ "duration": 100, "entryType": "measure" }, + { + "startTime": 0, + "name": "lh:computed:JSBundles", + "duration": 100, + "entryType": "measure" + }, { "startTime": 0, "name": "lh:audit:server-response-time", @@ -7182,6 +7188,12 @@ "duration": 100, "entryType": "measure" }, + { + "startTime": 0, + "name": "lh:computed:JSBundles", + "duration": 100, + "entryType": "measure" + }, { "startTime": 0, "name": "lh:audit:mainthread-work-breakdown", @@ -7338,6 +7350,12 @@ "duration": 100, "entryType": "measure" }, + { + "startTime": 0, + "name": "lh:computed:JSBundles", + "duration": 100, + "entryType": "measure" + }, { "startTime": 0, "name": "lh:audit:non-composited-animations", diff --git a/third-party/chromium-webtests/webtests/http/tests/devtools/lighthouse/lighthouse-successful-run-expected.txt b/third-party/chromium-webtests/webtests/http/tests/devtools/lighthouse/lighthouse-successful-run-expected.txt index 6fbcfc5f46b5..8b89766094ab 100644 --- a/third-party/chromium-webtests/webtests/http/tests/devtools/lighthouse/lighthouse-successful-run-expected.txt +++ b/third-party/chromium-webtests/webtests/http/tests/devtools/lighthouse/lighthouse-successful-run-expected.txt @@ -180,6 +180,7 @@ Computing artifact: LanternMaxPotentialFID$1 Auditing: Cumulative Layout Shift Computing artifact: CumulativeLayoutShift$2 Auditing: No browser errors logged to the console +Computing artifact: JSBundles Auditing: Initial server response time was short Computing artifact: MainResource$g Auditing: Time to Interactive @@ -202,6 +203,7 @@ Auditing: Displays images with correct aspect ratio Auditing: Serves images with appropriate resolution Auditing: Fonts with `font-display: optional` are preloaded Auditing: Avoids deprecated APIs +Computing artifact: JSBundles Auditing: Minimizes main-thread work Computing artifact: MainThreadTasks$7 Auditing: JavaScript execution time