diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js index 7c65e840b022..50726d04313d 100644 --- a/lighthouse-core/gather/gather-runner.js +++ b/lighthouse-core/gather/gather-runner.js @@ -150,8 +150,19 @@ class GatherRunner { if (!mainRecord) { errorDef = LHError.errors.NO_DOCUMENT_REQUEST; } else if (mainRecord.failed) { - errorDef = {...LHError.errors.FAILED_DOCUMENT_REQUEST}; - errorDef.message += ` ${mainRecord.localizedFailDescription}.`; + const netErr = mainRecord.localizedFailDescription; + // Match all resolution and DNS failures + // https://cs.chromium.org/chromium/src/net/base/net_error_list.h?rcl=cd62979b + if ( + netErr === 'net::ERR_NAME_NOT_RESOLVED' || + netErr === 'net::ERR_NAME_RESOLUTION_FAILED' || + netErr.startsWith('net::ERR_DNS_') + ) { + errorDef = LHError.errors.DNS_FAILURE; + } else { + errorDef = {...LHError.errors.FAILED_DOCUMENT_REQUEST}; + errorDef.message += ` ${netErr}.`; + } } else if (mainRecord.hasErrorStatusCode()) { errorDef = {...LHError.errors.ERRORED_DOCUMENT_REQUEST}; errorDef.message += ` Status code: ${mainRecord.statusCode}.`; diff --git a/lighthouse-core/lib/lh-error.js b/lighthouse-core/lib/lh-error.js index 9b4049cf2fc2..dbaae2b083a3 100644 --- a/lighthouse-core/lib/lh-error.js +++ b/lighthouse-core/lib/lh-error.js @@ -188,6 +188,13 @@ const ERRORS = { lhrRuntimeError: true, }, + // DNS failure on main document (no resolution, timed out, etc) + DNS_FAILURE: { + code: 'DNS_FAILURE', + message: strings.dnsFailure, + lhrRuntimeError: true, + }, + // Hey! When adding a new error type, update lighthouse-result.proto too. }; diff --git a/lighthouse-core/lib/strings.js b/lighthouse-core/lib/strings.js index ead92c977bf0..3792cae3f65c 100644 --- a/lighthouse-core/lib/strings.js +++ b/lighthouse-core/lib/strings.js @@ -17,4 +17,5 @@ module.exports = { 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/test/gather/gather-runner-test.js b/lighthouse-core/test/gather/gather-runner-test.js index 2b773a8d8faa..c302d5db3be1 100644 --- a/lighthouse-core/test/gather/gather-runner-test.js +++ b/lighthouse-core/test/gather/gather-runner-test.js @@ -679,6 +679,18 @@ describe('GatherRunner', function() { assert.equal(error.code, 'ERRORED_DOCUMENT_REQUEST'); assert.ok(/^Lighthouse was unable to reliably load/.test(error.friendlyMessage)); }); + + it('fails when page domain doesn\'t resolve', () => { + const url = 'http://the-page.com'; + const mainRecord = new NetworkRequest(); + mainRecord.url = url; + mainRecord.failed = true; + mainRecord.localizedFailDescription = 'net::ERR_NAME_NOT_RESOLVED'; + 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)); + }); }); describe('#assertNoSecurityIssues', () => { @@ -1059,7 +1071,7 @@ describe('GatherRunner', function() { config: new Config({}), }).then(artifacts => { assert.equal(artifacts.LighthouseRunWarnings.length, 1); - assert.ok(/unable.*load the page/.test(artifacts.LighthouseRunWarnings[0])); + assert.ok(/DNS servers could not resolve/.test(artifacts.LighthouseRunWarnings[0])); }); }); diff --git a/proto/lighthouse-result.proto b/proto/lighthouse-result.proto index a34ce7abbf63..0af762379418 100644 --- a/proto/lighthouse-result.proto +++ b/proto/lighthouse-result.proto @@ -49,6 +49,8 @@ enum LighthouseError { PROTOCOL_TIMEOUT = 17; // Used when the page is not responding after maxWaitForLoad. PAGE_HUNG = 18; + // DNS failure on main document (no resolution, timed out, etc) + DNS_FAILURE = 19; } // The overarching Lighthouse Response object (LHR)