forked from GoogleChrome/lighthouse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherrors-in-console.js
120 lines (102 loc) · 5 KB
/
errors-in-console.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
* @license Copyright 2017 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.
*/
/**
* @fileoverview Audits a page to determine whether it contains console errors.
* This is done by collecting Chrome console log messages and filtering out the non-error ones.
*/
import log from 'lighthouse-logger';
import {Audit} from './audit.js';
import {JSBundles} from '../computed/js-bundles.js';
import * as i18n from '../lib/i18n/i18n.js';
const UIStrings = {
/** Title of a Lighthouse audit that provides detail on browser errors. This descriptive title is shown to users when no browser errors were logged into the devtools console. */
title: 'No browser errors logged to the console',
/** Title of a Lighthouse audit that provides detail on browser errors. This descriptive title is shown to users when browser errors occurred and were logged into the devtools console. */
failureTitle: 'Browser errors were logged to the console',
/** Description of a Lighthouse audit that tells the user why errors being logged to the devtools console are a cause for concern and so should be fixed. This is displayed after a user expands the section to see more. No character length limits. */
description: 'Errors logged to the console indicate unresolved problems. ' +
'They can come from network request failures and other browser concerns. ' +
'[Learn more about this errors in console diagnostic audit](https://developer.chrome.com/docs/lighthouse/best-practices/errors-in-console/)',
};
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
/** @typedef {{ignoredPatterns?: Array<RegExp|string>}} AuditOptions */
class ErrorLogs extends Audit {
/**
* @return {LH.Audit.Meta}
*/
static get meta() {
return {
id: 'errors-in-console',
title: str_(UIStrings.title),
failureTitle: str_(UIStrings.failureTitle),
description: str_(UIStrings.description),
requiredArtifacts: ['ConsoleMessages', 'SourceMaps', 'Scripts'],
};
}
/** @return {AuditOptions} */
static get defaultOptions() {
// Any failed network requests with error messsage aren't actionable
return {ignoredPatterns: ['ERR_BLOCKED_BY_CLIENT.Inspector']};
}
/**
* @template {{description: string | undefined}} T
* @param {Array<T>} items
* @param {AuditOptions} options
* @return {Array<T>}
*/
static filterAccordingToOptions(items, options) {
const {ignoredPatterns, ...restOfOptions} = options;
const otherOptionKeys = Object.keys(restOfOptions);
if (otherOptionKeys.length) log.warn(this.meta.id, 'Unrecognized options', otherOptionKeys);
if (!ignoredPatterns) return items;
return items.filter(({description}) => {
if (!description) return true;
for (const pattern of ignoredPatterns) {
if (pattern instanceof RegExp && pattern.test(description)) return false;
if (typeof pattern === 'string' && description.includes(pattern)) return false;
}
return true;
});
}
/**
* @param {LH.Artifacts} artifacts
* @param {LH.Audit.Context} context
* @return {Promise<LH.Audit.Product>}
*/
static async audit(artifacts, context) {
/** @type {AuditOptions} */
const auditOptions = context.options;
const bundles = await JSBundles.request(artifacts, context);
/** @type {Array<{source: string, description: string|undefined, sourceLocation: LH.Audit.Details.SourceLocationValue|undefined}>} */
const consoleRows = artifacts.ConsoleMessages
.filter(item => item.level === 'error')
.map(item => {
const bundle = bundles.find(bundle => bundle.script.scriptId === item.scriptId);
return {
source: item.source,
description: item.text,
sourceLocation: Audit.makeSourceLocationFromConsoleMessage(item, bundle),
};
});
const tableRows = ErrorLogs.filterAccordingToOptions(consoleRows, auditOptions)
.sort((a, b) => (a.description || '').localeCompare(b.description || ''));
/** @type {LH.Audit.Details.Table['headings']} */
const headings = [
/* eslint-disable max-len */
{key: 'sourceLocation', valueType: 'source-location', label: str_(i18n.UIStrings.columnSource)},
{key: 'description', valueType: 'code', label: str_(i18n.UIStrings.columnDescription)},
/* eslint-enable max-len */
];
const details = Audit.makeTableDetails(headings, tableRows);
const numErrors = tableRows.length;
return {
score: Number(numErrors === 0),
details,
};
}
}
export default ErrorLogs;
export {UIStrings};