Skip to content
Open
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
28 changes: 27 additions & 1 deletion core/computed/metrics/lantern-largest-contentful-paint.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,25 @@ import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js
import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js';

class LanternLargestContentfulPaint extends Lantern.Metrics.LargestContentfulPaint {
static disableFcpShortCircuiting = false;

/**
* @param {LH.Artifacts.MetricComputationDataInput} data
* @param {LH.Artifacts.ComputedContext} context
* @param {Omit<Lantern.Metrics.Extras, 'optimistic'>=} extras
* @param {Required<Pick<Lantern.Metrics.Extras, 'fcpResult'>>} extras
* @return {Promise<LH.Artifacts.LanternMetric>}
*/
static async computeMetricWithGraphs(data, context, extras) {
const params = await getComputationDataParams(data, context);
// If FCP and LCP happened within the same frame, we can assume their simulated values
// are also the same.
if (
params.processedNavigation.timestamps.firstContentfulPaint ===
params.processedNavigation.timestamps.largestContentfulPaint &&
!this.disableFcpShortCircuiting
) {
return extras.fcpResult;
}
return Promise.resolve(this.compute(params, extras)).catch(lanternErrorAdapter);
}

Expand All @@ -30,6 +41,21 @@ class LanternLargestContentfulPaint extends Lantern.Metrics.LargestContentfulPai
const fcpResult = await LanternFirstContentfulPaint.request(data, context);
return this.computeMetricWithGraphs(data, context, {fcpResult});
}

/**
* Designed to be used solely in tests.
*
* @param {() => Promise<LH.Artifacts.LanternMetric>} callback
* @return {Promise<LH.Artifacts.LanternMetric>}
*/
static async withFcpShortCircuitDisabled(callback) {
this.disableFcpShortCircuiting = true;
try {
return await callback();
} finally {
this.disableFcpShortCircuiting = false;
}
}
}

const LanternLargestContentfulPaintComputed = makeComputedArtifact(
Expand Down
4 changes: 2 additions & 2 deletions core/test/audits/__snapshots__/metrics-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Object {
"firstContentfulPaintTs": undefined,
"interactive": 3149,
"interactiveTs": undefined,
"largestContentfulPaint": 1524,
"largestContentfulPaint": 1059,
"largestContentfulPaintAllFrames": undefined,
"largestContentfulPaintAllFramesTs": undefined,
"largestContentfulPaintTs": undefined,
Expand Down Expand Up @@ -118,7 +118,7 @@ Object {
"firstContentfulPaintTs": undefined,
"interactive": 3149,
"interactiveTs": undefined,
"largestContentfulPaint": 1524,
"largestContentfulPaint": 1059,
"largestContentfulPaintAllFrames": undefined,
"largestContentfulPaintAllFramesTs": undefined,
"largestContentfulPaintTs": undefined,
Expand Down
6 changes: 3 additions & 3 deletions core/test/audits/__snapshots__/predictive-perf-test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
exports[`Performance: predictive performance audit should compute the predicted values 1`] = `
Object {
"optimisticFCP": 1059,
"optimisticLCP": 1445,
"optimisticLCP": 1059,
"optimisticSI": 261,
"optimisticTTI": 2132,
"pessimisticFCP": 1059,
"pessimisticLCP": 1603,
"pessimisticLCP": 1059,
"pessimisticSI": 1109,
"pessimisticTTI": 3981,
"roughEstimateOfFCP": 1059,
"roughEstimateOfLCP": 1524,
"roughEstimateOfLCP": 1059,
"roughEstimateOfLCPLoadEnd": undefined,
"roughEstimateOfLCPLoadStart": undefined,
"roughEstimateOfSI": 1059,
Expand Down
12 changes: 6 additions & 6 deletions core/test/audits/byte-efficiency/byte-efficiency-audit-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ describe('Byte efficiency base audit', () => {
{computedCache: new Map()}
);

assert.equal(result.numericValue, 160);
assert.equal(result.numericValue, 0);
});

it('should create load simulator with the specified settings', async () => {
Expand Down Expand Up @@ -263,14 +263,14 @@ describe('Byte efficiency base audit', () => {
let settings = {throttlingMethod: 'simulate', throttling: modestThrottling};
let result = await MockAudit.audit(artifacts, {settings, computedCache});
// expect modest savings
expect(result.numericValue).toBeLessThan(5000);
expect(result.numericValue).toMatchInlineSnapshot(`1220`);
expect(result.numericValue).toBeLessThan(500);
expect(result.numericValue).toMatchInlineSnapshot(`160`);

settings = {throttlingMethod: 'simulate', throttling: ultraSlowThrottling};
result = await MockAudit.audit(artifacts, {settings, computedCache});
// expect lots of savings
expect(result.numericValue).not.toBeLessThan(5000);
expect(result.numericValue).toMatchInlineSnapshot(`13580`);
// expect more savings
expect(result.numericValue).not.toBeLessThan(500);
expect(result.numericValue).toMatchInlineSnapshot(`1740`);
});

it('should compute savings with throughput in timespan mode', async () => {
Expand Down
44 changes: 41 additions & 3 deletions core/test/computed/metrics/largest-contentful-paint-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {LanternLargestContentfulPaint} from '../../../computed/metrics/lantern-largest-contentful-paint.js';
import {LargestContentfulPaint} from '../../../computed/metrics/largest-contentful-paint.js';
import {getURLArtifactFromDevtoolsLog, readJson} from '../../test-utils.js';

Expand Down Expand Up @@ -31,9 +32,9 @@ describe('Metrics: LCP', () => {
pessimistic: Math.round(result.pessimisticEstimate.timeInMs)}).
toMatchInlineSnapshot(`
Object {
"optimistic": 1445,
"pessimistic": 1603,
"timing": 1524,
"optimistic": 1059,
"pessimistic": 1059,
"timing": 1059,
}
`);
});
Expand All @@ -52,4 +53,41 @@ Object {
}
`);
});

it(
'when simulating, should return the FCP result ' +
'when original FCP and LCP timestamps are the same',
async () => {
const settings = {throttlingMethod: 'simulate'};
const URL = getURLArtifactFromDevtoolsLog(devtoolsLog);

const simulatedLcpOnlyResult =
await LanternLargestContentfulPaint.withFcpShortCircuitDisabled(() =>
LanternLargestContentfulPaint.request({
trace,
devtoolsLog,
gatherContext,
settings,
URL,
SourceMaps: [],
simulator: null,
}, {settings, computedCache: new Map()})
);

const simulatedLcpWithFcpResult = await LargestContentfulPaint.request({
trace,
devtoolsLog,
gatherContext,
settings,
URL,
SourceMaps: [],
simulator: null,
}, {settings, computedCache: new Map()});

expect(simulatedLcpOnlyResult.timing).not.toBe(simulatedLcpWithFcpResult.timing);
expect(simulatedLcpOnlyResult.optimisticEstimate.timeInMs)
.not.toBe(simulatedLcpWithFcpResult.optimisticEstimate.timeInMs);
expect(simulatedLcpOnlyResult.pessimisticEstimate.timeInMs)
.not.toBe(simulatedLcpWithFcpResult.pessimisticEstimate.timeInMs);
});
});