diff --git a/clients/test/lightrider-entry-test.js b/clients/test/lightrider-entry-test.js index 408c7dc944d2..2151241c4286 100644 --- a/clients/test/lightrider-entry-test.js +++ b/clients/test/lightrider-entry-test.js @@ -14,7 +14,10 @@ const LHError = require('../../lighthouse-core/lib/lh-error.js'); describe('lightrider-entry', () => { describe('#runLighthouseInLR', () => { it('returns a runtimeError LHR when lighthouse throws a runtimeError', async () => { - const connectionError = new LHError(LHError.errors.FAILED_DOCUMENT_REQUEST); + const connectionError = new LHError( + LHError.errors.FAILED_DOCUMENT_REQUEST, + {errorDetails: 'Bad connection req'} + ); assert.strictEqual(connectionError.lhrRuntimeError, true); const mockConnection = { async connect() { diff --git a/lighthouse-core/gather/driver.js b/lighthouse-core/gather/driver.js index c49e512218f3..6b92db6db316 100644 --- a/lighthouse-core/gather/driver.js +++ b/lighthouse-core/gather/driver.js @@ -281,8 +281,10 @@ class Driver { this._nextProtocolTimeout = DEFAULT_PROTOCOL_TIMEOUT; return new Promise(async (resolve, reject) => { const asyncTimeout = setTimeout((() => { - const err = new LHError(LHError.errors.PROTOCOL_TIMEOUT); - err.message += ` Method: ${method}`; + const err = new LHError( + LHError.errors.PROTOCOL_TIMEOUT, + {protocolMethod: method} + ); reject(err); }), timeout); try { diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js index 50726d04313d..70c2c7a48746 100644 --- a/lighthouse-core/gather/gather-runner.js +++ b/lighthouse-core/gather/gather-runner.js @@ -146,9 +146,8 @@ class GatherRunner { return URL.equalWithExcludedFragments(record.url, url); }); - let errorDef; if (!mainRecord) { - errorDef = LHError.errors.NO_DOCUMENT_REQUEST; + return new LHError(LHError.errors.NO_DOCUMENT_REQUEST); } else if (mainRecord.failed) { const netErr = mainRecord.localizedFailDescription; // Match all resolution and DNS failures @@ -158,18 +157,18 @@ class GatherRunner { netErr === 'net::ERR_NAME_RESOLUTION_FAILED' || netErr.startsWith('net::ERR_DNS_') ) { - errorDef = LHError.errors.DNS_FAILURE; + return new LHError(LHError.errors.DNS_FAILURE); } else { - errorDef = {...LHError.errors.FAILED_DOCUMENT_REQUEST}; - errorDef.message += ` ${netErr}.`; + return new LHError( + LHError.errors.FAILED_DOCUMENT_REQUEST, + {errorDetails: netErr} + ); } } else if (mainRecord.hasErrorStatusCode()) { - errorDef = {...LHError.errors.ERRORED_DOCUMENT_REQUEST}; - errorDef.message += ` Status code: ${mainRecord.statusCode}.`; - } - - if (errorDef) { - return new LHError(errorDef); + return new LHError( + LHError.errors.ERRORED_DOCUMENT_REQUEST, + {statusCode: `${mainRecord.statusCode}`} + ); } } @@ -180,12 +179,13 @@ class GatherRunner { */ static assertNoSecurityIssues({securityState, explanations}) { if (securityState === 'insecure') { - const errorDef = {...LHError.errors.INSECURE_DOCUMENT_REQUEST}; const insecureDescriptions = explanations .filter(exp => exp.securityState === 'insecure') .map(exp => exp.description); - errorDef.message += ` ${insecureDescriptions.join(' ')}`; - throw new LHError(errorDef); + throw new LHError( + LHError.errors.INSECURE_DOCUMENT_REQUEST, + {securityMessages: insecureDescriptions.join(' ')} + ); } } diff --git a/lighthouse-core/lib/i18n/en-US.json b/lighthouse-core/lib/i18n/en-US.json index 0bbdab614f42..e35e009b142c 100644 --- a/lighthouse-core/lib/i18n/en-US.json +++ b/lighthouse-core/lib/i18n/en-US.json @@ -923,6 +923,58 @@ "message": "{timeInMs, number, seconds} s", "description": "Used to show the duration in seconds that something lasted. The {timeInMs} placeholder will be replaced with the time duration, shown in seconds (e.g. 5.2 s)" }, + "lighthouse-core/lib/lh-error.js | badTraceRecording": { + "message": "Something went wrong with recording the trace over your page load. Please run Lighthouse again.", + "description": "Error message explaining that the network trace was not able to be recorded for the Lighthouse run." + }, + "lighthouse-core/lib/lh-error.js | didntCollectScreenshots": { + "message": "Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse.", + "description": "Error message explaining that the Lighthouse run was not able to collect screenshots through Chrome." + }, + "lighthouse-core/lib/lh-error.js | dnsFailure": { + "message": "DNS servers could not resolve the provided domain.", + "description": "Error message explaining that the requested page could not be resolved by the DNS server." + }, + "lighthouse-core/lib/lh-error.js | internalChromeError": { + "message": "An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.", + "description": "Error message explaining that Chrome has encountered an error during the Lighthouse run, and that Chrome should be restarted." + }, + "lighthouse-core/lib/lh-error.js | pageLoadFailed": { + "message": "Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests.", + "description": "Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability." + }, + "lighthouse-core/lib/lh-error.js | pageLoadFailedHung": { + "message": "Lighthouse was unable to reliably load the URL you requested because the page stopped responding.", + "description": "Error message explaining that Lighthouse couldn't complete because the page has stopped responding to its instructions." + }, + "lighthouse-core/lib/lh-error.js | pageLoadFailedInsecure": { + "message": "The URL you have provided does not have valid security credentials. ({securityMessages})", + "description": "Error message explaining that the credentials included in the Lighthouse run were invalid, so the URL cannot be accessed." + }, + "lighthouse-core/lib/lh-error.js | pageLoadFailedWithDetails": { + "message": "Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Details: {errorDetails})", + "description": "Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability." + }, + "lighthouse-core/lib/lh-error.js | pageLoadFailedWithStatusCode": { + "message": "Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Status code: {statusCode})", + "description": "Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability." + }, + "lighthouse-core/lib/lh-error.js | pageLoadTookTooLong": { + "message": "Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse.", + "description": "Error message explaining that the page loaded too slowly to perform a Lighthouse run." + }, + "lighthouse-core/lib/lh-error.js | protocolTimeout": { + "message": "Waiting for DevTools protocol response has exceeded the allotted time. (Method: {protocolMethod})", + "description": "Error message explaining that the Chrome Devtools protocol has exceeded the maximum timeout allowed." + }, + "lighthouse-core/lib/lh-error.js | requestContentTimeout": { + "message": "Fetching resource content has exceeded the allotted time", + "description": "Error message explaining that fetching the resources of the webpage has taken longer than the maximum time." + }, + "lighthouse-core/lib/lh-error.js | urlInvalid": { + "message": "The URL you have provided appears to be invalid.", + "description": "Error message explaining that the provided URL Lighthouse points to is not valid, and cannot be loaded." + }, "lighthouse-core/report/html/renderer/util.js | auditGroupExpandTooltip": { "message": "Show audits", "description": "The tooltip text on an expandable chevron icon. Clicking the icon expands a section to reveal a list of audit results that was hidden by default." diff --git a/lighthouse-core/lib/lh-error.js b/lighthouse-core/lib/lh-error.js index dbaae2b083a3..c83015e3f248 100644 --- a/lighthouse-core/lib/lh-error.js +++ b/lighthouse-core/lib/lh-error.js @@ -5,7 +5,40 @@ */ 'use strict'; -const strings = require('./strings'); +const i18n = require('./i18n/i18n.js'); + +/* eslint-disable max-len */ +const UIStrings = { + /** Error message explaining that the Lighthouse run was not able to collect screenshots through Chrome.*/ + didntCollectScreenshots: `Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse.`, + /** Error message explaining that the network trace was not able to be recorded for the Lighthouse run. */ + badTraceRecording: 'Something went wrong with recording the trace over your page load. Please run Lighthouse again.', + /** Error message explaining that the page loaded too slowly to perform a Lighthouse run. */ + pageLoadTookTooLong: 'Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse.', + /** Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability. */ + pageLoadFailed: 'Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests.', + /** Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability. */ + pageLoadFailedWithStatusCode: 'Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Status code: {statusCode})', + /** Error message explaining that Lighthouse could not load the requested URL and the steps that might be taken to fix the unreliability. */ + pageLoadFailedWithDetails: 'Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests. (Details: {errorDetails})', + /** Error message explaining that the credentials included in the Lighthouse run were invalid, so the URL cannot be accessed. */ + pageLoadFailedInsecure: 'The URL you have provided does not have valid security credentials. ({securityMessages})', + /** Error message explaining that Chrome has encountered an error during the Lighthouse run, and that Chrome should be restarted. */ + internalChromeError: 'An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.', + /** Error message explaining that fetching the resources of the webpage has taken longer than the maximum time. */ + requestContentTimeout: 'Fetching resource content has exceeded the allotted time', + /** Error message explaining that the provided URL Lighthouse points to is not valid, and cannot be loaded. */ + urlInvalid: 'The URL you have provided appears to be invalid.', + /** Error message explaining that the Chrome Devtools protocol has exceeded the maximum timeout allowed. */ + protocolTimeout: 'Waiting for DevTools protocol response has exceeded the allotted time. (Method: {protocolMethod})', + /** Error message explaining that the requested page could not be resolved by the DNS server. */ + dnsFailure: 'DNS servers could not resolve the provided domain.', + /** Error message explaining that Lighthouse couldn't complete because the page has stopped responding to its instructions. */ + pageLoadFailedHung: 'Lighthouse was unable to reliably load the URL you requested because the page stopped responding.', +}; + +const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings); + /** * @typedef LighthouseErrorDefinition @@ -24,7 +57,7 @@ class LighthouseError extends Error { super(errorDefinition.code); this.name = 'LHError'; this.code = errorDefinition.code; - this.friendlyMessage = errorDefinition.message; + this.friendlyMessage = str_(errorDefinition.message, properties); this.lhrRuntimeError = !!errorDefinition.lhrRuntimeError; if (properties) Object.assign(this, properties); @@ -70,107 +103,113 @@ const ERRORS = { // Screenshot/speedline errors NO_SPEEDLINE_FRAMES: { code: 'NO_SPEEDLINE_FRAMES', - message: strings.didntCollectScreenshots, + message: UIStrings.didntCollectScreenshots, lhrRuntimeError: true, }, SPEEDINDEX_OF_ZERO: { code: 'SPEEDINDEX_OF_ZERO', - message: strings.didntCollectScreenshots, + message: UIStrings.didntCollectScreenshots, lhrRuntimeError: true, }, NO_SCREENSHOTS: { code: 'NO_SCREENSHOTS', - message: strings.didntCollectScreenshots, + message: UIStrings.didntCollectScreenshots, lhrRuntimeError: true, }, INVALID_SPEEDLINE: { code: 'INVALID_SPEEDLINE', - message: strings.didntCollectScreenshots, + message: UIStrings.didntCollectScreenshots, lhrRuntimeError: true, }, // Trace parsing errors NO_TRACING_STARTED: { code: 'NO_TRACING_STARTED', - message: strings.badTraceRecording, + message: UIStrings.badTraceRecording, lhrRuntimeError: true, }, NO_NAVSTART: { code: 'NO_NAVSTART', - message: strings.badTraceRecording, + message: UIStrings.badTraceRecording, lhrRuntimeError: true, }, NO_FCP: { code: 'NO_FCP', - message: strings.badTraceRecording, + message: UIStrings.badTraceRecording, lhrRuntimeError: true, }, NO_DCL: { code: 'NO_DCL', - message: strings.badTraceRecording, + message: UIStrings.badTraceRecording, lhrRuntimeError: true, }, NO_FMP: { code: 'NO_FMP', - message: strings.badTraceRecording, + message: UIStrings.badTraceRecording, }, // TTI calculation failures - FMP_TOO_LATE_FOR_FCPUI: {code: 'FMP_TOO_LATE_FOR_FCPUI', message: strings.pageLoadTookTooLong}, - NO_FCPUI_IDLE_PERIOD: {code: 'NO_FCPUI_IDLE_PERIOD', message: strings.pageLoadTookTooLong}, - NO_TTI_CPU_IDLE_PERIOD: {code: 'NO_TTI_CPU_IDLE_PERIOD', message: strings.pageLoadTookTooLong}, + FMP_TOO_LATE_FOR_FCPUI: {code: 'FMP_TOO_LATE_FOR_FCPUI', message: UIStrings.pageLoadTookTooLong}, + NO_FCPUI_IDLE_PERIOD: {code: 'NO_FCPUI_IDLE_PERIOD', message: UIStrings.pageLoadTookTooLong}, + NO_TTI_CPU_IDLE_PERIOD: {code: 'NO_TTI_CPU_IDLE_PERIOD', message: UIStrings.pageLoadTookTooLong}, NO_TTI_NETWORK_IDLE_PERIOD: { code: 'NO_TTI_NETWORK_IDLE_PERIOD', - message: strings.pageLoadTookTooLong, + message: UIStrings.pageLoadTookTooLong, }, // Page load failures NO_DOCUMENT_REQUEST: { code: 'NO_DOCUMENT_REQUEST', - message: strings.pageLoadFailed, + message: UIStrings.pageLoadFailed, lhrRuntimeError: true, }, - /* Used when DevTools reports loading failed. Usually an internal (Chrome) issue. */ + /* Used when DevTools reports loading failed. Usually an internal (Chrome) issue. + * Requries an additional `errorDetails` field for translation. + */ FAILED_DOCUMENT_REQUEST: { code: 'FAILED_DOCUMENT_REQUEST', - message: strings.pageLoadFailed, + message: UIStrings.pageLoadFailedWithDetails, lhrRuntimeError: true, }, - /* Used when status code is 4xx or 5xx. */ + /* Used when status code is 4xx or 5xx. + * Requires an additional `statusCode` field for translation. + */ ERRORED_DOCUMENT_REQUEST: { code: 'ERRORED_DOCUMENT_REQUEST', - message: strings.pageLoadFailed, + message: UIStrings.pageLoadFailedWithStatusCode, lhrRuntimeError: true, }, - /* Used when security error prevents page load. */ + /* Used when security error prevents page load. + * Requires an additional `securityMessages` field for translation. + */ INSECURE_DOCUMENT_REQUEST: { code: 'INSECURE_DOCUMENT_REQUEST', - message: strings.pageLoadFailedInsecure, + message: UIStrings.pageLoadFailedInsecure, lhrRuntimeError: true, }, /* Used when the page stopped responding and did not finish loading. */ PAGE_HUNG: { code: 'PAGE_HUNG', - message: strings.pageLoadFailedHung, + message: UIStrings.pageLoadFailedHung, lhrRuntimeError: true, }, // Protocol internal failures TRACING_ALREADY_STARTED: { code: 'TRACING_ALREADY_STARTED', - message: strings.internalChromeError, + message: UIStrings.internalChromeError, pattern: /Tracing.*started/, lhrRuntimeError: true, }, PARSING_PROBLEM: { code: 'PARSING_PROBLEM', - message: strings.internalChromeError, + message: UIStrings.internalChromeError, pattern: /Parsing problem/, lhrRuntimeError: true, }, READ_FAILED: { code: 'READ_FAILED', - message: strings.internalChromeError, + message: UIStrings.internalChromeError, pattern: /Read failed/, lhrRuntimeError: true, }, @@ -178,20 +217,22 @@ const ERRORS = { // URL parsing failures INVALID_URL: { code: 'INVALID_URL', - message: strings.urlInvalid, + message: UIStrings.urlInvalid, }, - // Protocol timeout failures + /* Protocol timeout failures + * Requires an additional `icuProtocolMethod` field for translation. + */ PROTOCOL_TIMEOUT: { code: 'PROTOCOL_TIMEOUT', - message: strings.protocolTimeout, + message: UIStrings.protocolTimeout, lhrRuntimeError: true, }, // DNS failure on main document (no resolution, timed out, etc) DNS_FAILURE: { code: 'DNS_FAILURE', - message: strings.dnsFailure, + message: UIStrings.dnsFailure, lhrRuntimeError: true, }, @@ -203,4 +244,4 @@ LighthouseError.errors = ERRORS; LighthouseError.NO_ERROR = 'NO_ERROR'; LighthouseError.UNKNOWN_ERROR = 'UNKNOWN_ERROR'; module.exports = LighthouseError; - +module.exports.UIStrings = UIStrings; diff --git a/lighthouse-core/lib/strings.js b/lighthouse-core/lib/strings.js deleted file mode 100644 index 3792cae3f65c..000000000000 --- a/lighthouse-core/lib/strings.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license Copyright 2018 Google Inc. 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'; - -/* eslint-disable max-len */ -module.exports = { - didntCollectScreenshots: `Chrome didn't collect any screenshots during the page load. Please make sure there is content visible on the page, and then try re-running Lighthouse.`, - badTraceRecording: `Something went wrong with recording the trace over your page load. Please run Lighthouse again.`, - pageLoadTookTooLong: `Your page took too long to load. Please follow the opportunities in the report to reduce your page load time, and then try re-running Lighthouse.`, - pageLoadFailed: `Lighthouse was unable to reliably load the page you requested. Make sure you are testing the correct URL and that the server is properly responding to all requests.`, - pageLoadFailedHung: `Lighthouse was unable to reliably load the URL you requested because the page stopped responding.`, - pageLoadFailedInsecure: `The URL you have provided does not have valid security credentials.`, - internalChromeError: `An internal Chrome error occurred. Please restart Chrome and try re-running Lighthouse.`, - requestContentTimeout: 'Fetching resource content has exceeded the allotted time', - urlInvalid: `The URL you have provided appears to be invalid.`, - protocolTimeout: `Waiting for DevTools protocol response has exceeded the allotted time.`, - dnsFailure: `DNS servers could not resolve the provided domain.`, -}; diff --git a/lighthouse-core/runner.js b/lighthouse-core/runner.js index 83d84b8fb732..a77a5a8a6d2f 100644 --- a/lighthouse-core/runner.js +++ b/lighthouse-core/runner.js @@ -30,8 +30,8 @@ class Runner { * @return {Promise} */ static async run(connection, runOpts) { + const settings = runOpts.config.settings; try { - const settings = runOpts.config.settings; const runnerStatus = {msg: 'Runner setup', id: 'lh:runner:run'}; log.time(runnerStatus, 'verbose'); @@ -157,6 +157,8 @@ class Runner { return {lhr, artifacts, report}; } catch (err) { + // i18n error strings + err.friendlyMessage = i18n.getFormatted(err.friendlyMessage, settings.locale); await Sentry.captureException(err, {level: 'fatal'}); throw err; } @@ -193,7 +195,6 @@ class Runner { if (!runnerOpts.config.passes) { throw new Error('No browser artifacts are either provided or requested.'); } - const driver = runnerOpts.driverMock || new Driver(connection); const gatherOpts = { driver, diff --git a/lighthouse-core/test/gather/driver-test.js b/lighthouse-core/test/gather/driver-test.js index a68266a4bfcf..3229755d6533 100644 --- a/lighthouse-core/test/gather/driver-test.js +++ b/lighthouse-core/test/gather/driver-test.js @@ -166,6 +166,8 @@ describe('Browser Driver', () => { assert.ok(false, 'long-running getRequestContent supposed to reject'); }, e => { assert.equal(e.code, 'PROTOCOL_TIMEOUT'); + expect(e.friendlyMessage).toBeDisplayString( + /^Waiting for DevTools.*Method: Network.getResponseBody/); }); }); diff --git a/lighthouse-core/test/gather/gather-runner-test.js b/lighthouse-core/test/gather/gather-runner-test.js index c302d5db3be1..68c2076e109b 100644 --- a/lighthouse-core/test/gather/gather-runner-test.js +++ b/lighthouse-core/test/gather/gather-runner-test.js @@ -646,7 +646,8 @@ describe('GatherRunner', function() { const error = GatherRunner.getPageLoadError(url, [mainRecord]); assert.equal(error.message, 'FAILED_DOCUMENT_REQUEST'); assert.equal(error.code, 'FAILED_DOCUMENT_REQUEST'); - assert.ok(/^Lighthouse was unable to reliably load/.test(error.friendlyMessage)); + expect(error.friendlyMessage) + .toBeDisplayString(/^Lighthouse was unable to reliably load.*foobar/); }); it('fails when page times out', () => { @@ -655,7 +656,7 @@ describe('GatherRunner', function() { const error = GatherRunner.getPageLoadError(url, records); assert.equal(error.message, 'NO_DOCUMENT_REQUEST'); assert.equal(error.code, 'NO_DOCUMENT_REQUEST'); - assert.ok(/^Lighthouse was unable to reliably load/.test(error.friendlyMessage)); + expect(error.friendlyMessage).toBeDisplayString(/^Lighthouse was unable to reliably load/); }); it('fails when page returns with a 404', () => { @@ -666,7 +667,8 @@ describe('GatherRunner', function() { const error = GatherRunner.getPageLoadError(url, [mainRecord]); assert.equal(error.message, 'ERRORED_DOCUMENT_REQUEST'); assert.equal(error.code, 'ERRORED_DOCUMENT_REQUEST'); - assert.ok(/^Lighthouse was unable to reliably load/.test(error.friendlyMessage)); + expect(error.friendlyMessage) + .toBeDisplayString(/^Lighthouse was unable to reliably load.*404/); }); it('fails when page returns with a 500', () => { @@ -677,7 +679,8 @@ describe('GatherRunner', function() { const error = GatherRunner.getPageLoadError(url, [mainRecord]); assert.equal(error.message, 'ERRORED_DOCUMENT_REQUEST'); assert.equal(error.code, 'ERRORED_DOCUMENT_REQUEST'); - assert.ok(/^Lighthouse was unable to reliably load/.test(error.friendlyMessage)); + expect(error.friendlyMessage) + .toBeDisplayString(/^Lighthouse was unable to reliably load.*500/); }); it('fails when page domain doesn\'t resolve', () => { @@ -689,7 +692,7 @@ describe('GatherRunner', function() { const error = GatherRunner.getPageLoadError(url, [mainRecord]); assert.equal(error.message, 'DNS_FAILURE'); assert.equal(error.code, 'DNS_FAILURE'); - assert.ok(/^DNS servers could not resolve/.test(error.friendlyMessage)); + expect(error.friendlyMessage).toBeDisplayString(/^DNS servers could not resolve/); }); }); @@ -705,7 +708,7 @@ describe('GatherRunner', function() { const insecureSecurityState = { explanations: [ { - description: 'reason 1.', + description: 'reason 1', securityState: 'insecure', }, { @@ -713,7 +716,7 @@ describe('GatherRunner', function() { securityState: 'info', }, { - description: 'reason 2.', + description: 'reason 2', securityState: 'insecure', }, ], @@ -725,8 +728,8 @@ describe('GatherRunner', function() { } catch (err) { assert.equal(err.message, 'INSECURE_DOCUMENT_REQUEST'); assert.equal(err.code, 'INSECURE_DOCUMENT_REQUEST'); - /* eslint-disable-next-line max-len */ - assert.equal(err.friendlyMessage, 'The URL you have provided does not have valid security credentials. reason 1. reason 2.'); + expect(err.friendlyMessage) + .toBeDisplayString(/The URL.*security credentials.*reason 1 reason 2/); } }); }); @@ -1071,7 +1074,8 @@ describe('GatherRunner', function() { config: new Config({}), }).then(artifacts => { assert.equal(artifacts.LighthouseRunWarnings.length, 1); - assert.ok(/DNS servers could not resolve/.test(artifacts.LighthouseRunWarnings[0])); + expect(artifacts.LighthouseRunWarnings[0]) + .toBeDisplayString(/DNS servers could not resolve/); }); }); diff --git a/lighthouse-core/test/runner-test.js b/lighthouse-core/test/runner-test.js index 45a83721e6b4..d3683f316236 100644 --- a/lighthouse-core/test/runner-test.js +++ b/lighthouse-core/test/runner-test.js @@ -609,6 +609,27 @@ describe('Runner', () => { assert.ok(lhr.runtimeError.message.includes(NO_FCP.message)); }); + it('localized errors thrown from driver', async () => { + const erroringDriver = {...driverMock, + async connect() { + const err = new LHError( + LHError.errors.PROTOCOL_TIMEOUT, + {protocolMethod: 'Method.Failure'} + ); + throw err; + }, + }; + + try { + await Runner.run(null, {url: 'https://example.com/', driverMock: erroringDriver, config: new Config()}); + assert.fail('should have thrown'); + } catch (err) { + assert.equal(err.code, LHError.errors.PROTOCOL_TIMEOUT.code); + assert.ok(/^Waiting for DevTools protocol.*Method: Method.Failure/.test(err.friendlyMessage), + 'did not localize error message'); + } + }); + it('can handle array of outputs', async () => { const url = 'https://example.com'; const config = new Config({