From ae8eb005e694c2c261507deb9a47b8485452f315 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Tue, 1 Dec 2020 18:43:34 -0500 Subject: [PATCH 01/13] start --- .../first-contentful-paint-all-frames.js | 33 +++++++++++++++ .../computed/metrics/timing-summary.js | 6 +++ lighthouse-core/computed/trace-of-tab.js | 38 ++++++++++++++--- .../lib/tracehouse/trace-processor.js | 12 +++++- .../first-contentful-paint-all-frames-test.js | 41 +++++++++++++++++++ .../test/computed/trace-of-tab-test.js | 15 +++++++ types/artifacts.d.ts | 7 ++++ 7 files changed, 144 insertions(+), 8 deletions(-) create mode 100644 lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js create mode 100644 lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js diff --git a/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js new file mode 100644 index 000000000000..8137ac5e92a0 --- /dev/null +++ b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js @@ -0,0 +1,33 @@ +/** + * @license Copyright 2020 The Lighthouse Authors. 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 makeComputedArtifact = require('../computed-artifact.js'); +const ComputedMetric = require('./metric.js'); + +class FirstContentfulPaintAllFrames extends ComputedMetric { + /** + * @return {Promise} + */ + static computeSimulatedMetric() { + throw new Error('FCP All Frames not implemented in lantern.'); + } + + /** + * @param {LH.Artifacts.MetricComputationData} data + * @return {Promise} + */ + static async computeObservedMetric(data) { + const {traceOfTab} = data; + + return { + timing: traceOfTab.timings.firstContentfulPaintAllFrames, + timestamp: traceOfTab.timestamps.firstContentfulPaintAllFrames, + }; + } +} + +module.exports = makeComputedArtifact(FirstContentfulPaintAllFrames); diff --git a/lighthouse-core/computed/metrics/timing-summary.js b/lighthouse-core/computed/metrics/timing-summary.js index f796abd53816..7212be69b873 100644 --- a/lighthouse-core/computed/metrics/timing-summary.js +++ b/lighthouse-core/computed/metrics/timing-summary.js @@ -8,6 +8,7 @@ const TraceOfTab = require('../trace-of-tab.js'); const Speedline = require('../speedline.js'); const FirstContentfulPaint = require('./first-contentful-paint.js'); +const FirstContentfulPaintAllFrames = require('./first-contentful-paint-all-frames.js'); const FirstMeaningfulPaint = require('./first-meaningful-paint.js'); const LargestContentfulPaint = require('./largest-contentful-paint.js'); const LargestContentfulPaintAllFrames = require('./largest-contentful-paint-all-frames.js'); @@ -44,6 +45,7 @@ class TimingSummary { const traceOfTab = await TraceOfTab.request(trace, context); const speedline = await Speedline.request(trace, context); const firstContentfulPaint = await FirstContentfulPaint.request(metricComputationData, context); + const firstContentfulPaintAllFrames = await FirstContentfulPaintAllFrames.request(metricComputationData, context); // eslint-disable-line max-len const firstMeaningfulPaint = await FirstMeaningfulPaint.request(metricComputationData, context); const largestContentfulPaint = await requestOrUndefined(LargestContentfulPaint, metricComputationData); // eslint-disable-line max-len const largestContentfulPaintAllFrames = await requestOrUndefined(LargestContentfulPaintAllFrames, metricComputationData); // eslint-disable-line max-len @@ -67,6 +69,8 @@ class TimingSummary { // Include the simulated/observed performance metrics firstContentfulPaint: firstContentfulPaint.timing, firstContentfulPaintTs: firstContentfulPaint.timestamp, + firstContentfulPaintAllFrames: firstContentfulPaintAllFrames.timing, + firstContentfulPaintAllFramesTs: firstContentfulPaintAllFrames.timestamp, firstMeaningfulPaint: firstMeaningfulPaint.timing, firstMeaningfulPaintTs: firstMeaningfulPaint.timestamp, largestContentfulPaint: largestContentfulPaint && largestContentfulPaint.timing, @@ -97,6 +101,8 @@ class TimingSummary { observedFirstPaintTs: traceOfTab.timestamps.firstPaint, observedFirstContentfulPaint: traceOfTab.timings.firstContentfulPaint, observedFirstContentfulPaintTs: traceOfTab.timestamps.firstContentfulPaint, + observedFirstContentfulPaintAllFrames: traceOfTab.timings.firstContentfulPaintAllFrames, + observedFirstContentfulPaintAllFramesTs: traceOfTab.timestamps.firstContentfulPaintAllFrames, observedFirstMeaningfulPaint: traceOfTab.timings.firstMeaningfulPaint, observedFirstMeaningfulPaintTs: traceOfTab.timestamps.firstMeaningfulPaint, observedLargestContentfulPaint: traceOfTab.timings.largestContentfulPaint, diff --git a/lighthouse-core/computed/trace-of-tab.js b/lighthouse-core/computed/trace-of-tab.js index eb63b974292b..4f30851c1566 100644 --- a/lighthouse-core/computed/trace-of-tab.js +++ b/lighthouse-core/computed/trace-of-tab.js @@ -50,13 +50,30 @@ class TraceOfTab { // We'll check that we got an FCP here and re-type accordingly so all of our consumers don't // have to repeat this check. const traceOfTab = await LHTraceProcessor.computeTraceOfTab(trace); - const {timings, timestamps, firstContentfulPaintEvt} = traceOfTab; - const {firstContentfulPaint: firstContentfulPaintTiming} = timings; - const {firstContentfulPaint: firstContentfulPaintTs} = timestamps; + const { + timings, + timestamps, + firstContentfulPaintEvt, + firstContentfulPaintAllFramesEvt, + } = traceOfTab; + const { + firstContentfulPaint: firstContentfulPaintTiming, + firstContentfulPaintAllFrames: firstContentfulPaintAllFramesTiming, + } = timings; + const { + firstContentfulPaint: firstContentfulPaintTs, + firstContentfulPaintAllFrames: firstContentfulPaintAllFramesTs, + } = timestamps; + if ( !firstContentfulPaintEvt || firstContentfulPaintTiming === undefined || - firstContentfulPaintTs === undefined + firstContentfulPaintTs === undefined || + // FCP-AF will only be undefined if FCP is also undefined. + // These conditions are for enforcing types and should never actually trigger. + !firstContentfulPaintAllFramesEvt || + firstContentfulPaintAllFramesTiming === undefined || + firstContentfulPaintAllFramesTs === undefined ) { throw new LHError(LHError.errors.NO_FCP); } @@ -66,8 +83,17 @@ class TraceOfTab { return { ...traceOfTab, firstContentfulPaintEvt, - timings: {...timings, firstContentfulPaint: firstContentfulPaintTiming}, - timestamps: {...timestamps, firstContentfulPaint: firstContentfulPaintTs}, + firstContentfulPaintAllFramesEvt, + timings: { + ...timings, + firstContentfulPaint: firstContentfulPaintTiming, + firstContentfulPaintAllFrames: firstContentfulPaintAllFramesTiming, + }, + timestamps: { + ...timestamps, + firstContentfulPaint: firstContentfulPaintTs, + firstContentfulPaintAllFrames: firstContentfulPaintAllFramesTs, + }, }; } } diff --git a/lighthouse-core/lib/tracehouse/trace-processor.js b/lighthouse-core/lib/tracehouse/trace-processor.js index 3eabb68f38fa..b10a95f65593 100644 --- a/lighthouse-core/lib/tracehouse/trace-processor.js +++ b/lighthouse-core/lib/tracehouse/trace-processor.js @@ -16,9 +16,9 @@ * 4. Return all those items in one handy bundle. */ -/** @typedef {Omit & {firstContentfulPaint?: number}} TraceTimesWithoutFCP */ +/** @typedef {Omit & {firstContentfulPaint?: number, firstContentfulPaintAllFrames?: number}} TraceTimesWithoutFCP */ /** @typedef {Omit} TraceTimesWithoutFCPAndTraceEnd */ -/** @typedef {Omit & {timings: TraceTimesWithoutFCP, timestamps: TraceTimesWithoutFCP, firstContentfulPaintEvt?: LH.Artifacts.TraceOfTab['firstContentfulPaintEvt']}} TraceOfTabWithoutFCP */ +/** @typedef {Omit & {timings: TraceTimesWithoutFCP, timestamps: TraceTimesWithoutFCP, firstContentfulPaintEvt?: LH.Artifacts.TraceOfTab['firstContentfulPaintEvt'], firstContentfulPaintAllFramesEvt?: LH.Artifacts.TraceOfTab['largestContentfulPaintAllFramesEvt']}} TraceOfTabWithoutFCP */ /** @typedef {'lastNavigationStart'|'firstResourceSendRequest'} TimeOriginDeterminationMethod */ const log = require('lighthouse-logger'); @@ -545,6 +545,11 @@ class TraceProcessor { // Compute the key frame timings for the main frame. const frameTimings = this.computeKeyTimingsForFrame(frameEvents, {timeOriginEvt}); + // Compute FCP for all frames. + const fcpAllFramesEvt = keyEvents.find( + e => e.name === 'firstContentfulPaint' && e.ts > timeOriginEvt.ts + ); + // Compute LCP for all frames. const lcpAllFramesEvt = this.computeValidLCP({ candidateEventName: 'NavStartToLargestContentfulPaint::Candidate::AllFrames::UKM', @@ -584,6 +589,7 @@ class TraceProcessor { timeOrigin: frameTimings.timings.timeOrigin, firstPaint: frameTimings.timings.firstPaint, firstContentfulPaint: frameTimings.timings.firstContentfulPaint, + firstContentfulPaintAllFrames: maybeGetTiming(fcpAllFramesEvt && fcpAllFramesEvt.ts), firstMeaningfulPaint: frameTimings.timings.firstMeaningfulPaint, largestContentfulPaint: frameTimings.timings.largestContentfulPaint, largestContentfulPaintAllFrames: maybeGetTiming(lcpAllFramesEvt && lcpAllFramesEvt.ts), @@ -595,6 +601,7 @@ class TraceProcessor { timeOrigin: frameTimings.timestamps.timeOrigin, firstPaint: frameTimings.timestamps.firstPaint, firstContentfulPaint: frameTimings.timestamps.firstContentfulPaint, + firstContentfulPaintAllFrames: fcpAllFramesEvt && fcpAllFramesEvt.ts, firstMeaningfulPaint: frameTimings.timestamps.firstMeaningfulPaint, largestContentfulPaint: frameTimings.timestamps.largestContentfulPaint, largestContentfulPaintAllFrames: lcpAllFramesEvt && lcpAllFramesEvt.ts, @@ -605,6 +612,7 @@ class TraceProcessor { timeOriginEvt: frameTimings.timeOriginEvt, firstPaintEvt: frameTimings.firstPaintEvt, firstContentfulPaintEvt: frameTimings.firstContentfulPaintEvt, + firstContentfulPaintAllFramesEvt: fcpAllFramesEvt, firstMeaningfulPaintEvt: frameTimings.firstMeaningfulPaintEvt, largestContentfulPaintEvt: frameTimings.largestContentfulPaintEvt, largestContentfulPaintAllFramesEvt: lcpAllFramesEvt, diff --git a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js new file mode 100644 index 000000000000..26ec3ba962f6 --- /dev/null +++ b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js @@ -0,0 +1,41 @@ +/** + * @license Copyright 2018 The Lighthouse Authors. 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 FirstContentfulPaintAllFrames = require('../../../computed/metrics/first-contentful-paint-all-frames.js'); // eslint-disable-line max-len +const trace = require('../../fixtures/traces/frame-metrics-m89.json'); +const devtoolsLog = require('../../fixtures/traces/frame-metrics-m89.devtools.log.json'); + +/* eslint-env jest */ + +describe('Metrics: FCP all frames', () => { + it('should error for a simulated value', async () => { + const settings = {throttlingMethod: 'simulate'}; + const context = {settings, computedCache: new Map()}; + const resultPromise = FirstContentfulPaintAllFrames.request( + {trace, devtoolsLog, settings}, + context + ); + + await expect(resultPromise).rejects.toThrow(); + }); + + it('should compute FCP-AF separate from FCP', async () => { + const settings = {throttlingMethod: 'provided'}; + const context = {settings, computedCache: new Map()}; + const result = await FirstContentfulPaintAllFrames.request( + {trace, devtoolsLog, settings}, + context + ); + + expect(result).toEqual( + { + timestamp: 46134430620, + timing: 688.13, + } + ); + }); +}); diff --git a/lighthouse-core/test/computed/trace-of-tab-test.js b/lighthouse-core/test/computed/trace-of-tab-test.js index a87f6c48b789..44c538fd5156 100644 --- a/lighthouse-core/test/computed/trace-of-tab-test.js +++ b/lighthouse-core/test/computed/trace-of-tab-test.js @@ -49,6 +49,19 @@ describe('TraceOfTabComputed', () => { ts: 225414670885, tts: 866570, }, + firstContentfulPaintAllFramesEvt: { + args: { + frame: '0x25a638821e30', + }, + cat: 'loading,rail,devtools.timeline', + name: 'firstContentfulPaint', + ph: 'I', + pid: 44277, + s: 'p', + tid: 775, + ts: 225414670885, + tts: 866570, + }, firstMeaningfulPaintEvt: { args: { frame: '0x25a638821e30', @@ -109,6 +122,7 @@ describe('TraceOfTabComputed', () => { timestamps: { domContentLoaded: 225414732309, firstContentfulPaint: 225414670885, + firstContentfulPaintAllFrames: 225414670885, firstMeaningfulPaint: 225414955343, firstPaint: 225414670868, load: 225416370913, @@ -118,6 +132,7 @@ describe('TraceOfTabComputed', () => { timings: { domContentLoaded: 560.294, firstContentfulPaint: 498.87, + firstContentfulPaintAllFrames: 498.87, firstMeaningfulPaint: 783.328, firstPaint: 498.853, load: 2198.898, diff --git a/types/artifacts.d.ts b/types/artifacts.d.ts index 9db440524d6a..a75816ee4b7a 100644 --- a/types/artifacts.d.ts +++ b/types/artifacts.d.ts @@ -596,6 +596,7 @@ declare global { timeOrigin: number; firstPaint?: number; firstContentfulPaint: number; + firstContentfulPaintAllFrames: number; firstMeaningfulPaint?: number; largestContentfulPaint?: number; largestContentfulPaintAllFrames?: number; @@ -623,6 +624,8 @@ declare global { firstPaintEvt?: TraceEvent; /** The trace event marking firstContentfulPaint, if it was found. */ firstContentfulPaintEvt: TraceEvent; + /** The trace event marking firstContentfulPaint from all frames, if it was found. */ + firstContentfulPaintAllFramesEvt: TraceEvent; /** The trace event marking firstMeaningfulPaint, if it was found. */ firstMeaningfulPaintEvt?: TraceEvent; /** The trace event marking largestContentfulPaint, if it was found. */ @@ -669,6 +672,8 @@ declare global { export interface TimingSummary { firstContentfulPaint: number; firstContentfulPaintTs: number | undefined; + firstContentfulPaintAllFrames: number; + firstContentfulPaintAllFramesTs: number | undefined; firstMeaningfulPaint: number; firstMeaningfulPaintTs: number | undefined; largestContentfulPaint: number | undefined; @@ -697,6 +702,8 @@ declare global { observedFirstPaintTs: number | undefined; observedFirstContentfulPaint: number; observedFirstContentfulPaintTs: number; + observedFirstContentfulPaintAllFrames: number; + observedFirstContentfulPaintAllFramesTs: number; observedFirstMeaningfulPaint: number | undefined; observedFirstMeaningfulPaintTs: number | undefined; observedLargestContentfulPaint: number | undefined; From 402b44867bde1a4799cf7850d5e1abd33a62a8b5 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Tue, 22 Dec 2020 11:00:20 -0500 Subject: [PATCH 02/13] update frametreeevents --- .../lib/tracehouse/trace-processor.js | 2 +- .../lib/tracehouse/trace-processor-test.js | 41 ++++++++++++++++--- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/lighthouse-core/lib/tracehouse/trace-processor.js b/lighthouse-core/lib/tracehouse/trace-processor.js index b19cfbd3de2b..23967a7ff6d2 100644 --- a/lighthouse-core/lib/tracehouse/trace-processor.js +++ b/lighthouse-core/lib/tracehouse/trace-processor.js @@ -631,7 +631,7 @@ class TraceProcessor { const frameTimings = this.computeKeyTimingsForFrame(frameEvents, {timeOriginEvt}); // Compute FCP for all frames. - const fcpAllFramesEvt = keyEvents.find( + const fcpAllFramesEvt = frameTreeEvents.find( e => e.name === 'firstContentfulPaint' && e.ts > timeOriginEvt.ts ); diff --git a/lighthouse-core/test/lib/tracehouse/trace-processor-test.js b/lighthouse-core/test/lib/tracehouse/trace-processor-test.js index 6ae7f00d017e..c5e4068b6dd6 100644 --- a/lighthouse-core/test/lib/tracehouse/trace-processor-test.js +++ b/lighthouse-core/test/lib/tracehouse/trace-processor-test.js @@ -505,36 +505,65 @@ Object { }); }); - describe('finds correct LCP from all frames', () => { + describe('finds correct metrics from all frames', () => { it('in a trace', () => { const trace = TraceProcessor.computeTraceOfTab(lcpAllFramesTrace); expect({ + // Main frame 'firstContentfulPaintEvt.ts': trace.firstContentfulPaintEvt.ts, 'largestContentfulPaintEvt.ts': trace.largestContentfulPaintEvt.ts, - 'mainFrameIds.frameId': trace.mainFrameIds.frameId, - 'timeOriginEvt.ts': trace.timeOriginEvt.ts, 'timestamps.firstContentfulPaint': trace.timestamps.firstContentfulPaint, 'timestamps.largestContentfulPaint': trace.timestamps.largestContentfulPaint, - 'timestamps.largestContentfulPaintAllFrames': trace.timestamps.largestContentfulPaintAllFrames, // eslint-disable-line max-len 'timings.firstContentfulPaint': trace.timings.firstContentfulPaint, 'timings.largestContentfulPaint': trace.timings.largestContentfulPaint, + // All frames + 'firstContentfulPaintAllFramesEvt.ts': trace.firstContentfulPaintAllFramesEvt.ts, + 'largestContentfulPaintAllFramesEvt.ts': trace.largestContentfulPaintAllFramesEvt.ts, + 'timestamps.firstContentfulPaintAllFrames': trace.timestamps.firstContentfulPaintAllFrames, // eslint-disable-line max-len + 'timestamps.largestContentfulPaintAllFrames': trace.timestamps.largestContentfulPaintAllFrames, // eslint-disable-line max-len + 'timings.firstContentfulPaintAllFrames': trace.timings.firstContentfulPaintAllFrames, 'timings.largestContentfulPaintAllFrames': trace.timings.largestContentfulPaintAllFrames, }).toMatchInlineSnapshot(` Object { + "firstContentfulPaintAllFramesEvt.ts": 23466705983, "firstContentfulPaintEvt.ts": 23466886143, + "largestContentfulPaintAllFramesEvt.ts": 23466705983, "largestContentfulPaintEvt.ts": 23466886143, - "mainFrameIds.frameId": "207613A6AD77B492759226780A40F6F4", - "timeOriginEvt.ts": 23466023130, "timestamps.firstContentfulPaint": 23466886143, + "timestamps.firstContentfulPaintAllFrames": 23466705983, "timestamps.largestContentfulPaint": 23466886143, "timestamps.largestContentfulPaintAllFrames": 23466705983, "timings.firstContentfulPaint": 863.013, + "timings.firstContentfulPaintAllFrames": 682.853, "timings.largestContentfulPaint": 863.013, "timings.largestContentfulPaintAllFrames": 682.853, } `); }); + it('finds FCP from all frames', () => { + const testTrace = createTestTrace({timeOrigin: 0, traceEnd: 2000}); + const mainFrame = testTrace.traceEvents[0].args.frame; + const childFrame = 'CHILDFRAME'; + const cat = 'loading,rail,devtools.timeline'; + + // Remove default FCP event because we will define them manually. + testTrace.traceEvents + = testTrace.traceEvents.filter(e => e.name !== 'firstContentfulPaint'); + + testTrace.traceEvents.push( + /* eslint-disable max-len */ + {name: 'FrameCommittedInBrowser', cat, args: {data: {frame: mainFrame, url: 'https://example.com'}}, ts: 900, duration: 10}, + {name: 'FrameCommittedInBrowser', cat, args: {data: {frame: childFrame, parent: mainFrame, url: 'https://frame.com'}}, ts: 910, duration: 10}, + {name: 'firstContentfulPaint', cat, args: {frame: childFrame}, ts: 1000, duration: 10}, + {name: 'firstContentfulPaint', cat, args: {frame: mainFrame}, ts: 1100, duration: 10} + /* eslint-enable max-len */ + ); + const trace = TraceProcessor.computeTraceOfTab(testTrace); + assert.equal(trace.timestamps.firstContentfulPaint, 1100); + assert.equal(trace.timestamps.firstContentfulPaintAllFrames, 1000); + }); + it('finds LCP from all frames', () => { const testTrace = createTestTrace({timeOrigin: 0, traceEnd: 2000}); const mainFrame = testTrace.traceEvents[0].args.frame; From d9792460535db882117921d31ec47675243a4b3d Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Tue, 22 Dec 2020 14:52:59 -0500 Subject: [PATCH 03/13] timing-summary-test.js --- lighthouse-core/test/computed/metrics/timing-summary-test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lighthouse-core/test/computed/metrics/timing-summary-test.js b/lighthouse-core/test/computed/metrics/timing-summary-test.js index e4e1e8a02994..c9190896fd37 100644 --- a/lighthouse-core/test/computed/metrics/timing-summary-test.js +++ b/lighthouse-core/test/computed/metrics/timing-summary-test.js @@ -25,6 +25,8 @@ describe('Timing summary', () => { "firstCPUIdle": 863.013, "firstCPUIdleTs": 23466886143, "firstContentfulPaint": 863.013, + "firstContentfulPaintAllFrames": 682.853, + "firstContentfulPaintAllFramesTs": 23466705983, "firstContentfulPaintTs": 23466886143, "firstMeaningfulPaint": 863.013, "firstMeaningfulPaintTs": 23466886143, @@ -40,6 +42,8 @@ describe('Timing summary', () => { "observedDomContentLoaded": 596.195, "observedDomContentLoadedTs": 23466619325, "observedFirstContentfulPaint": 863.013, + "observedFirstContentfulPaintAllFrames": 682.853, + "observedFirstContentfulPaintAllFramesTs": 23466705983, "observedFirstContentfulPaintTs": 23466886143, "observedFirstMeaningfulPaint": 863.013, "observedFirstMeaningfulPaintTs": 23466886143, From 7de15b745d3f3476e0661da5e496dc1f9d96fed2 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Tue, 22 Dec 2020 16:26:02 -0500 Subject: [PATCH 04/13] update tests --- .../metrics/first-contentful-paint-all-frames.js | 10 ++++++++-- .../lib/tracehouse/trace-processor.js | 5 ++++- .../audits/__snapshots__/metrics-test.js.snap | 16 ++++++++++++++++ .../first-contentful-paint-all-frames-test.js | 15 ++++++++++----- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js index 8137ac5e92a0..6a6b78e1ab7f 100644 --- a/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js +++ b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js @@ -6,14 +6,20 @@ 'use strict'; const makeComputedArtifact = require('../computed-artifact.js'); +const LanternFirstContentfulPaint = require('./lantern-first-contentful-paint.js'); const ComputedMetric = require('./metric.js'); class FirstContentfulPaintAllFrames extends ComputedMetric { /** + * @param {LH.Artifacts.MetricComputationData} data + * @param {LH.Audit.Context} context * @return {Promise} */ - static computeSimulatedMetric() { - throw new Error('FCP All Frames not implemented in lantern.'); + static computeSimulatedMetric(data, context) { + // Fall back to main frame LCP when using simulated throttling. + // Throwing an error causes tests to fail. + // TODO: Add support for all frames in lantern. + return LanternFirstContentfulPaint.request(data, context); } /** diff --git a/lighthouse-core/lib/tracehouse/trace-processor.js b/lighthouse-core/lib/tracehouse/trace-processor.js index 23967a7ff6d2..7f85f5cbad04 100644 --- a/lighthouse-core/lib/tracehouse/trace-processor.js +++ b/lighthouse-core/lib/tracehouse/trace-processor.js @@ -631,9 +631,12 @@ class TraceProcessor { const frameTimings = this.computeKeyTimingsForFrame(frameEvents, {timeOriginEvt}); // Compute FCP for all frames. + // In practice, this will always be defined when there is a main frame FCP. + // Unfortunately, many test traces do not include FrameCommittedInBrowser events due to minification. + // The fallback to the main frame FCP is added so these tests do throw a NO_FCP error. const fcpAllFramesEvt = frameTreeEvents.find( e => e.name === 'firstContentfulPaint' && e.ts > timeOriginEvt.ts - ); + ) || frameTimings.firstContentfulPaintEvt; // Compute LCP for all frames. const lcpAllFramesEvt = this.computeValidLCPAllFrames(frameTreeEvents, timeOriginEvt).lcp; diff --git a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap index 22dc7d64174a..747ab0d92edf 100644 --- a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap +++ b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap @@ -9,6 +9,8 @@ Object { "firstCPUIdle": 863, "firstCPUIdleTs": 23466886143, "firstContentfulPaint": 863, + "firstContentfulPaintAllFrames": 683, + "firstContentfulPaintAllFramesTs": 23466705983, "firstContentfulPaintTs": 23466886143, "firstMeaningfulPaint": 863, "firstMeaningfulPaintTs": 23466886143, @@ -24,6 +26,8 @@ Object { "observedDomContentLoaded": 596, "observedDomContentLoadedTs": 23466619325, "observedFirstContentfulPaint": 863, + "observedFirstContentfulPaintAllFrames": 683, + "observedFirstContentfulPaintAllFramesTs": 23466705983, "observedFirstContentfulPaintTs": 23466886143, "observedFirstMeaningfulPaint": 863, "observedFirstMeaningfulPaintTs": 23466886143, @@ -62,6 +66,8 @@ Object { "firstCPUIdle": 3790, "firstCPUIdleTs": undefined, "firstContentfulPaint": 2289, + "firstContentfulPaintAllFrames": 2289, + "firstContentfulPaintAllFramesTs": undefined, "firstContentfulPaintTs": undefined, "firstMeaningfulPaint": 2758, "firstMeaningfulPaintTs": undefined, @@ -77,6 +83,8 @@ Object { "observedDomContentLoaded": 1513, "observedDomContentLoadedTs": 713038536140, "observedFirstContentfulPaint": 1122, + "observedFirstContentfulPaintAllFrames": 1122, + "observedFirstContentfulPaintAllFramesTs": 713038144775, "observedFirstContentfulPaintTs": 713038144775, "observedFirstMeaningfulPaint": 1122, "observedFirstMeaningfulPaintTs": 713038144775, @@ -115,6 +123,8 @@ Object { "firstCPUIdle": 1582, "firstCPUIdleTs": 225415754204, "firstContentfulPaint": 499, + "firstContentfulPaintAllFrames": 499, + "firstContentfulPaintAllFramesTs": 225414670885, "firstContentfulPaintTs": 225414670885, "firstMeaningfulPaint": 783, "firstMeaningfulPaintTs": 225414955343, @@ -130,6 +140,8 @@ Object { "observedDomContentLoaded": 560, "observedDomContentLoadedTs": 225414732309, "observedFirstContentfulPaint": 499, + "observedFirstContentfulPaintAllFrames": 499, + "observedFirstContentfulPaintAllFramesTs": 225414670885, "observedFirstContentfulPaintTs": 225414670885, "observedFirstMeaningfulPaint": 783, "observedFirstMeaningfulPaintTs": 225414955343, @@ -168,6 +180,8 @@ Object { "firstCPUIdle": 4313, "firstCPUIdleTs": undefined, "firstContentfulPaint": 1337, + "firstContentfulPaintAllFrames": 1337, + "firstContentfulPaintAllFramesTs": undefined, "firstContentfulPaintTs": undefined, "firstMeaningfulPaint": 1553, "firstMeaningfulPaintTs": undefined, @@ -183,6 +197,8 @@ Object { "observedDomContentLoaded": 560, "observedDomContentLoadedTs": 225414732309, "observedFirstContentfulPaint": 499, + "observedFirstContentfulPaintAllFrames": 499, + "observedFirstContentfulPaintAllFramesTs": 225414670885, "observedFirstContentfulPaintTs": 225414670885, "observedFirstMeaningfulPaint": 783, "observedFirstMeaningfulPaintTs": 225414955343, diff --git a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js index 26ec3ba962f6..bc5513e55290 100644 --- a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js +++ b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js @@ -6,21 +6,26 @@ 'use strict'; const FirstContentfulPaintAllFrames = require('../../../computed/metrics/first-contentful-paint-all-frames.js'); // eslint-disable-line max-len +const LanternFirstContentfulPaint = require('../../../computed/metrics/lantern-first-contentful-paint.js'); // eslint-disable-line max-len const trace = require('../../fixtures/traces/frame-metrics-m89.json'); const devtoolsLog = require('../../fixtures/traces/frame-metrics-m89.devtools.log.json'); /* eslint-env jest */ describe('Metrics: FCP all frames', () => { - it('should error for a simulated value', async () => { + it('should fall back to main frame lantern FCP for simulated throttling', async () => { const settings = {throttlingMethod: 'simulate'}; const context = {settings, computedCache: new Map()}; - const resultPromise = FirstContentfulPaintAllFrames.request( + const result = await FirstContentfulPaintAllFrames.request( + {trace, devtoolsLog, settings}, + context + ); + const lanternResult = await LanternFirstContentfulPaint.request( {trace, devtoolsLog, settings}, context ); - await expect(resultPromise).rejects.toThrow(); + await expect(result).toEqual(lanternResult); }); it('should compute FCP-AF separate from FCP', async () => { @@ -33,8 +38,8 @@ describe('Metrics: FCP all frames', () => { expect(result).toEqual( { - timestamp: 46134430620, - timing: 688.13, + timestamp: 23466705983, + timing: 682.853, } ); }); From 8fe525b0950de13392e1ee9c3f84577428a0d82b Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Tue, 22 Dec 2020 16:57:29 -0500 Subject: [PATCH 05/13] update sample --- lighthouse-core/test/results/sample_v2.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json index 0c6ebb642e3d..891617072a5a 100644 --- a/lighthouse-core/test/results/sample_v2.json +++ b/lighthouse-core/test/results/sample_v2.json @@ -1453,6 +1453,8 @@ { "firstContentfulPaint": 3969, "firstContentfulPaintTs": 185607289047, + "firstContentfulPaintAllFrames": 3969, + "firstContentfulPaintAllFramesTs": 185607289047, "firstMeaningfulPaint": 3969, "firstMeaningfulPaintTs": 185607289048, "largestContentfulPaint": 4927, @@ -1476,6 +1478,8 @@ "observedFirstPaintTs": 185607289043, "observedFirstContentfulPaint": 3969, "observedFirstContentfulPaintTs": 185607289047, + "observedFirstContentfulPaintAllFrames": 3969, + "observedFirstContentfulPaintAllFramesTs": 185607289047, "observedFirstMeaningfulPaint": 3969, "observedFirstMeaningfulPaintTs": 185607289048, "observedLargestContentfulPaint": 4927, @@ -6233,6 +6237,12 @@ "duration": 100, "entryType": "measure" }, + { + "startTime": 0, + "name": "lh:computed:FirstContentfulPaintAllFrames", + "duration": 100, + "entryType": "measure" + }, { "startTime": 0, "name": "lh:computed:LargestContentfulPaintAllFrames", From fbd963f7727d15556ac9720e8fcc1eac90fef344 Mon Sep 17 00:00:00 2001 From: Adam Raine <6752989+adamraine@users.noreply.github.com> Date: Tue, 12 Jan 2021 19:20:04 -0500 Subject: [PATCH 06/13] date Co-authored-by: Connor Clark --- .../computed/metrics/first-contentful-paint-all-frames-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js index bc5513e55290..80be4260ce9d 100644 --- a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js +++ b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js @@ -1,5 +1,5 @@ /** - * @license Copyright 2018 The Lighthouse Authors. All Rights Reserved. + * @license Copyright 2021 The Lighthouse Authors. 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. */ From 9360bb7f4946467d74af88c103b8d8ef74e79ad2 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Fri, 15 Jan 2021 14:45:37 -0500 Subject: [PATCH 07/13] review --- .../first-contentful-paint-all-frames.js | 9 ++----- .../computed/metrics/timing-summary.js | 6 ++--- .../lib/tracehouse/trace-processor.js | 24 ++++++++++-------- .../audits/__snapshots__/metrics-test.js.snap | 8 +++--- .../first-contentful-paint-all-frames-test.js | 12 +++------ ...argest-contentful-paint-all-frames-test.js | 9 ++++--- .../test/computed/trace-of-tab-test.js | 2 +- .../lib/tracehouse/trace-processor-test.js | 25 +++++++++++++++++++ types/artifacts.d.ts | 2 +- 9 files changed, 60 insertions(+), 37 deletions(-) diff --git a/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js index 6a6b78e1ab7f..b3ab05bbd2ad 100644 --- a/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js +++ b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js @@ -6,20 +6,15 @@ 'use strict'; const makeComputedArtifact = require('../computed-artifact.js'); -const LanternFirstContentfulPaint = require('./lantern-first-contentful-paint.js'); const ComputedMetric = require('./metric.js'); class FirstContentfulPaintAllFrames extends ComputedMetric { /** - * @param {LH.Artifacts.MetricComputationData} data - * @param {LH.Audit.Context} context * @return {Promise} */ - static computeSimulatedMetric(data, context) { - // Fall back to main frame LCP when using simulated throttling. - // Throwing an error causes tests to fail. + static computeSimulatedMetric() { // TODO: Add support for all frames in lantern. - return LanternFirstContentfulPaint.request(data, context); + throw new Error('FCP All Frames not implemented in lantern'); } /** diff --git a/lighthouse-core/computed/metrics/timing-summary.js b/lighthouse-core/computed/metrics/timing-summary.js index 7212be69b873..85f0f1f8b0ef 100644 --- a/lighthouse-core/computed/metrics/timing-summary.js +++ b/lighthouse-core/computed/metrics/timing-summary.js @@ -45,7 +45,7 @@ class TimingSummary { const traceOfTab = await TraceOfTab.request(trace, context); const speedline = await Speedline.request(trace, context); const firstContentfulPaint = await FirstContentfulPaint.request(metricComputationData, context); - const firstContentfulPaintAllFrames = await FirstContentfulPaintAllFrames.request(metricComputationData, context); // eslint-disable-line max-len + const firstContentfulPaintAllFrames = await requestOrUndefined(FirstContentfulPaintAllFrames, metricComputationData); // eslint-disable-line max-len const firstMeaningfulPaint = await FirstMeaningfulPaint.request(metricComputationData, context); const largestContentfulPaint = await requestOrUndefined(LargestContentfulPaint, metricComputationData); // eslint-disable-line max-len const largestContentfulPaintAllFrames = await requestOrUndefined(LargestContentfulPaintAllFrames, metricComputationData); // eslint-disable-line max-len @@ -69,8 +69,8 @@ class TimingSummary { // Include the simulated/observed performance metrics firstContentfulPaint: firstContentfulPaint.timing, firstContentfulPaintTs: firstContentfulPaint.timestamp, - firstContentfulPaintAllFrames: firstContentfulPaintAllFrames.timing, - firstContentfulPaintAllFramesTs: firstContentfulPaintAllFrames.timestamp, + firstContentfulPaintAllFrames: firstContentfulPaintAllFrames && firstContentfulPaintAllFrames.timing, // eslint-disable-line max-len + firstContentfulPaintAllFramesTs: firstContentfulPaintAllFrames && firstContentfulPaintAllFrames.timestamp, // eslint-disable-line max-len firstMeaningfulPaint: firstMeaningfulPaint.timing, firstMeaningfulPaintTs: firstMeaningfulPaint.timestamp, largestContentfulPaint: largestContentfulPaint && largestContentfulPaint.timing, diff --git a/lighthouse-core/lib/tracehouse/trace-processor.js b/lighthouse-core/lib/tracehouse/trace-processor.js index 7f85f5cbad04..db021d61799a 100644 --- a/lighthouse-core/lib/tracehouse/trace-processor.js +++ b/lighthouse-core/lib/tracehouse/trace-processor.js @@ -611,15 +611,22 @@ class TraceProcessor { }); const frameIdToRootFrameId = this.resolveRootFrames(frames); - // Filter to just events matching the frame ID, just to make sure. + // Filter to just events matching the main frame ID, just to make sure. const frameEvents = keyEvents.filter(e => e.args.frame === mainFrameIds.frameId); // Filter to just events matching the main frame ID or any child frame IDs. - const frameTreeEvents = keyEvents.filter(e => { - return e.args && - e.args.frame && - frameIdToRootFrameId.get(e.args.frame) === mainFrameIds.frameId; - }); + // In practice, there should always be FrameCommittedInBrowser events to define the frame tree. + // Unfortunately, many test traces do not include FrameCommittedInBrowser events due to minification. + // This ensures there is always a minimal frame tree and events so those tests don't fail. + let frameTreeEvents = []; + if (!frameIdToRootFrameId.has(mainFrameIds.frameId)) { + frameIdToRootFrameId.set(mainFrameIds.frameId, mainFrameIds.frameId); + frameTreeEvents = frameEvents; + } else { + frameTreeEvents = keyEvents.filter(e => { + return e.args.frame && frameIdToRootFrameId.get(e.args.frame) === mainFrameIds.frameId; + }); + } // Compute our time origin to use for all relative timings. const timeOriginEvt = this.computeTimeOrigin( @@ -631,12 +638,9 @@ class TraceProcessor { const frameTimings = this.computeKeyTimingsForFrame(frameEvents, {timeOriginEvt}); // Compute FCP for all frames. - // In practice, this will always be defined when there is a main frame FCP. - // Unfortunately, many test traces do not include FrameCommittedInBrowser events due to minification. - // The fallback to the main frame FCP is added so these tests do throw a NO_FCP error. const fcpAllFramesEvt = frameTreeEvents.find( e => e.name === 'firstContentfulPaint' && e.ts > timeOriginEvt.ts - ) || frameTimings.firstContentfulPaintEvt; + ); // Compute LCP for all frames. const lcpAllFramesEvt = this.computeValidLCPAllFrames(frameTreeEvents, timeOriginEvt).lcp; diff --git a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap index 747ab0d92edf..47b8db35c659 100644 --- a/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap +++ b/lighthouse-core/test/audits/__snapshots__/metrics-test.js.snap @@ -66,7 +66,7 @@ Object { "firstCPUIdle": 3790, "firstCPUIdleTs": undefined, "firstContentfulPaint": 2289, - "firstContentfulPaintAllFrames": 2289, + "firstContentfulPaintAllFrames": undefined, "firstContentfulPaintAllFramesTs": undefined, "firstContentfulPaintTs": undefined, "firstMeaningfulPaint": 2758, @@ -93,8 +93,8 @@ Object { "observedFirstVisualChange": 1105, "observedFirstVisualChangeTs": 713038128064, "observedLargestContentfulPaint": 1122, - "observedLargestContentfulPaintAllFrames": undefined, - "observedLargestContentfulPaintAllFramesTs": undefined, + "observedLargestContentfulPaintAllFrames": 1122, + "observedLargestContentfulPaintAllFramesTs": 713038144775, "observedLargestContentfulPaintTs": 713038144775, "observedLastVisualChange": 1722, "observedLastVisualChangeTs": 713038745064, @@ -180,7 +180,7 @@ Object { "firstCPUIdle": 4313, "firstCPUIdleTs": undefined, "firstContentfulPaint": 1337, - "firstContentfulPaintAllFrames": 1337, + "firstContentfulPaintAllFrames": undefined, "firstContentfulPaintAllFramesTs": undefined, "firstContentfulPaintTs": undefined, "firstMeaningfulPaint": 1553, diff --git a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js index bc5513e55290..930ec03014e6 100644 --- a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js +++ b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js @@ -6,26 +6,22 @@ 'use strict'; const FirstContentfulPaintAllFrames = require('../../../computed/metrics/first-contentful-paint-all-frames.js'); // eslint-disable-line max-len -const LanternFirstContentfulPaint = require('../../../computed/metrics/lantern-first-contentful-paint.js'); // eslint-disable-line max-len const trace = require('../../fixtures/traces/frame-metrics-m89.json'); const devtoolsLog = require('../../fixtures/traces/frame-metrics-m89.devtools.log.json'); /* eslint-env jest */ describe('Metrics: FCP all frames', () => { - it('should fall back to main frame lantern FCP for simulated throttling', async () => { + it('should throw for simulated throttling', async () => { const settings = {throttlingMethod: 'simulate'}; const context = {settings, computedCache: new Map()}; - const result = await FirstContentfulPaintAllFrames.request( - {trace, devtoolsLog, settings}, - context - ); - const lanternResult = await LanternFirstContentfulPaint.request( + const resultPromise = FirstContentfulPaintAllFrames.request( {trace, devtoolsLog, settings}, context ); - await expect(result).toEqual(lanternResult); + // TODO: Implement lantern solution for FCP all frames. + await expect(resultPromise).rejects.toThrow(); }); it('should compute FCP-AF separate from FCP', async () => { diff --git a/lighthouse-core/test/computed/metrics/largest-contentful-paint-all-frames-test.js b/lighthouse-core/test/computed/metrics/largest-contentful-paint-all-frames-test.js index 8e6e1b7def3c..e3f3674ddc95 100644 --- a/lighthouse-core/test/computed/metrics/largest-contentful-paint-all-frames-test.js +++ b/lighthouse-core/test/computed/metrics/largest-contentful-paint-all-frames-test.js @@ -46,13 +46,16 @@ describe('Metrics: LCP from all frames', () => { await expect(resultPromise).rejects.toThrow('NO_LCP_ALL_FRAMES'); }); - it('should fail if even if main frame LCP is available', async () => { + it('should use main frame LCP if no other frames', async () => { const settings = {throttlingMethod: 'provided'}; const context = {settings, computedCache: new Map()}; - const resultPromise = LargestContentfulPaintAllFrames.request( + const result = await LargestContentfulPaintAllFrames.request( {trace: traceMainFrame, devtoolsLog: devtoolsLogMainFrame, settings}, context ); - await expect(resultPromise).rejects.toThrow('NO_LCP_ALL_FRAMES'); + await expect(result).toEqual({ + timestamp: 713038144775, + timing: 1121.711, + }); }); }); diff --git a/lighthouse-core/test/computed/trace-of-tab-test.js b/lighthouse-core/test/computed/trace-of-tab-test.js index e75121a35cb9..53c5dc7541a8 100644 --- a/lighthouse-core/test/computed/trace-of-tab-test.js +++ b/lighthouse-core/test/computed/trace-of-tab-test.js @@ -22,6 +22,7 @@ describe('TraceOfTabComputed', () => { delete traceOfTab.processEvents; delete traceOfTab.mainThreadEvents; + delete traceOfTab.frameTreeEvents; expect(traceOfTab).toEqual({ domContentLoadedEvt: { @@ -119,7 +120,6 @@ describe('TraceOfTabComputed', () => { tts: 455539, }, frames: [], - frameTreeEvents: [], timestamps: { domContentLoaded: 225414732309, firstContentfulPaint: 225414670885, diff --git a/lighthouse-core/test/lib/tracehouse/trace-processor-test.js b/lighthouse-core/test/lib/tracehouse/trace-processor-test.js index c5e4068b6dd6..f90b5b8acbd6 100644 --- a/lighthouse-core/test/lib/tracehouse/trace-processor-test.js +++ b/lighthouse-core/test/lib/tracehouse/trace-processor-test.js @@ -225,6 +225,29 @@ describe('TraceProcessor', () => { 'Event2', ]); }); + + it('frameTreeEvents includes main frame events if no FrameCommittedInBrowser found', () => { + const testTrace = createTestTrace({timeOrigin: 0, traceEnd: 2000}); + const mainFrame = testTrace.traceEvents[0].args.frame; + const childFrame = 'CHILDFRAME'; + const otherMainFrame = 'ANOTHERTAB'; + const cat = 'loading,rail,devtools.timeline'; + testTrace.traceEvents.push( + /* eslint-disable max-len */ + {name: 'Event1', cat, args: {frame: mainFrame}}, + {name: 'Event2', cat, args: {frame: childFrame}}, + {name: 'Event3', cat, args: {frame: otherMainFrame}} + /* eslint-enable max-len */ + ); + const trace = TraceProcessor.computeTraceOfTab(testTrace); + expect(trace.frameTreeEvents.map(e => e.name)).toEqual([ + 'navigationStart', + 'domContentLoadedEventEnd', + 'firstContentfulPaint', + 'firstMeaningfulPaint', + 'Event1', + ]); + }); }); describe('getMainThreadTopLevelEvents', () => { @@ -510,6 +533,7 @@ Object { const trace = TraceProcessor.computeTraceOfTab(lcpAllFramesTrace); expect({ // Main frame + 'mainFrameIds.frameId': trace.mainFrameIds.frameId, 'firstContentfulPaintEvt.ts': trace.firstContentfulPaintEvt.ts, 'largestContentfulPaintEvt.ts': trace.largestContentfulPaintEvt.ts, 'timestamps.firstContentfulPaint': trace.timestamps.firstContentfulPaint, @@ -529,6 +553,7 @@ Object { "firstContentfulPaintEvt.ts": 23466886143, "largestContentfulPaintAllFramesEvt.ts": 23466705983, "largestContentfulPaintEvt.ts": 23466886143, + "mainFrameIds.frameId": "207613A6AD77B492759226780A40F6F4", "timestamps.firstContentfulPaint": 23466886143, "timestamps.firstContentfulPaintAllFrames": 23466705983, "timestamps.largestContentfulPaint": 23466886143, diff --git a/types/artifacts.d.ts b/types/artifacts.d.ts index 81a1d8fb053b..bfa642dc6cd1 100644 --- a/types/artifacts.d.ts +++ b/types/artifacts.d.ts @@ -667,7 +667,7 @@ declare global { export interface TimingSummary { firstContentfulPaint: number; firstContentfulPaintTs: number | undefined; - firstContentfulPaintAllFrames: number; + firstContentfulPaintAllFrames: number | undefined; firstContentfulPaintAllFramesTs: number | undefined; firstMeaningfulPaint: number; firstMeaningfulPaintTs: number | undefined; From e91c3f07590d40bfd7c1adfc9c7c3847afc2732c Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Fri, 15 Jan 2021 14:53:22 -0500 Subject: [PATCH 08/13] update sample --- lighthouse-core/test/results/sample_v2.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json index 891617072a5a..1f84ed51688e 100644 --- a/lighthouse-core/test/results/sample_v2.json +++ b/lighthouse-core/test/results/sample_v2.json @@ -1459,6 +1459,8 @@ "firstMeaningfulPaintTs": 185607289048, "largestContentfulPaint": 4927, "largestContentfulPaintTs": 185608247190, + "largestContentfulPaintAllFrames": 4927, + "largestContentfulPaintAllFramesTs": 185608247190, "firstCPUIdle": 4927, "firstCPUIdleTs": 185608247190, "interactive": 4927, @@ -1484,6 +1486,8 @@ "observedFirstMeaningfulPaintTs": 185607289048, "observedLargestContentfulPaint": 4927, "observedLargestContentfulPaintTs": 185608247190, + "observedLargestContentfulPaintAllFrames": 4927, + "observedLargestContentfulPaintAllFramesTs": 185608247190, "observedTraceEnd": 10281, "observedTraceEndTs": 185613601189, "observedLoad": 4924, From c626fe59ffc957295c8188156c51a35905c3ea35 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Fri, 15 Jan 2021 17:04:46 -0500 Subject: [PATCH 09/13] warning --- lighthouse-core/lib/tracehouse/trace-processor.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lighthouse-core/lib/tracehouse/trace-processor.js b/lighthouse-core/lib/tracehouse/trace-processor.js index db021d61799a..aa17a41e6803 100644 --- a/lighthouse-core/lib/tracehouse/trace-processor.js +++ b/lighthouse-core/lib/tracehouse/trace-processor.js @@ -620,6 +620,10 @@ class TraceProcessor { // This ensures there is always a minimal frame tree and events so those tests don't fail. let frameTreeEvents = []; if (!frameIdToRootFrameId.has(mainFrameIds.frameId)) { + log.warn( + 'trace-of-tab', + 'frameTreeEvents may be incomplete, make sure the trace has FrameCommittedInBrowser events' + ); frameIdToRootFrameId.set(mainFrameIds.frameId, mainFrameIds.frameId); frameTreeEvents = frameEvents; } else { From ab163b23574e0823b860dbc83181971ea1da8b3d Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Fri, 15 Jan 2021 17:25:30 -0500 Subject: [PATCH 10/13] c --- lighthouse-core/lib/tracehouse/trace-processor.js | 10 +++++----- .../first-contentful-paint-all-frames-test.js | 12 ++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lighthouse-core/lib/tracehouse/trace-processor.js b/lighthouse-core/lib/tracehouse/trace-processor.js index aa17a41e6803..393d651d696d 100644 --- a/lighthouse-core/lib/tracehouse/trace-processor.js +++ b/lighthouse-core/lib/tracehouse/trace-processor.js @@ -619,17 +619,17 @@ class TraceProcessor { // Unfortunately, many test traces do not include FrameCommittedInBrowser events due to minification. // This ensures there is always a minimal frame tree and events so those tests don't fail. let frameTreeEvents = []; - if (!frameIdToRootFrameId.has(mainFrameIds.frameId)) { + if (frameIdToRootFrameId.has(mainFrameIds.frameId)) { + frameTreeEvents = keyEvents.filter(e => { + return e.args.frame && frameIdToRootFrameId.get(e.args.frame) === mainFrameIds.frameId; + }); + } else { log.warn( 'trace-of-tab', 'frameTreeEvents may be incomplete, make sure the trace has FrameCommittedInBrowser events' ); frameIdToRootFrameId.set(mainFrameIds.frameId, mainFrameIds.frameId); frameTreeEvents = frameEvents; - } else { - frameTreeEvents = keyEvents.filter(e => { - return e.args.frame && frameIdToRootFrameId.get(e.args.frame) === mainFrameIds.frameId; - }); } // Compute our time origin to use for all relative timings. diff --git a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js index 9da89bc2afae..8293fc238d51 100644 --- a/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js +++ b/lighthouse-core/test/computed/metrics/first-contentful-paint-all-frames-test.js @@ -6,6 +6,7 @@ 'use strict'; const FirstContentfulPaintAllFrames = require('../../../computed/metrics/first-contentful-paint-all-frames.js'); // eslint-disable-line max-len +const FirstContentfulPaint = require('../../../computed/metrics/first-contentful-paint.js'); // eslint-disable-line max-len const trace = require('../../fixtures/traces/frame-metrics-m89.json'); const devtoolsLog = require('../../fixtures/traces/frame-metrics-m89.devtools.log.json'); @@ -27,10 +28,15 @@ describe('Metrics: FCP all frames', () => { it('should compute FCP-AF separate from FCP', async () => { const settings = {throttlingMethod: 'provided'}; const context = {settings, computedCache: new Map()}; + const result = await FirstContentfulPaintAllFrames.request( {trace, devtoolsLog, settings}, context ); + const mainFrameResult = await FirstContentfulPaint.request( + {trace, devtoolsLog, settings}, + context + ); expect(result).toEqual( { @@ -38,5 +44,11 @@ describe('Metrics: FCP all frames', () => { timing: 682.853, } ); + expect(mainFrameResult).toEqual( + { + timestamp: 23466886143, + timing: 863.013, + } + ); }); }); From 562c4f332a21b6c9d97f300f279986c40bdbe8df Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Tue, 19 Jan 2021 12:25:13 -0500 Subject: [PATCH 11/13] smoke --- .../fixtures/perf/frame-metrics-inner.html | 20 ++++++++++++++ .../test/fixtures/perf/frame-metrics.html | 27 +++++++++++++++++++ .../test-definitions/perf/expectations.js | 27 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 lighthouse-cli/test/fixtures/perf/frame-metrics-inner.html create mode 100644 lighthouse-cli/test/fixtures/perf/frame-metrics.html diff --git a/lighthouse-cli/test/fixtures/perf/frame-metrics-inner.html b/lighthouse-cli/test/fixtures/perf/frame-metrics-inner.html new file mode 100644 index 000000000000..6dd5f50f30b4 --- /dev/null +++ b/lighthouse-cli/test/fixtures/perf/frame-metrics-inner.html @@ -0,0 +1,20 @@ + + + + +
+

THIS IS THE INNER FRAME LCP AND FCP

+ + + diff --git a/lighthouse-cli/test/fixtures/perf/frame-metrics.html b/lighthouse-cli/test/fixtures/perf/frame-metrics.html new file mode 100644 index 000000000000..ad3f73dee7bc --- /dev/null +++ b/lighthouse-cli/test/fixtures/perf/frame-metrics.html @@ -0,0 +1,27 @@ + + + + + +
+
+ + + diff --git a/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js b/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js index 83244dcb2a41..75bae77e89ed 100644 --- a/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js +++ b/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js @@ -323,4 +323,31 @@ module.exports = [ }, }, }, + { + lhr: { + requestedUrl: 'http://localhost:10200/perf/frame-metrics.html', + finalUrl: 'http://localhost:10200/perf/frame-metrics.html', + audits: { + 'metrics': { + score: null, + details: { + type: 'debugdata', + items: [ + { + firstContentfulPaint: '>1000', + firstContentfulPaintAllFrames: '<1000', + largestContentfulPaint: '>1000', + largestContentfulPaintAllFrames: '<1000', + cumulativeLayoutShift: '0.001 +/- 0.0005', + cumulativeLayoutShiftAllFrames: '0.068 +/- 0.0005', + }, + { + lcpInvalidated: false, + }, + ], + }, + }, + }, + }, + }, ]; From 200ce028d6a5b279dee1330ef4c28f7c47b82cc6 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Tue, 19 Jan 2021 14:03:16 -0500 Subject: [PATCH 12/13] extend --- .../test/fixtures/perf/frame-metrics.html | 17 ++++++++++++++--- .../test-definitions/perf/expectations.js | 8 ++++---- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lighthouse-cli/test/fixtures/perf/frame-metrics.html b/lighthouse-cli/test/fixtures/perf/frame-metrics.html index ad3f73dee7bc..1b4b17a2d8dd 100644 --- a/lighthouse-cli/test/fixtures/perf/frame-metrics.html +++ b/lighthouse-cli/test/fixtures/perf/frame-metrics.html @@ -4,16 +4,27 @@
-
+
+ +
diff --git a/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js b/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js index 75bae77e89ed..9ce9d9ba5397 100644 --- a/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js +++ b/lighthouse-cli/test/smokehouse/test-definitions/perf/expectations.js @@ -334,10 +334,10 @@ module.exports = [ type: 'debugdata', items: [ { - firstContentfulPaint: '>1000', - firstContentfulPaintAllFrames: '<1000', - largestContentfulPaint: '>1000', - largestContentfulPaintAllFrames: '<1000', + firstContentfulPaint: '>5000', + firstContentfulPaintAllFrames: '<5000', + largestContentfulPaint: '>5000', + largestContentfulPaintAllFrames: '<5000', cumulativeLayoutShift: '0.001 +/- 0.0005', cumulativeLayoutShiftAllFrames: '0.068 +/- 0.0005', }, From 6ab0900dd8dee5519a3787c9e375158a7fabbfd1 Mon Sep 17 00:00:00 2001 From: Adam Raine <6752989+adamraine@users.noreply.github.com> Date: Tue, 19 Jan 2021 14:54:59 -0500 Subject: [PATCH 13/13] 2021 --- .../computed/metrics/first-contentful-paint-all-frames.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js index b3ab05bbd2ad..6abc243d811d 100644 --- a/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js +++ b/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js @@ -1,5 +1,5 @@ /** - * @license Copyright 2020 The Lighthouse Authors. All Rights Reserved. + * @license Copyright 2021 The Lighthouse Authors. 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. */