Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: centralize error strings #4280

Merged
merged 6 commits into from
Feb 1, 2018
Merged
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
27 changes: 10 additions & 17 deletions lighthouse-cli/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ const Printer = require('./printer');
const ChromeLauncher = require('chrome-launcher');

const yargsParser = require('yargs-parser');
const lighthouse = require('../lighthouse-core/index.js');
const lighthouse = require('../lighthouse-core');
const log = require('lighthouse-logger');
const getFilenamePrefix = require('../lighthouse-core/lib/file-namer.js').getFilenamePrefix;
const assetSaver = require('../lighthouse-core/lib/asset-saver.js');
const getFilenamePrefix = require('../lighthouse-core/lib/file-namer').getFilenamePrefix;
const assetSaver = require('../lighthouse-core/lib/asset-saver');

const opn = require('opn');

Expand Down Expand Up @@ -65,34 +65,27 @@ function showConnectionError() {
process.exit(_RUNTIME_ERROR_CODE);
}

function showProtocolTimeoutError() {
console.error('Debugger protocol timed out while connecting to Chrome.');
process.exit(_PROTOCOL_TIMEOUT_EXIT_CODE);
}

/**
* @param {!LH.LighthouseError} err
*/
function showRuntimeError(err) {
console.error('Runtime error encountered:', err);
console.error('Runtime error encountered:', err.friendlyMessage || err.message);
if (err.stack) {
console.error(err.stack);
}
process.exit(_RUNTIME_ERROR_CODE);
}

function showProtocolTimeoutError() {
console.error('Debugger protocol timed out while connecting to Chrome.');
process.exit(_PROTOCOL_TIMEOUT_EXIT_CODE);
}

function showPageLoadError() {
console.error('Unable to load the page. Please verify the url you are trying to review.');
process.exit(_RUNTIME_ERROR_CODE);
}

