diff --git a/lighthouse-core/audits/metrics.js b/lighthouse-core/audits/metrics.js index c2b7e51141ca..60fdab804fb5 100644 --- a/lighthouse-core/audits/metrics.js +++ b/lighthouse-core/audits/metrics.js @@ -8,6 +8,12 @@ const Audit = require('./audit.js'); const ComputedTimingSummary = require('../computed/metrics/timing-summary.js'); +/** @type {Set} */ +const DECIMAL_METRIC_KEYS = new Set([ + 'cumulativeLayoutShift', + 'observedCumulativeLayoutShift', +]); + class Metrics extends Audit { /** * @return {LH.Audit.Meta} @@ -37,7 +43,7 @@ class Metrics extends Audit { for (const [name, value] of Object.entries(metrics)) { const key = /** @type {keyof LH.Artifacts.TimingSummary} */ (name); - if (typeof value === 'number') { + if (typeof value === 'number' && !DECIMAL_METRIC_KEYS.has(key)) { metrics[key] = Math.round(value); } } diff --git a/lighthouse-core/computed/metrics/timing-summary.js b/lighthouse-core/computed/metrics/timing-summary.js index c6595db6bdca..7cfabd9bbfca 100644 --- a/lighthouse-core/computed/metrics/timing-summary.js +++ b/lighthouse-core/computed/metrics/timing-summary.js @@ -52,6 +52,10 @@ class TimingSummary { const estimatedInputLatency = await EstimatedInputLatency.request(metricComputationData, context); // eslint-disable-line max-len const totalBlockingTime = await TotalBlockingTime.request(metricComputationData, context); // eslint-disable-line max-len + const cumulativeLayoutShiftValue = cumulativeLayoutShift && + cumulativeLayoutShift.value !== null ? + cumulativeLayoutShift.value : undefined; + /** @type {LH.Artifacts.TimingSummary} */ const metrics = { // Include the simulated/observed performance metrics @@ -71,8 +75,7 @@ class TimingSummary { estimatedInputLatencyTs: estimatedInputLatency.timestamp, totalBlockingTime: totalBlockingTime.timing, maxPotentialFID: maxPotentialFID && maxPotentialFID.timing, - cumulativeLayoutShift: cumulativeLayoutShift && cumulativeLayoutShift.value !== null ? - cumulativeLayoutShift.value : undefined, + cumulativeLayoutShift: cumulativeLayoutShiftValue, // Include all timestamps of interest from trace of tab observedNavigationStart: traceOfTab.timings.navigationStart, @@ -91,8 +94,7 @@ class TimingSummary { observedLoadTs: traceOfTab.timestamps.load, observedDomContentLoaded: traceOfTab.timings.domContentLoaded, observedDomContentLoadedTs: traceOfTab.timestamps.domContentLoaded, - observedCumulativeLayoutShift: traceOfTab.timings.cumulativeLayoutShift, - observedCumulativeLayoutShiftTs: traceOfTab.timestamps.cumulativeLayoutShift, + observedCumulativeLayoutShift: cumulativeLayoutShiftValue, // Include some visual metrics from speedline observedFirstVisualChange: speedline.first, diff --git a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap index 713bbe68a597..b972dc3354cd 100644 --- a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap +++ b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap @@ -16,8 +16,7 @@ Object { "largestContentfulPaint": 2758, "largestContentfulPaintTs": undefined, "maxPotentialFID": 1336, - "observedCumulativeLayoutShift": undefined, - "observedCumulativeLayoutShiftTs": undefined, + "observedCumulativeLayoutShift": 0, "observedDomContentLoaded": 1513, "observedDomContentLoadedTs": 713038536140, "observedFirstContentfulPaint": 1122, @@ -46,6 +45,51 @@ Object { } `; +exports[`Performance: metrics evaluates valid input correctly (throttlingMethod=provided) 1`] = ` +Object { + "cumulativeLayoutShift": 0, + "estimatedInputLatency": 17, + "estimatedInputLatencyTs": undefined, + "firstCPUIdle": 1582, + "firstCPUIdleTs": 225415754204, + "firstContentfulPaint": 499, + "firstContentfulPaintTs": 225414670885, + "firstMeaningfulPaint": 783, + "firstMeaningfulPaintTs": 225414955343, + "interactive": 1582, + "interactiveTs": 225415754204, + "largestContentfulPaint": undefined, + "largestContentfulPaintTs": undefined, + "maxPotentialFID": 198, + "observedCumulativeLayoutShift": 0, + "observedDomContentLoaded": 560, + "observedDomContentLoadedTs": 225414732309, + "observedFirstContentfulPaint": 499, + "observedFirstContentfulPaintTs": 225414670885, + "observedFirstMeaningfulPaint": 783, + "observedFirstMeaningfulPaintTs": 225414955343, + "observedFirstPaint": 499, + "observedFirstPaintTs": 225414670868, + "observedFirstVisualChange": 520, + "observedFirstVisualChangeTs": 225414692015, + "observedLargestContentfulPaint": undefined, + "observedLargestContentfulPaintTs": undefined, + "observedLastVisualChange": 818, + "observedLastVisualChangeTs": 225414990015, + "observedLoad": 2199, + "observedLoadTs": 225416370913, + "observedNavigationStart": 0, + "observedNavigationStartTs": 225414172015, + "observedSpeedIndex": 605, + "observedSpeedIndexTs": 225414776724, + "observedTraceEnd": 12540, + "observedTraceEndTs": 225426711887, + "speedIndex": 605, + "speedIndexTs": 225414777015, + "totalBlockingTime": 48, +} +`; + exports[`Performance: metrics evaluates valid input correctly 1`] = ` Object { "cumulativeLayoutShift": 0, @@ -62,8 +106,7 @@ Object { "largestContentfulPaint": undefined, "largestContentfulPaintTs": undefined, "maxPotentialFID": 396, - "observedCumulativeLayoutShift": undefined, - "observedCumulativeLayoutShiftTs": undefined, + "observedCumulativeLayoutShift": 0, "observedDomContentLoaded": 560, "observedDomContentLoadedTs": 225414732309, "observedFirstContentfulPaint": 499, diff --git a/lighthouse-core/test/audits/metrics-test.js b/lighthouse-core/test/audits/metrics-test.js index 964e67050a9f..fc47ac7b0d45 100644 --- a/lighthouse-core/test/audits/metrics-test.js +++ b/lighthouse-core/test/audits/metrics-test.js @@ -14,6 +14,9 @@ const pwaDevtoolsLog = require('../fixtures/traces/progressive-app-m60.devtools. const lcpTrace = require('../fixtures/traces/lcp-m78.json'); const lcpDevtoolsLog = require('../fixtures/traces/lcp-m78.devtools.log.json'); +const artifactsTrace = require('../results/artifacts/defaultPass.trace.json'); +const artifactsDevtoolsLog = require('../results/artifacts/defaultPass.devtoolslog.json'); + /* eslint-env jest */ describe('Performance: metrics', () => { @@ -32,6 +35,21 @@ describe('Performance: metrics', () => { expect(result.details.items[0]).toMatchSnapshot(); }); + it('evaluates valid input correctly (throttlingMethod=provided)', async () => { + const artifacts = { + traces: { + [MetricsAudit.DEFAULT_PASS]: pwaTrace, + }, + devtoolsLogs: { + [MetricsAudit.DEFAULT_PASS]: pwaDevtoolsLog, + }, + }; + + const context = {settings: {throttlingMethod: 'provided'}, computedCache: new Map()}; + const result = await MetricsAudit.audit(artifacts, context); + expect(result.details.items[0]).toMatchSnapshot(); + }); + it('evaluates valid input (with lcp) correctly', async () => { const artifacts = { traces: { @@ -47,6 +65,22 @@ describe('Performance: metrics', () => { expect(result.details.items[0]).toMatchSnapshot(); }); + it('evaluates valid input (with CLS) correctly', async () => { + const artifacts = { + traces: { + [MetricsAudit.DEFAULT_PASS]: artifactsTrace, + }, + devtoolsLogs: { + [MetricsAudit.DEFAULT_PASS]: artifactsDevtoolsLog, + }, + }; + + const context = {settings: {throttlingMethod: 'simulate'}, computedCache: new Map()}; + const {details} = await MetricsAudit.audit(artifacts, context); + expect(details.items[0].cumulativeLayoutShift).toMatchInlineSnapshot(`0.42`); + expect(details.items[0].observedCumulativeLayoutShift).toMatchInlineSnapshot(`0.42`); + }); + it('does not fail the entire audit when TTI errors', async () => { const artifacts = { traces: { diff --git a/lighthouse-core/test/computed/metrics/timing-summary-test.js b/lighthouse-core/test/computed/metrics/timing-summary-test.js index 0eed25b006f3..25d4f5c5ce43 100644 --- a/lighthouse-core/test/computed/metrics/timing-summary-test.js +++ b/lighthouse-core/test/computed/metrics/timing-summary-test.js @@ -32,8 +32,7 @@ describe('Timing summary', () => { "largestContentfulPaint": undefined, "largestContentfulPaintTs": undefined, "maxPotentialFID": 396.0000000000001, - "observedCumulativeLayoutShift": undefined, - "observedCumulativeLayoutShiftTs": undefined, + "observedCumulativeLayoutShift": 0, "observedDomContentLoaded": 560.294, "observedDomContentLoadedTs": 225414732309, "observedFirstContentfulPaint": 498.87, diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json index bea282eb23fd..accb3e77cf24 100644 --- a/lighthouse-core/test/results/sample_v2.json +++ b/lighthouse-core/test/results/sample_v2.json @@ -1380,7 +1380,7 @@ "estimatedInputLatency": 16, "totalBlockingTime": 117, "maxPotentialFID": 123, - "cumulativeLayoutShift": 0, + "cumulativeLayoutShift": 0.42, "observedNavigationStart": 0, "observedNavigationStartTs": 185603319912, "observedFirstPaint": 3969, @@ -1397,6 +1397,7 @@ "observedLoadTs": 185608244374, "observedDomContentLoaded": 4901, "observedDomContentLoadedTs": 185608220734, + "observedCumulativeLayoutShift": 0.42, "observedFirstVisualChange": 3969, "observedFirstVisualChangeTs": 185607288912, "observedLastVisualChange": 4791, diff --git a/types/artifacts.d.ts b/types/artifacts.d.ts index e188b2475c87..89d199249ed4 100644 --- a/types/artifacts.d.ts +++ b/types/artifacts.d.ts @@ -563,7 +563,6 @@ declare global { traceEnd: number; load?: number; domContentLoaded?: number; - cumulativeLayoutShift?: number; } export interface TraceOfTab { @@ -637,7 +636,6 @@ declare global { observedNavigationStart: number; observedNavigationStartTs: number; observedCumulativeLayoutShift: number | undefined; - observedCumulativeLayoutShiftTs: number | undefined; observedFirstPaint: number | undefined; observedFirstPaintTs: number | undefined; observedFirstContentfulPaint: number;