diff --git a/core/computed/metrics/lantern-first-contentful-paint.js b/core/computed/metrics/lantern-first-contentful-paint.js index 7e60d7bcbe2e..cbb2d2a68e30 100644 --- a/core/computed/metrics/lantern-first-contentful-paint.js +++ b/core/computed/metrics/lantern-first-contentful-paint.js @@ -5,7 +5,7 @@ */ import {makeComputedArtifact} from '../computed-artifact.js'; -import {getComputationDataParams} from './lantern-metric.js'; +import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {FirstContentfulPaint} from '../../lib/lantern/metrics/first-contentful-paint.js'; /** @typedef {import('../../lib/lantern/metric.js').Extras} Extras */ @@ -18,7 +18,8 @@ class LanternFirstContentfulPaint extends FirstContentfulPaint { * @return {Promise} */ static async computeMetricWithGraphs(data, context, extras) { - return this.compute(await getComputationDataParams(data, context), extras); + return this.compute(await getComputationDataParams(data, context), extras) + .catch(lanternErrorAdapter); } /** diff --git a/core/computed/metrics/lantern-first-meaningful-paint.js b/core/computed/metrics/lantern-first-meaningful-paint.js index 29150721ad9d..6606bc5ea6d9 100644 --- a/core/computed/metrics/lantern-first-meaningful-paint.js +++ b/core/computed/metrics/lantern-first-meaningful-paint.js @@ -5,7 +5,7 @@ */ import {makeComputedArtifact} from '../computed-artifact.js'; -import {getComputationDataParams} from './lantern-metric.js'; +import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {FirstMeaningfulPaint} from '../../lib/lantern/metrics/first-meaningful-paint.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; @@ -19,7 +19,8 @@ class LanternFirstMeaningfulPaint extends FirstMeaningfulPaint { * @return {Promise} */ static async computeMetricWithGraphs(data, context, extras) { - return this.compute(await getComputationDataParams(data, context), extras); + return this.compute(await getComputationDataParams(data, context), extras) + .catch(lanternErrorAdapter); } /** diff --git a/core/computed/metrics/lantern-interactive.js b/core/computed/metrics/lantern-interactive.js index 16aaa03bcafd..7a634cda8b68 100644 --- a/core/computed/metrics/lantern-interactive.js +++ b/core/computed/metrics/lantern-interactive.js @@ -7,7 +7,7 @@ import {makeComputedArtifact} from '../computed-artifact.js'; import {LanternFirstMeaningfulPaint} from './lantern-first-meaningful-paint.js'; import {Interactive} from '../../lib/lantern/metrics/interactive.js'; -import {getComputationDataParams} from './lantern-metric.js'; +import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; /** @typedef {import('../../lib/lantern/metric.js').Extras} Extras */ @@ -19,7 +19,8 @@ class LanternInteractive extends Interactive { * @return {Promise} */ static async computeMetricWithGraphs(data, context, extras) { - return this.compute(await getComputationDataParams(data, context), extras); + return this.compute(await getComputationDataParams(data, context), extras) + .catch(lanternErrorAdapter); } /** diff --git a/core/computed/metrics/lantern-largest-contentful-paint.js b/core/computed/metrics/lantern-largest-contentful-paint.js index 8348c2d9aff1..4afb9d86d08f 100644 --- a/core/computed/metrics/lantern-largest-contentful-paint.js +++ b/core/computed/metrics/lantern-largest-contentful-paint.js @@ -6,7 +6,7 @@ import {makeComputedArtifact} from '../computed-artifact.js'; import {LargestContentfulPaint} from '../../lib/lantern/metrics/largest-contentful-paint.js'; -import {getComputationDataParams} from './lantern-metric.js'; +import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; /** @typedef {import('../../lib/lantern/metric.js').Extras} Extras */ @@ -19,7 +19,8 @@ class LanternLargestContentfulPaint extends LargestContentfulPaint { * @return {Promise} */ static async computeMetricWithGraphs(data, context, extras) { - return this.compute(await getComputationDataParams(data, context), extras); + return this.compute(await getComputationDataParams(data, context), extras) + .catch(lanternErrorAdapter); } /** diff --git a/core/computed/metrics/lantern-max-potential-fid.js b/core/computed/metrics/lantern-max-potential-fid.js index 894c4431c652..4772a95471fa 100644 --- a/core/computed/metrics/lantern-max-potential-fid.js +++ b/core/computed/metrics/lantern-max-potential-fid.js @@ -6,7 +6,7 @@ import {makeComputedArtifact} from '../computed-artifact.js'; import {MaxPotentialFID} from '../../lib/lantern/metrics/max-potential-fid.js'; -import {getComputationDataParams} from './lantern-metric.js'; +import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; /** @typedef {import('../../lib/lantern/metric.js').Extras} Extras */ @@ -19,7 +19,8 @@ class LanternMaxPotentialFID extends MaxPotentialFID { * @return {Promise} */ static async computeMetricWithGraphs(data, context, extras) { - return this.compute(await getComputationDataParams(data, context), extras); + return this.compute(await getComputationDataParams(data, context), extras) + .catch(lanternErrorAdapter); } /** diff --git a/core/computed/metrics/lantern-metric.js b/core/computed/metrics/lantern-metric.js index 9a7d779a3026..80f4d2abe23e 100644 --- a/core/computed/metrics/lantern-metric.js +++ b/core/computed/metrics/lantern-metric.js @@ -4,6 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import {LanternError} from '../../lib/lantern/lantern-error.js'; +import {LighthouseError} from '../../lib/lh-error.js'; import {LoadSimulator} from '../load-simulator.js'; import {PageDependencyGraph} from '../page-dependency-graph.js'; import {ProcessedNavigation} from '../processed-navigation.js'; @@ -24,4 +26,24 @@ async function getComputationDataParams(data, context) { return {simulator, graph, processedNavigation}; } -export {getComputationDataParams}; +/** + * @param {unknown} err + * @return {never} + */ +function lanternErrorAdapter(err) { + if (!(err instanceof LanternError)) { + throw err; + } + + const code = /** @type {keyof LighthouseError.errors} */ (err.message); + if (LighthouseError.errors[code]) { + throw new LighthouseError(LighthouseError.errors[code]); + } + + throw err; +} + +export { + getComputationDataParams, + lanternErrorAdapter, +}; diff --git a/core/computed/metrics/lantern-speed-index.js b/core/computed/metrics/lantern-speed-index.js index 1fad27ee57aa..f2538e9b4298 100644 --- a/core/computed/metrics/lantern-speed-index.js +++ b/core/computed/metrics/lantern-speed-index.js @@ -5,7 +5,7 @@ */ import {makeComputedArtifact} from '../computed-artifact.js'; -import {getComputationDataParams} from './lantern-metric.js'; +import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {Speedline} from '../speedline.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; import {SpeedIndex} from '../../lib/lantern/metrics/speed-index.js'; @@ -20,7 +20,8 @@ class LanternSpeedIndex extends SpeedIndex { * @return {Promise} */ static async computeMetricWithGraphs(data, context, extras) { - return this.compute(await getComputationDataParams(data, context), extras); + return this.compute(await getComputationDataParams(data, context), extras) + .catch(lanternErrorAdapter); } /** diff --git a/core/lib/lantern/lantern-error.js b/core/lib/lantern/lantern-error.js new file mode 100644 index 000000000000..54fa2116ddc5 --- /dev/null +++ b/core/lib/lantern/lantern-error.js @@ -0,0 +1,9 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +class LanternError extends Error {} + +export {LanternError}; diff --git a/core/lib/lantern/metrics/first-meaningful-paint.js b/core/lib/lantern/metrics/first-meaningful-paint.js index 93dafd900be6..867be1b3ff0b 100644 --- a/core/lib/lantern/metrics/first-meaningful-paint.js +++ b/core/lib/lantern/metrics/first-meaningful-paint.js @@ -6,8 +6,6 @@ import * as Lantern from '../types/lantern.js'; import {Metric} from '../metric.js'; -// TODO(15841): don't use LighthouseError -import {LighthouseError} from '../../lh-error.js'; import {FirstContentfulPaint} from './first-contentful-paint.js'; /** @typedef {import('../base-node.js').Node} Node */ @@ -32,7 +30,7 @@ class FirstMeaningfulPaint extends Metric { static getOptimisticGraph(dependencyGraph, processedNavigation) { const fmp = processedNavigation.timestamps.firstMeaningfulPaint; if (!fmp) { - throw new LighthouseError(LighthouseError.errors.NO_FMP); + throw new Error('NO_FMP'); } return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { cutoffTimestamp: fmp, @@ -51,7 +49,7 @@ class FirstMeaningfulPaint extends Metric { static getPessimisticGraph(dependencyGraph, processedNavigation) { const fmp = processedNavigation.timestamps.firstMeaningfulPaint; if (!fmp) { - throw new LighthouseError(LighthouseError.errors.NO_FMP); + throw new Error('NO_FMP'); } return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { diff --git a/core/lib/lantern/metrics/largest-contentful-paint.js b/core/lib/lantern/metrics/largest-contentful-paint.js index b7cdffb59ca4..505f276eff4b 100644 --- a/core/lib/lantern/metrics/largest-contentful-paint.js +++ b/core/lib/lantern/metrics/largest-contentful-paint.js @@ -6,8 +6,8 @@ import * as Lantern from '../types/lantern.js'; import {Metric} from '../metric.js'; -import {LighthouseError} from '../../../lib/lh-error.js'; import {FirstContentfulPaint} from './first-contentful-paint.js'; +import {LanternError} from '../lantern-error.js'; /** @typedef {import('../base-node.js').Node} Node */ @@ -45,7 +45,7 @@ class LargestContentfulPaint extends Metric { static getOptimisticGraph(dependencyGraph, processedNavigation) { const lcp = processedNavigation.timestamps.largestContentfulPaint; if (!lcp) { - throw new LighthouseError(LighthouseError.errors.NO_LCP); + throw new LanternError('NO_LCP'); } return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { @@ -62,7 +62,7 @@ class LargestContentfulPaint extends Metric { static getPessimisticGraph(dependencyGraph, processedNavigation) { const lcp = processedNavigation.timestamps.largestContentfulPaint; if (!lcp) { - throw new LighthouseError(LighthouseError.errors.NO_LCP); + throw new LanternError('NO_LCP'); } return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { diff --git a/core/test/computed/metrics/largest-contentful-paint-test.js b/core/test/computed/metrics/largest-contentful-paint-test.js index 3936c9fc1553..a50615f5d62f 100644 --- a/core/test/computed/metrics/largest-contentful-paint-test.js +++ b/core/test/computed/metrics/largest-contentful-paint-test.js @@ -48,14 +48,19 @@ Object { assert.equal(result.timestamp, 713038144775); }); - it('should fail to compute an observed value for old trace', async () => { - const settings = {throttlingMethod: 'provided'}; - const context = {settings, computedCache: new Map()}; - const URL = getURLArtifactFromDevtoolsLog(invalidDevtoolsLog); - const resultPromise = LargestContentfulPaint.request( - {gatherContext, trace: invalidTrace, devtoolsLog: invalidDevtoolsLog, settings, URL}, - context - ); - await expect(resultPromise).rejects.toThrow('NO_LCP'); + ['provided', 'simulate'].forEach(throttlingMethod => { + it(`should fail to compute a value for old trace (${throttlingMethod})`, async () => { + const settings = {throttlingMethod}; + const context = {settings, computedCache: new Map()}; + const URL = getURLArtifactFromDevtoolsLog(invalidDevtoolsLog); + const resultPromise = LargestContentfulPaint.request( + {gatherContext, trace: invalidTrace, devtoolsLog: invalidDevtoolsLog, settings, URL}, + context + ); + await expect(resultPromise).rejects.toMatchObject({ + code: 'NO_LCP', + friendlyMessage: expect.toBeDisplayString(/The page did not display content.*NO_LCP/), + }); + }); }); });