/**
* @param {!LH.LighthouseError} err
*/
function handleError(err) {
if (err.code === 'PAGE_LOAD_ERROR') {
showPageLoadError();
} else if (err.code === 'ECONNREFUSED') {
if (err.code === 'ECONNREFUSED') {
showConnectionError();
} else if (err.code === 'CRI_TIMEOUT') {
showProtocolTimeoutError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class UnminifiedJavaScript extends ByteEfficiencyAudit {
name: 'unminified-javascript',
description: 'Minify JavaScript',
informative: true,
helpText: 'Minifying JavaScript files can reduce payload sizes and script parse time.' +
helpText: 'Minifying JavaScript files can reduce payload sizes and script parse time. ' +
'[Learn more](https://developers.google.com/speed/docs/insights/MinifyResources).',
requiredArtifacts: ['Scripts', 'devtoolsLogs'],
};
Expand Down
16 changes: 9 additions & 7 deletions lighthouse-core/audits/consistently-interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
'use strict';

const Audit = require('./audit');
const Util = require('../report/v2/renderer/util.js');
const Util = require('../report/v2/renderer/util');
const NetworkRecorder = require('../lib/network-recorder');
const TracingProcessor = require('../lib/traces/tracing-processor');
const LHError = require('../lib/errors');

// Parameters (in ms) for log-normal CDF scoring. To see the curve:
// https://www.desmos.com/calculator/uti67afozh
Expand Down Expand Up @@ -145,10 +146,11 @@ class ConsistentlyInteractiveMetric extends Audit {
}
}

const culprit = cpuCandidate ? 'Network' : 'Main thread';
throw new Error(`${culprit} activity continued through the end of the trace recording. ` +
'Consistently Interactive requires a minimum of 5 seconds of both main thread idle and ' +
'network idle.');
throw new LHError(
cpuCandidate
? LHError.errors.NO_TTI_NETWORK_IDLE_PERIOD
: LHError.errors.NO_TTI_CPU_IDLE_PERIOD
);
}

/**
Expand All @@ -166,11 +168,11 @@ class ConsistentlyInteractiveMetric extends Audit {
return Promise.all(computedArtifacts)
.then(([networkRecords, traceOfTab]) => {
if (!traceOfTab.timestamps.firstMeaningfulPaint) {
throw new Error('No firstMeaningfulPaint found in trace.');
throw new LHError(LHError.errors.NO_FMP);
}

if (!traceOfTab.timestamps.domContentLoaded) {
throw new Error('No domContentLoaded found in trace.');
throw new LHError(LHError.errors.NO_DCL);
}

const longTasks = TracingProcessor.getMainThreadTopLevelEvents(traceOfTab)
Expand Down
5 changes: 3 additions & 2 deletions lighthouse-core/audits/estimated-input-latency.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
'use strict';

const Audit = require('./audit');
const Util = require('../report/v2/renderer/util.js');
const Util = require('../report/v2/renderer/util');
const TracingProcessor = require('../lib/traces/tracing-processor');
const LHError = require('../lib/errors');

// Parameters (in ms) for log-normal CDF scoring. To see the curve:
// https://www.desmos.com/calculator/srv0hqhf7d
Expand Down Expand Up @@ -35,7 +36,7 @@ class EstimatedInputLatency extends Audit {
static calculate(tabTrace) {
const startTime = tabTrace.timings.firstMeaningfulPaint;
if (!startTime) {
throw new Error('No firstMeaningfulPaint event found in trace');
throw new LHError(LHError.errors.NO_FMP);
}

const latencyPercentiles = TracingProcessor.getRiskToResponsiveness(tabTrace, startTime);
Expand Down
7 changes: 4 additions & 3 deletions lighthouse-core/audits/first-meaningful-paint.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
'use strict';

const Audit = require('./audit');
const Util = require('../report/v2/renderer/util.js');
const Util = require('../report/v2/renderer/util');
const LHError = require('../lib/errors');

// Parameters (in ms) for log-normal CDF scoring. To see the curve:
// https://www.desmos.com/calculator/joz3pqttdq
Expand Down Expand Up @@ -40,13 +41,13 @@ class FirstMeaningfulPaint extends Audit {
const trace = artifacts.traces[this.DEFAULT_PASS];
return artifacts.requestTraceOfTab(trace).then(tabTrace => {
if (!tabTrace.firstMeaningfulPaintEvt) {
throw new Error('No usable `firstMeaningfulPaint(Candidate)` events found in trace');
throw new LHError(LHError.errors.NO_FMP);
}

// navigationStart is currently essential to FMP calculation.
// see: https://github.com/GoogleChrome/lighthouse/issues/753
if (!tabTrace.navigationStartEvt) {
throw new Error('No `navigationStart` event found in trace');
throw new LHError(LHError.errors.NO_NAVSTART);
}

const result = this.calculateScore(tabTrace);
Expand Down
5 changes: 3 additions & 2 deletions lighthouse-core/audits/speed-index-metric.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

const Audit = require('./audit');
const Util = require('../report/v2/renderer/util');
const LHError = require('../lib/errors');

// Parameters (in ms) for log-normal CDF scoring. To see the curve:
// https://www.desmos.com/calculator/mdgjzchijg
Expand Down Expand Up @@ -40,11 +41,11 @@ class SpeedIndexMetric extends Audit {
// run speedline
return artifacts.requestSpeedline(trace).then(speedline => {
if (speedline.frames.length === 0) {
throw new Error('Trace unable to find visual progress frames.');
throw new LHError(LHError.errors.NO_SPEEDLINE_FRAMES);
}

if (speedline.perceptualSpeedIndex === 0) {
throw new Error('Error in Speedline calculating Speed Index (speedIndex of 0).');
throw new LHError(LHError.errors.SPEEDINDEX_OF_ZERO);
}

let visuallyReadyInMs = undefined;
Expand Down
11 changes: 5 additions & 6 deletions lighthouse-core/gather/computed/first-interactive.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

const ComputedArtifact = require('./computed-artifact');
const TracingProcessor = require('../../lib/traces/tracing-processor');
const LHError = require('../../lib/errors');

const LONG_TASK_THRESHOLD = 50;

Expand All @@ -15,8 +16,6 @@ const MIN_TASK_CLUSTER_PADDING = 1000;
const MIN_TASK_CLUSTER_FMP_DISTANCE = 5000;

const MAX_QUIET_WINDOW_SIZE = 5000;
const TRACE_BUSY_MSG = 'The main thread was busy for the entire trace recording. ' +
'First Interactive requires the main thread to be idle for several seconds.';

// Window size should be three seconds at 15 seconds after FMP
const EXPONENTIATION_COEFFICIENT = -Math.log(3 - 1) / 15;
Expand Down Expand Up @@ -143,7 +142,7 @@ class FirstInteractive extends ComputedArtifact {

// Check that we have a long enough trace
if (windowEnd > traceEnd) {
throw new Error(TRACE_BUSY_MSG);
throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
}

// Check that this task isn't the beginning of a cluster
Expand All @@ -160,7 +159,7 @@ class FirstInteractive extends ComputedArtifact {
}
}

throw new Error(TRACE_BUSY_MSG);
throw new LHError(LHError.errors.NO_FCPUI_IDLE_PERIOD);
}

/**
Expand All @@ -174,11 +173,11 @@ class FirstInteractive extends ComputedArtifact {
const traceEnd = traceOfTab.timings.traceEnd;

if (traceEnd - FMP < MAX_QUIET_WINDOW_SIZE) {
throw new Error('trace not at least 5 seconds longer than FMP');
throw new LHError(LHError.errors.FMP_TOO_LATE_FOR_FCPUI);
}

if (!FMP || !DCL) {
throw new Error(`No ${FMP ? 'domContentLoaded' : 'firstMeaningfulPaint'} event in trace`);
throw new LHError(FMP ? LHError.errors.NO_DCL : LHError.errors.NO_FMP);
}

const longTasksAfterFMP = TracingProcessor.getMainThreadTopLevelEvents(traceOfTab, FMP)
Expand Down
7 changes: 7 additions & 0 deletions lighthouse-core/gather/computed/speedline.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

const ComputedArtifact = require('./computed-artifact');
const speedline = require('speedline');
const LHError = require('../../lib/errors');

class Speedline extends ComputedArtifact {
get name() {
Expand All @@ -31,6 +32,12 @@ class Speedline extends ComputedArtifact {
fastMode: true,
include: 'perceptualSpeedIndex',
});
}).catch(err => {
if (/No screenshots found in trace/.test(err.message)) {
throw new LHError(LHError.errors.NO_SCREENSHOTS);
}

throw err;
});
}
}
Expand Down
5 changes: 3 additions & 2 deletions lighthouse-core/gather/computed/trace-of-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

const ComputedArtifact = require('./computed-artifact');
const log = require('lighthouse-logger');
const LHError = require('../../lib/errors');
const Sentry = require('../../lib/sentry');

// Bring in web-inspector for side effect of adding [].stableSort
Expand Down Expand Up @@ -51,13 +52,13 @@ class TraceOfTab extends ComputedArtifact {
// The first TracingStartedInPage in the trace is definitely our renderer thread of interest
// Beware: the tracingStartedInPage event can appear slightly after a navigationStart
const startedInPageEvt = keyEvents.find(e => e.name === 'TracingStartedInPage');
if (!startedInPageEvt) throw new Error('TracingStartedInPage was not found in the trace');
if (!startedInPageEvt) throw new LHError(LHError.errors.NO_TRACING_STARTED);
// Filter to just events matching the frame ID for sanity
const frameEvents = keyEvents.filter(e => e.args.frame === startedInPageEvt.args.data.page);

// Our navStart will be the last frame navigation in the trace
const navigationStart = frameEvents.filter(e => e.name === 'navigationStart').pop();
if (!navigationStart) throw new Error('navigationStart was not found in the trace');
if (!navigationStart) throw new LHError(LHError.errors.NO_NAVSTART);

// Find our first paint of this frame
const firstPaint = frameEvents.find(e => e.name === 'firstPaint' && e.ts > navigationStart.ts);
Expand Down
8 changes: 2 additions & 6 deletions lighthouse-core/gather/connections/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

const EventEmitter = require('events').EventEmitter;
const log = require('lighthouse-logger');
const LHError = require('../../lib/errors');

class Connection {
constructor() {
Expand Down Expand Up @@ -99,12 +100,7 @@ class Connection {
if (object.error) {
const logLevel = callback.options && callback.options.silent ? 'verbose' : 'error';
log.formatProtocol('method <= browser ERR', {method: callback.method}, logLevel);
let errMsg = `(${callback.method}): ${object.error.message}`;
if (object.error.data) errMsg += ` (${object.error.data})`;
const error = new Error(`Protocol error ${errMsg}`);
error.protocolMethod = callback.method;
error.protocolError = object.error.message;
throw error;
throw LHError.fromProtocolMessage(callback.method, object.error);
}

log.formatProtocol('method <= browser OK',
Expand Down
1 change: 1 addition & 0 deletions lighthouse-core/gather/connections/cri.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class CriConnection extends Connection {
}
});

// TODO: Replace this with an LHError on next major version bump
// Reject on error with code specifically indicating timeout in connection setup.
const err = new Error('Timeout waiting for initial Debugger Protocol connection.');
err.code = 'CRI_TIMEOUT';
Expand Down
18 changes: 10 additions & 8 deletions lighthouse-core/gather/gather-runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

const log = require('lighthouse-logger');
const Audit = require('../audits/audit');
const LHError = require('../lib/errors');
const URL = require('../lib/url-shim');
const NetworkRecorder = require('../lib/network-recorder.js');

Expand Down Expand Up @@ -149,17 +150,18 @@ class GatherRunner {
return URL.equalWithExcludedFragments(record.url, url);
});

let errorMessage;
let errorCode;
let errorReason;
if (!mainRecord) {
errorMessage = 'no document request found';
errorCode = LHError.errors.NO_DOCUMENT_REQUEST;
} else if (mainRecord.failed) {
errorMessage = `failed document request (${mainRecord.localizedFailDescription})`;
errorCode = LHError.errors.FAILED_DOCUMENT_REQUEST;
errorReason = mainRecord.localizedFailDescription;
}

if (errorMessage) {
log.error('GatherRunner', errorMessage, url);
const error = new Error(`Unable to load page: ${errorMessage}`);
error.code = 'PAGE_LOAD_ERROR';
if (errorCode) {
const error = new LHError(errorCode, {reason: errorReason});
log.error('GatherRunner', error.message, url);
return error;
}
}
Expand Down Expand Up @@ -355,7 +357,7 @@ class GatherRunner {
// runner to handle turning it into an error audit.
artifacts[gathererName] = err;
// Track page load errors separately, so we can fail loudly if needed.
if (err.code === 'PAGE_LOAD_ERROR') pageLoadFailures.push(err);
if (LHError.isPageLoadError(err)) pageLoadFailures.push(err);
});
});
}, Promise.resolve()).then(_ => {
Expand Down
Loading