From 71bab97fcb7ee25524aadc4d2790baf22e8de31b Mon Sep 17 00:00:00 2001 From: Patrick Hulce Date: Fri, 2 Mar 2018 10:44:59 -0800 Subject: [PATCH] PROPOSAL: new structure for metrics + lantern --- .../audits/first-contentful-paint.js | 42 ++++++ lighthouse-core/audits/predictive-perf.js | 36 +---- lighthouse-core/config/config.js | 6 + lighthouse-core/config/default.js | 20 ++- lighthouse-core/config/lantern.js | 50 +++++++ .../gather/computed/computed-artifact.js | 24 +-- .../gather/computed/first-contentful-paint.js | 137 ++++++++++++++++++ .../gather/computed/network-analysis.js | 56 +++++++ .../gather/computed/page-dependency-graph.js | 11 +- .../dependency-graph/simulator/simulator.js | 13 +- lighthouse-core/runner.js | 8 +- .../gather/computed/computed-artifact-test.js | 37 ----- .../computed/page-dependency-graph-test.js | 8 +- .../simulator/simulator-test.js | 6 +- 14 files changed, 335 insertions(+), 119 deletions(-) create mode 100644 lighthouse-core/audits/first-contentful-paint.js create mode 100644 lighthouse-core/config/lantern.js create mode 100644 lighthouse-core/gather/computed/first-contentful-paint.js create mode 100644 lighthouse-core/gather/computed/network-analysis.js diff --git a/lighthouse-core/audits/first-contentful-paint.js b/lighthouse-core/audits/first-contentful-paint.js new file mode 100644 index 000000000000..90fa3d13ac37 --- /dev/null +++ b/lighthouse-core/audits/first-contentful-paint.js @@ -0,0 +1,42 @@ +/** + * @license Copyright 2016 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'); + +class FirstContentfulPaint extends Audit { + /** + * @return {!AuditMeta} + */ + static get meta() { + return { + name: 'first-contentful-paint', + description: 'First Contentful Paint', + failureDescription: 'First Contentful Paint', + helpText: 'Foo', + requiredArtifacts: ['traces', 'devtoolsLogs'], + }; + } + + /** + * @param {!Artifacts} artifacts + * @return {!AuditResult} + */ + static async audit(artifacts, context) { + const result = await artifacts.requestFirstContentfulPaint({ + trace: artifacts.traces.defaultPass, + devtoolsLog: artifacts.devtoolsLogs.defaultPass, + throttling: context.config.settings.throttling, + }) + + return { + rawValue: result.timing, + score: 100 - 100 * (result.timing / 10000), + }; + } +} + +module.exports = FirstContentfulPaint; diff --git a/lighthouse-core/audits/predictive-perf.js b/lighthouse-core/audits/predictive-perf.js index c9a6d4804e09..946e2281b5ea 100644 --- a/lighthouse-core/audits/predictive-perf.js +++ b/lighthouse-core/audits/predictive-perf.js @@ -72,40 +72,6 @@ class PredictivePerf extends Audit { return scriptUrls; } - /** - * @param {!Node} dependencyGraph - * @return {!Object} - */ - static computeRTTAndServerResponseTime(dependencyGraph) { - const records = []; - dependencyGraph.traverse(node => { - if (node.type === Node.TYPES.NETWORK) records.push(node.record); - }); - - // First pass compute the estimated observed RTT to each origin's servers. - const rttByOrigin = new Map(); - for (const [origin, summary] of NetworkAnalyzer.estimateRTTByOrigin(records).entries()) { - rttByOrigin.set(origin, summary.min); - } - - // We'll use the minimum RTT as the assumed connection latency since we care about how much addt'l - // latency each origin introduces as Lantern will be simulating with its own connection latency. - const minimumRtt = Math.min(...Array.from(rttByOrigin.values())); - // We'll use the observed RTT information to help estimate the server response time - const responseTimeSummaries = NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, { - rttByOrigin, - }); - - const additionalRttByOrigin = new Map(); - const serverResponseTimeByOrigin = new Map(); - for (const [origin, summary] of responseTimeSummaries.entries()) { - additionalRttByOrigin.set(origin, rttByOrigin.get(origin) - minimumRtt); - serverResponseTimeByOrigin.set(origin, summary.median); - } - - return {additionalRttByOrigin, serverResponseTimeByOrigin}; - } - /** * @param {!Node} dependencyGraph * @param {!TraceOfTabArtifact} traceOfTab @@ -245,7 +211,7 @@ class PredictivePerf extends Audit { const trace = artifacts.traces[Audit.DEFAULT_PASS]; const devtoolsLogs = artifacts.devtoolsLogs[Audit.DEFAULT_PASS]; return Promise.all([ - artifacts.requestPageDependencyGraph(trace, devtoolsLogs), + artifacts.requestPageDependencyGraph({trace, devtoolsLogs}), artifacts.requestTraceOfTab(trace), ]).then(([graph, traceOfTab]) => { const graphs = { diff --git a/lighthouse-core/config/config.js b/lighthouse-core/config/config.js index 3eaf8ee8c31d..52c71ec3ffa2 100644 --- a/lighthouse-core/config/config.js +++ b/lighthouse-core/config/config.js @@ -341,6 +341,7 @@ class Config { this._artifacts = expandArtifacts(configJSON.artifacts); this._categories = configJSON.categories; this._groups = configJSON.groups; + this._settings = configJSON.settings || {}; // validatePasses must follow after audits are required validatePasses(configJSON.passes, this._audits); @@ -748,6 +749,11 @@ class Config { get groups() { return this._groups; } + + /** @type {Object} */ + get settings() { + return this._settings; + } } /** diff --git a/lighthouse-core/config/default.js b/lighthouse-core/config/default.js index e2bd1306e078..bbffe29120c8 100644 --- a/lighthouse-core/config/default.js +++ b/lighthouse-core/config/default.js @@ -7,8 +7,24 @@ /* eslint-disable max-len */ +const emulation = require('../lib/emulation'); + module.exports = { - settings: {}, + settings: { + onlyAudits: ['first-contentful-paint'], + throttling: { + // method: 'devtools', + // requestLatency: emulation.settings.TYPICAL_MOBILE_THROTTLING_METRICS.latency, + // downloadThroughput: emulation.settings.TYPICAL_MOBILE_THROTTLING_METRICS.downloadThroughput, + // uploadThroughput: emulation.settings.TYPICAL_MOBILE_THROTTLING_METRICS.uploadThroughput, + + method: 'lantern', + rtt: 160, + throughput: 128 * 1000, + + cpuSlowdownMultiplier: emulation.settings.CPU_THROTTLE_METRICS.rate, + }, + }, passes: [{ passName: 'defaultPass', recordTrace: true, @@ -72,6 +88,7 @@ module.exports = { ], }], audits: [ + 'first-contentful-paint', 'is-on-https', 'redirects-http', 'service-worker', @@ -264,6 +281,7 @@ module.exports = { name: 'Performance', description: 'These encapsulate your web app\'s current performance and opportunities to improve it.', audits: [ + {id: 'first-contentful-paint', weight: 5, group: 'perf-metric'}, {id: 'first-meaningful-paint', weight: 5, group: 'perf-metric'}, {id: 'first-interactive', weight: 5, group: 'perf-metric'}, {id: 'consistently-interactive', weight: 5, group: 'perf-metric'}, diff --git a/lighthouse-core/config/lantern.js b/lighthouse-core/config/lantern.js new file mode 100644 index 000000000000..35cef6d99101 --- /dev/null +++ b/lighthouse-core/config/lantern.js @@ -0,0 +1,50 @@ +/** + * @license Copyright 2017 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'; + +module.exports = { + extends: 'lighthouse:default', + settings: { + throttling: { + method: 'lantern', + rtt: emulation.settings.TYPICAL_MOBILE_THROTTLING_METRICS.targetLatency, + throughput: emulation.settings.TYPICAL_MOBILE_THROTTLING_METRICS.targetDownloadThroughput, + cpuSlowdownMultiplier: emulation.settings.CPU_THROTTLE_METRICS.rate, + }, + skipAudits: [ + // disabled for now because their results are not meaningful/cannot be computed anymore + 'first-meaningful-paint', + 'first-interactive', + 'consistently-interactive', + 'estimated-input-latency', + 'speed-index-metric', + 'offscreen-images', + 'load-fast-enough-for-pwa', + ], + }, + passes: [ + { + passName: 'defaultPass', + // overwrite the throttling and load wait parameters + useThrottling: false, + pauseAfterLoadMs: 0, + networkQuietThresholdMs: 500, + cpuQuietThresholdMs: 500, + // no need to add any gatherers yet, but this property is required + gatherers: [], + }, + ], + audits: [ + 'predictive-perf', + ], + categories: { + performance: { + audits: [ + {id: 'predictive-perf', weight: 5, group: 'perf-metric'}, + ], + }, + }, +}; diff --git a/lighthouse-core/gather/computed/computed-artifact.js b/lighthouse-core/gather/computed/computed-artifact.js index a3812f37d6b4..bd010dd97738 100644 --- a/lighthouse-core/gather/computed/computed-artifact.js +++ b/lighthouse-core/gather/computed/computed-artifact.js @@ -20,10 +20,6 @@ class ComputedArtifact { this._allComputedArtifacts = allComputedArtifacts; } - get requiredNumberOfArtifacts() { - return 1; - } - /* eslint-disable no-unused-vars */ /** @@ -38,34 +34,20 @@ class ComputedArtifact { throw new Error('compute_() not implemented for computed artifact ' + this.name); } - /** - * Asserts that the length of the array is the same as the number of inputs the class expects - * @param {!Array<*>} artifacts - */ - _assertCorrectNumberOfArtifacts(artifacts) { - const actual = artifacts.length; - const expected = this.requiredNumberOfArtifacts; - if (actual !== expected) { - const className = this.constructor.name; - throw new Error(`${className} requires ${expected} artifacts but ${actual} were given`); - } - } - /* eslint-enable no-unused-vars */ /** * Request a computed artifact, caching the result on the input artifact. - * @param {...*} artifacts + * @param {*} artifacts * @return {!Promise<*>} */ - request(...artifacts) { - this._assertCorrectNumberOfArtifacts(artifacts); + request(artifacts) { if (this._cache.has(artifacts)) { return Promise.resolve(this._cache.get(artifacts)); } const artifactPromise = Promise.resolve() - .then(_ => this.compute_(...artifacts, this._allComputedArtifacts)); + .then(_ => this.compute_(artifacts, this._allComputedArtifacts)); this._cache.set(artifacts, artifactPromise); return artifactPromise; diff --git a/lighthouse-core/gather/computed/first-contentful-paint.js b/lighthouse-core/gather/computed/first-contentful-paint.js new file mode 100644 index 000000000000..863499be8542 --- /dev/null +++ b/lighthouse-core/gather/computed/first-contentful-paint.js @@ -0,0 +1,137 @@ +/** + * @license Copyright 2017 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 ComputedArtifact = require('./computed-artifact'); +const Node = require('../../lib/dependency-graph/node'); +const Simulator = require('../../lib/dependency-graph/simulator/simulator'); + +const COEFFICIENTS = { + intercept: 1440, + optimistic: -1.75, + pessimistic: 2.73, +}; + +class FirstContentfulPaint extends ComputedArtifact { + get name() { + return 'FirstContentfulPaint'; + } + + /** + * @param {!Node} dependencyGraph + * @param {function()=} condition + * @return {!Set} + */ + static getScriptUrls(dependencyGraph, condition) { + const scriptUrls = new Set(); + + dependencyGraph.traverse(node => { + if (node.type === Node.TYPES.CPU) return; + if (node.record._resourceType !== WebInspector.resourceTypes.Script) return; + if (condition && !condition(node)) return; + scriptUrls.add(node.record.url); + }); + + return scriptUrls; + } + + /** + * @param {!Node} dependencyGraph + * @param {!TraceOfTabArtifact} traceOfTab + * @return {!Node} + */ + static getOptimisticGraph(dependencyGraph, traceOfTab) { + const fcp = traceOfTab.timestamps.firstContentfulPaint; + const blockingScriptUrls = FirstContentfulPaint.getScriptUrls(dependencyGraph, node => { + return ( + node.endTime <= fcp && node.hasRenderBlockingPriority() && node.initiatorType !== 'script' + ); + }); + + return dependencyGraph.cloneWithRelationships(node => { + if (node.endTime > fcp) return false; + // Include EvaluateScript tasks for blocking scripts + if (node.type === Node.TYPES.CPU) return node.isEvaluateScriptFor(blockingScriptUrls); + // Include non-script-initiated network requests with a render-blocking priority + return node.hasRenderBlockingPriority() && node.initiatorType !== 'script'; + }); + } + + /** + * @param {!Node} dependencyGraph + * @param {!TraceOfTabArtifact} traceOfTab + * @return {!Node} + */ + static getPessimisticGraph(dependencyGraph, traceOfTab) { + const fcp = traceOfTab.timestamps.firstContentfulPaint; + const blockingScriptUrls = FirstContentfulPaint.getScriptUrls(dependencyGraph, node => { + return node.endTime <= fcp && node.hasRenderBlockingPriority(); + }); + + return dependencyGraph.cloneWithRelationships(node => { + if (node.endTime > fcp) return false; + // Include EvaluateScript tasks for blocking scripts + if (node.type === Node.TYPES.CPU) return node.isEvaluateScriptFor(blockingScriptUrls); + // Include all network requests that had render-blocking priority (even script-initiated) + return node.hasRenderBlockingPriority(); + }); + } + + static async computeLantern(data, artifacts) { + const {trace, devtoolsLog} = data; + const graph = await artifacts.requestPageDependencyGraph({trace, devtoolsLog}); + const traceOfTab = await artifacts.requestTraceOfTab(trace); + const networkAnalysis = await artifacts.requestNetworkAnalysis(devtoolsLog); + + const optimisticGraph = FirstContentfulPaint.getOptimisticGraph(graph, traceOfTab); + const pessimisticGraph = FirstContentfulPaint.getPessimisticGraph(graph, traceOfTab); + + const options = {...networkAnalysis, ...data.throttling}; + const optimisticEstimate = new Simulator(optimisticGraph, options).simulate().timeInMs; + const pessimisticEstimate = new Simulator(pessimisticGraph, options).simulate().timeInMs; + + const timing = + COEFFICIENTS.intercept + + COEFFICIENTS.optimistic * optimisticEstimate + + COEFFICIENTS.pessimistic * pessimisticEstimate; + + return { + timing, + optimisticEstimate, + pessimisticEstimate, + optimisticGraph, + pessimisticGraph, + }; + } + + /** + * @param {{trace: Object, devtoolsLog: Object, throttling: Object}} data + * @return {Object} + */ + async compute_(data, artifacts) { + if (data.throttling.method !== 'lantern') { + const traceOfTab = await artifacts.requestTraceOfTab(data.trace); + return { + timing: traceOfTab.timings.firstContentfulPaint, + timestamp: traceOfTab.timestamps.firstContentfulPaint, + }; + } + + return FirstContentfulPaint.computeLantern(data, artifacts); + } +} + +/** + * @typedef MetricResult + * @property {number} timing + * @property {number|undefined} timestamp + * @property {number|undefined} optimisticEstimate + * @property {number|undefined} pessimisticEstimate + * @property {!Node|undefined} optimisticGraph + * @property {!Node|undefined} pessimisticGraph + */ + +module.exports = FirstContentfulPaint; diff --git a/lighthouse-core/gather/computed/network-analysis.js b/lighthouse-core/gather/computed/network-analysis.js new file mode 100644 index 000000000000..af804b637c09 --- /dev/null +++ b/lighthouse-core/gather/computed/network-analysis.js @@ -0,0 +1,56 @@ +/** + * @license Copyright 2017 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 ComputedArtifact = require('./computed-artifact'); +const NetworkAnalyzer = require('../../lib/dependency-graph/simulator/network-analyzer'); + +class NetworkAnalysis extends ComputedArtifact { + get name() { + return 'NetworkAnalysis'; + } + + /** + * @param {!Array} records + * @return {!Object} + */ + static computeRTTAndServerResponseTime(records) { + // First pass compute the estimated observed RTT to each origin's servers. + const rttByOrigin = new Map(); + for (const [origin, summary] of NetworkAnalyzer.estimateRTTByOrigin(records).entries()) { + rttByOrigin.set(origin, summary.min); + } + + // We'll use the minimum RTT as the assumed connection latency since we care about how much addt'l + // latency each origin introduces as Lantern will be simulating with its own connection latency. + const minimumRtt = Math.min(...Array.from(rttByOrigin.values())); + // We'll use the observed RTT information to help estimate the server response time + const responseTimeSummaries = NetworkAnalyzer.estimateServerResponseTimeByOrigin(records, { + rttByOrigin, + }); + + const additionalRttByOrigin = new Map(); + const serverResponseTimeByOrigin = new Map(); + for (const [origin, summary] of responseTimeSummaries.entries()) { + additionalRttByOrigin.set(origin, rttByOrigin.get(origin) - minimumRtt); + serverResponseTimeByOrigin.set(origin, summary.median); + } + + return {rtt: minimumRtt, additionalRttByOrigin, serverResponseTimeByOrigin}; + } + + /** + * @param {Object} devtoolsLog + * @return {Object} + */ + async compute_(devtoolsLog, artifacts) { + const records = await artifacts.requestNetworkRecords(devtoolsLog); + const throughput = await artifacts.requestNetworkThroughput(devtoolsLog); + return {throughput, ...NetworkAnalysis.computeRTTAndServerResponseTime(records)}; + } +} + +module.exports = NetworkAnalysis; diff --git a/lighthouse-core/gather/computed/page-dependency-graph.js b/lighthouse-core/gather/computed/page-dependency-graph.js index 51d95cdb246f..28bcab6ed75a 100644 --- a/lighthouse-core/gather/computed/page-dependency-graph.js +++ b/lighthouse-core/gather/computed/page-dependency-graph.js @@ -22,10 +22,6 @@ class PageDependencyGraphArtifact extends ComputedArtifact { return 'PageDependencyGraph'; } - get requiredNumberOfArtifacts() { - return 2; - } - /** * @param {!WebInspector.NetworkRequest} record * @return {!Array} @@ -284,12 +280,13 @@ class PageDependencyGraphArtifact extends ComputedArtifact { } /** - * @param {!Trace} trace - * @param {!DevtoolsLog} devtoolsLog + * @param {{trace: !Trace, devtoolsLog: !DevToolsLog}} data * @param {!ComputedArtifacts} artifacts * @return {!Promise} */ - compute_(trace, devtoolsLog, artifacts) { + compute_(data, artifacts) { + const trace = data.trace; + const devtoolsLog = data.devtoolsLog; const promises = [ artifacts.requestTraceOfTab(trace), artifacts.requestNetworkRecords(devtoolsLog), diff --git a/lighthouse-core/lib/dependency-graph/simulator/simulator.js b/lighthouse-core/lib/dependency-graph/simulator/simulator.js index e7bfaf54b44e..716c041b51d7 100644 --- a/lighthouse-core/lib/dependency-graph/simulator/simulator.js +++ b/lighthouse-core/lib/dependency-graph/simulator/simulator.js @@ -22,7 +22,7 @@ const DEFAULT_THROUGHPUT = emulation.TYPICAL_MOBILE_THROTTLING_METRICS.targetDow // same multiplier as Lighthouse uses for CPU emulation const DEFAULT_CPU_TASK_MULTIPLIER = emulation.CPU_THROTTLE_METRICS.rate; // layout tasks tend to be less CPU-bound and do not experience the same increase in duration -const DEFAULT_LAYOUT_TASK_MULTIPLIER = DEFAULT_CPU_TASK_MULTIPLIER / 2; +const LAYOUT_TASK_MULTIPLIER_OF_CPU = 0.5; // if a task takes more than 10 seconds it's usually a sign it isn't actually CPU bound and we're overestimating const DEFAULT_MAXIMUM_CPU_TASK_DURATION = 10000; @@ -45,8 +45,7 @@ class Simulator { rtt: DEFAULT_RTT, throughput: DEFAULT_THROUGHPUT, maximumConcurrentRequests: DEFAULT_MAXIMUM_CONCURRENT_REQUESTS, - cpuTaskMultiplier: DEFAULT_CPU_TASK_MULTIPLIER, - layoutTaskMultiplier: DEFAULT_LAYOUT_TASK_MULTIPLIER, + cpuSlowdownMultiplier: DEFAULT_CPU_TASK_MULTIPLIER, }, options ); @@ -57,8 +56,8 @@ class Simulator { TcpConnection.maximumSaturatedConnections(this._rtt, this._throughput), this._options.maximumConcurrentRequests ); - this._cpuTaskMultiplier = this._options.cpuTaskMultiplier; - this._layoutTaskMultiplier = this._options.layoutTaskMultiplier; + this._cpuSlowdownMultiplier = this._options.cpuSlowdownMultiplier; + this._layoutTaskMultiplier = this._options.cpuSlowdownMultiplier * LAYOUT_TASK_MULTIPLIER_OF_CPU; this._nodeTiming = new Map(); this._numberInProgressByType = new Map(); @@ -206,7 +205,7 @@ class Simulator { const timingData = this._nodeTiming.get(node); const multiplier = (/** @type {CpuNode} */ (node)).didPerformLayout() ? this._layoutTaskMultiplier - : this._cpuTaskMultiplier; + : this._cpuSlowdownMultiplier; const totalDuration = Math.min( Math.round((/** @type {CpuNode} */ (node)).event.dur / 1000 * multiplier), DEFAULT_MAXIMUM_CPU_TASK_DURATION @@ -360,7 +359,7 @@ module.exports = Simulator; * @property {number} [throughput] * @property {number} [fallbackTTFB] * @property {number} [maximumConcurrentRequests] - * @property {number} [cpuTaskMultiplier] + * @property {number} [cpuSlowdownMultiplier] * @property {number} [layoutTaskMultiplier] */ diff --git a/lighthouse-core/runner.js b/lighthouse-core/runner.js index e2a9cd615add..86e5355631d4 100644 --- a/lighthouse-core/runner.js +++ b/lighthouse-core/runner.js @@ -178,7 +178,7 @@ class Runner { let promise = Promise.resolve(); for (const auditDefn of opts.config.audits) { promise = promise.then(_ => { - return Runner._runAudit(auditDefn, artifacts).then(ret => auditResults.push(ret)); + return Runner._runAudit(auditDefn, artifacts, opts.config).then(ret => auditResults.push(ret)); }); } return promise.then(_ => { @@ -203,7 +203,7 @@ class Runner { * @return {!Promise} * @private */ - static _runAudit(auditDefn, artifacts) { + static _runAudit(auditDefn, artifacts, config) { const audit = auditDefn.implementation; const status = `Evaluating: ${audit.meta.description}`; @@ -244,11 +244,11 @@ class Runner { } } // all required artifacts are in good shape, so we proceed - return audit.audit(artifacts, {options: auditDefn.options || {}}); + return audit.audit(artifacts, {config, options: auditDefn.options || {}}); // Fill remaining audit result fields. }).then(auditResult => Audit.generateAuditResult(audit, auditResult)) .catch(err => { - log.warn(audit.meta.name, `Caught exception: ${err.message}`); + log.warn(audit.meta.name, `Caught exception: ${err.stack}`); if (err.fatal) { throw err; } diff --git a/lighthouse-core/test/gather/computed/computed-artifact-test.js b/lighthouse-core/test/gather/computed/computed-artifact-test.js index c0e4e4f527e8..587d4a0bf7b3 100644 --- a/lighthouse-core/test/gather/computed/computed-artifact-test.js +++ b/lighthouse-core/test/gather/computed/computed-artifact-test.js @@ -29,24 +29,7 @@ class TestComputedArtifact extends ComputedArtifact { } } -class MultipleInputArtifact extends TestComputedArtifact { - get requiredNumberOfArtifacts() { - return 2; - } -} - describe('ComputedArtifact base class', () => { - it('tests correct number of inputs', () => { - const singleInputArtifact = new TestComputedArtifact(); - const multiInputArtifact = new MultipleInputArtifact(); - - return Promise.resolve() - .then(_ => singleInputArtifact.request(1)) - .then(_ => multiInputArtifact.request(1, 2)) - .then(_ => assert.throws(() => singleInputArtifact.request(1, 2))) - .then(_ => assert.throws(() => multiInputArtifact.request(1))); - }); - it('caches computed artifacts by strict equality', () => { const computedArtifact = new TestComputedArtifact(); @@ -61,24 +44,4 @@ describe('ComputedArtifact base class', () => { assert.equal(computedArtifact.computeCounter, 2); }); }); - - it('caches multiple input arguments', () => { - const mockComputed = {computed: true}; - const computedArtifact = new MultipleInputArtifact(mockComputed); - - const obj0 = {value: 1}; - const obj1 = {value: 2}; - const obj2 = {value: 3}; - - return computedArtifact.request(obj0, obj1) - .then(result => assert.equal(result, 0)) - .then(_ => assert.deepEqual(computedArtifact.lastArguments, [obj0, obj1, mockComputed])) - .then(_ => computedArtifact.request(obj1, obj2)) - .then(result => assert.equal(result, 1)) - .then(_ => assert.deepEqual(computedArtifact.lastArguments, [obj1, obj2, mockComputed])) - .then(_ => computedArtifact.request(obj0, obj1)) - .then(result => assert.equal(result, 0)) - .then(_ => assert.deepEqual(computedArtifact.lastArguments, [obj1, obj2, mockComputed])) - .then(_ => assert.equal(computedArtifact.computeCounter, 2)); - }); }); diff --git a/lighthouse-core/test/gather/computed/page-dependency-graph-test.js b/lighthouse-core/test/gather/computed/page-dependency-graph-test.js index 359350eaf91d..cd2a2eaff22f 100644 --- a/lighthouse-core/test/gather/computed/page-dependency-graph-test.js +++ b/lighthouse-core/test/gather/computed/page-dependency-graph-test.js @@ -55,10 +55,10 @@ describe('PageDependencyGraph computed artifact:', () => { describe('#compute_', () => { it('should compute the dependency graph', () => { - return computedArtifacts.requestPageDependencyGraph( - sampleTrace, - sampleDevtoolsLog - ).then(output => { + return computedArtifacts.requestPageDependencyGraph({ + trace: sampleTrace, + devtoolsLog: sampleDevtoolsLog + }).then(output => { assert.ok(output instanceof Node, 'did not return a graph'); const dependents = output.getDependents(); diff --git a/lighthouse-core/test/lib/dependency-graph/simulator/simulator-test.js b/lighthouse-core/test/lib/dependency-graph/simulator/simulator-test.js index a00f34647997..d616650e60f5 100644 --- a/lighthouse-core/test/lib/dependency-graph/simulator/simulator-test.js +++ b/lighthouse-core/test/lib/dependency-graph/simulator/simulator-test.js @@ -61,7 +61,7 @@ describe('DependencyGraph/Simulator', () => { const cpuNode = new CpuNode(cpuTask({duration: 200})); cpuNode.addDependency(rootNode); - const simulator = new Simulator(rootNode, {serverResponseTimeByOrigin, cpuTaskMultiplier: 5}); + const simulator = new Simulator(rootNode, {serverResponseTimeByOrigin, cpuSlowdownMultiplier: 5}); const result = simulator.simulate(); // should be 2 RTTs and 500ms for the server response time + 200 CPU assert.equal(result.timeInMs, 300 + 500 + 200); @@ -99,7 +99,7 @@ describe('DependencyGraph/Simulator', () => { nodeA.addDependent(nodeC); nodeA.addDependent(nodeD); - const simulator = new Simulator(nodeA, {serverResponseTimeByOrigin, cpuTaskMultiplier: 5}); + const simulator = new Simulator(nodeA, {serverResponseTimeByOrigin, cpuSlowdownMultiplier: 5}); const result = simulator.simulate(); // should be 800ms A, then 1000 ms total for B, C, D in serial assert.equal(result.timeInMs, 1800); @@ -123,7 +123,7 @@ describe('DependencyGraph/Simulator', () => { nodeC.addDependent(nodeD); nodeC.addDependent(nodeF); // finishes 400 ms after D - const simulator = new Simulator(nodeA, {serverResponseTimeByOrigin, cpuTaskMultiplier: 5}); + const simulator = new Simulator(nodeA, {serverResponseTimeByOrigin, cpuSlowdownMultiplier: 5}); const result = simulator.simulate(); // should be 800ms each for A, B, C, D, with F finishing 400 ms after D assert.equal(result.timeInMs, 3600);