lighthouse 9.5.0-dev.20220319 → 9.5.0-dev.20220322
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lighthouse-core/audits/byte-efficiency/duplicated-javascript.js +1 -2
- package/lighthouse-core/audits/byte-efficiency/legacy-javascript.js +1 -1
- package/lighthouse-core/audits/diagnostics.js +4 -3
- package/lighthouse-core/audits/seo/http-status-code.js +2 -4
- package/lighthouse-core/audits/server-response-time.js +2 -17
- package/lighthouse-core/computed/page-dependency-graph.js +3 -0
- package/lighthouse-core/fraggle-rock/gather/navigation-runner.js +1 -0
- package/lighthouse-core/gather/gather-runner.js +1 -0
- package/lighthouse-core/gather/gatherers/link-elements.js +12 -14
- package/lighthouse-core/gather/gatherers/main-document-content.js +8 -8
- package/lighthouse-core/lib/script-helpers.js +1 -2
- package/package.json +1 -1
- package/report/generator/report-generator.js +46 -21
- package/report/test/generator/report-generator-test.js +25 -18
|
@@ -163,14 +163,13 @@ class DuplicatedJavascript extends ByteEfficiencyAudit {
|
|
|
163
163
|
/** @type {number|undefined} */
|
|
164
164
|
let transferRatio = transferRatioByUrl.get(url);
|
|
165
165
|
if (transferRatio === undefined) {
|
|
166
|
-
const networkRecord = getRequestForScript(networkRecords, script);
|
|
167
|
-
|
|
168
166
|
if (!script || script.length === undefined) {
|
|
169
167
|
// This should never happen because we found the wasted bytes from bundles, which required contents in a ScriptElement.
|
|
170
168
|
continue;
|
|
171
169
|
}
|
|
172
170
|
|
|
173
171
|
const contentLength = script.length;
|
|
172
|
+
const networkRecord = getRequestForScript(networkRecords, script);
|
|
174
173
|
transferRatio = DuplicatedJavascript._estimateTransferRatio(networkRecord, contentLength);
|
|
175
174
|
transferRatioByUrl.set(url, transferRatio);
|
|
176
175
|
}
|
|
@@ -373,12 +373,12 @@ class LegacyJavascript extends ByteEfficiencyAudit {
|
|
|
373
373
|
if (transferRatio !== undefined) return transferRatio;
|
|
374
374
|
|
|
375
375
|
const script = artifacts.Scripts.find(script => script.url === url);
|
|
376
|
-
const networkRecord = getRequestForScript(networkRecords, script);
|
|
377
376
|
|
|
378
377
|
if (!script || script.content === null) {
|
|
379
378
|
// Can't find content, so just use 1.
|
|
380
379
|
transferRatio = 1;
|
|
381
380
|
} else {
|
|
381
|
+
const networkRecord = getRequestForScript(networkRecords, script);
|
|
382
382
|
const contentLength = script.length || 0;
|
|
383
383
|
const transferSize =
|
|
384
384
|
ByteEfficiencyAudit.estimateTransferSize(networkRecord, contentLength, 'Script');
|
|
@@ -9,7 +9,7 @@ const Audit = require('./audit.js');
|
|
|
9
9
|
const MainThreadTasksComputed = require('../computed/main-thread-tasks.js');
|
|
10
10
|
const NetworkRecordsComputed = require('../computed/network-records.js');
|
|
11
11
|
const NetworkAnalysisComputed = require('../computed/network-analysis.js');
|
|
12
|
-
const
|
|
12
|
+
const MainResource = require('../computed/main-resource.js');
|
|
13
13
|
|
|
14
14
|
class Diagnostics extends Audit {
|
|
15
15
|
/**
|
|
@@ -22,7 +22,7 @@ class Diagnostics extends Audit {
|
|
|
22
22
|
title: 'Diagnostics',
|
|
23
23
|
description: 'Collection of useful page vitals.',
|
|
24
24
|
supportedModes: ['navigation'],
|
|
25
|
-
requiredArtifacts: ['traces', 'devtoolsLogs'],
|
|
25
|
+
requiredArtifacts: ['URL', 'traces', 'devtoolsLogs'],
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -37,9 +37,10 @@ class Diagnostics extends Audit {
|
|
|
37
37
|
const tasks = await MainThreadTasksComputed.request(trace, context);
|
|
38
38
|
const records = await NetworkRecordsComputed.request(devtoolsLog, context);
|
|
39
39
|
const analysis = await NetworkAnalysisComputed.request(devtoolsLog, context);
|
|
40
|
+
const mainResource = await MainResource.request({devtoolsLog, URL: artifacts.URL}, context);
|
|
40
41
|
|
|
41
42
|
const toplevelTasks = tasks.filter(t => !t.parent);
|
|
42
|
-
const mainDocumentTransferSize =
|
|
43
|
+
const mainDocumentTransferSize = mainResource.transferSize;
|
|
43
44
|
const totalByteWeight = records.reduce((sum, r) => sum + (r.transferSize || 0), 0);
|
|
44
45
|
const totalTaskTime = toplevelTasks.reduce((sum, t) => sum + (t.duration || 0), 0);
|
|
45
46
|
const maxRtt = Math.max(...analysis.additionalRttByOrigin.values()) + analysis.rtt;
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const Audit = require('../audit.js');
|
|
9
|
-
const NetworkRecords = require('../../computed/network-records.js');
|
|
10
9
|
const HTTP_UNSUCCESSFUL_CODE_LOW = 400;
|
|
11
10
|
const HTTP_UNSUCCESSFUL_CODE_HIGH = 599;
|
|
12
11
|
const i18n = require('../../lib/i18n/i18n.js');
|
|
13
|
-
const
|
|
12
|
+
const MainResource = require('../../computed/main-resource.js');
|
|
14
13
|
|
|
15
14
|
const UIStrings = {
|
|
16
15
|
/** Title of a Lighthouse audit that provides detail on the HTTP status code a page responds with. This descriptive title is shown when the page has responded with a valid HTTP status code. */
|
|
@@ -47,8 +46,7 @@ class HTTPStatusCode extends Audit {
|
|
|
47
46
|
static async audit(artifacts, context) {
|
|
48
47
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
49
48
|
const URL = artifacts.URL;
|
|
50
|
-
const
|
|
51
|
-
const mainResource = NetworkAnalyzer.findMainDocument(networkRecords, URL.finalUrl);
|
|
49
|
+
const mainResource = await MainResource.request({devtoolsLog, URL}, context);
|
|
52
50
|
|
|
53
51
|
const statusCode = mainResource.statusCode;
|
|
54
52
|
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
const Audit = require('./audit.js');
|
|
9
9
|
const i18n = require('../lib/i18n/i18n.js');
|
|
10
10
|
const MainResource = require('../computed/main-resource.js');
|
|
11
|
-
const NetworkRecords = require('../computed/network-records.js');
|
|
12
|
-
const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
|
|
13
11
|
|
|
14
12
|
const UIStrings = {
|
|
15
13
|
/** Title of a diagnostic audit that provides detail on how long it took from starting a request to when the server started responding. This descriptive title is shown to users when the amount is acceptable and no user action is required. */
|
|
@@ -39,7 +37,7 @@ class ServerResponseTime extends Audit {
|
|
|
39
37
|
title: str_(UIStrings.title),
|
|
40
38
|
failureTitle: str_(UIStrings.failureTitle),
|
|
41
39
|
description: str_(UIStrings.description),
|
|
42
|
-
supportedModes: ['
|
|
40
|
+
supportedModes: ['navigation'],
|
|
43
41
|
requiredArtifacts: ['devtoolsLogs', 'URL', 'GatherContext'],
|
|
44
42
|
};
|
|
45
43
|
}
|
|
@@ -61,20 +59,7 @@ class ServerResponseTime extends Audit {
|
|
|
61
59
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
62
60
|
|
|
63
61
|
/** @type {LH.Artifacts.NetworkRequest} */
|
|
64
|
-
|
|
65
|
-
if (artifacts.GatherContext.gatherMode === 'timespan') {
|
|
66
|
-
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
67
|
-
const optionalMainResource = NetworkAnalyzer.findOptionalMainDocument(
|
|
68
|
-
networkRecords,
|
|
69
|
-
artifacts.URL.finalUrl
|
|
70
|
-
);
|
|
71
|
-
if (!optionalMainResource) {
|
|
72
|
-
return {score: null, notApplicable: true};
|
|
73
|
-
}
|
|
74
|
-
mainResource = optionalMainResource;
|
|
75
|
-
} else {
|
|
76
|
-
mainResource = await MainResource.request({devtoolsLog, URL: artifacts.URL}, context);
|
|
77
|
-
}
|
|
62
|
+
const mainResource = await MainResource.request({devtoolsLog, URL: artifacts.URL}, context);
|
|
78
63
|
|
|
79
64
|
const responseTime = ServerResponseTime.calculateResponseTime(mainResource);
|
|
80
65
|
const passed = responseTime < TOO_SLOW_THRESHOLD_MS;
|
|
@@ -394,6 +394,9 @@ class PageDependencyGraph {
|
|
|
394
394
|
const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords);
|
|
395
395
|
const cpuNodes = PageDependencyGraph.getCPUNodes(processedTrace);
|
|
396
396
|
|
|
397
|
+
// TODO: Remove this usage of `findMainDocument` and create a new function to get the first document request.
|
|
398
|
+
// https://github.com/GoogleChrome/lighthouse/issues/8984
|
|
399
|
+
//
|
|
397
400
|
// The main document request is the earliest network request *of type document*.
|
|
398
401
|
// This will be different from the root request when there are server redirects.
|
|
399
402
|
const mainDocumentRequest = NetworkAnalyzer.findMainDocument(networkRecords);
|
|
@@ -224,6 +224,7 @@ async function _navigation(navigationContext) {
|
|
|
224
224
|
await collectPhaseArtifacts({phase: 'startInstrumentation', ...phaseState});
|
|
225
225
|
await collectPhaseArtifacts({phase: 'startSensitiveInstrumentation', ...phaseState});
|
|
226
226
|
const navigateResult = await _navigate(navigationContext);
|
|
227
|
+
phaseState.baseArtifacts.URL.finalUrl = navigateResult.finalUrl;
|
|
227
228
|
phaseState.url = navigateResult.finalUrl;
|
|
228
229
|
await collectPhaseArtifacts({phase: 'stopSensitiveInstrumentation', ...phaseState});
|
|
229
230
|
await collectPhaseArtifacts({phase: 'stopInstrumentation', ...phaseState});
|
|
@@ -80,6 +80,7 @@ class GatherRunner {
|
|
|
80
80
|
...passContext.passConfig,
|
|
81
81
|
});
|
|
82
82
|
passContext.url = finalUrl;
|
|
83
|
+
passContext.baseArtifacts.URL.finalUrl = finalUrl;
|
|
83
84
|
if (passContext.passConfig.loadFailureMode === 'fatal') {
|
|
84
85
|
passContext.LighthouseRunWarnings.push(...warnings);
|
|
85
86
|
}
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
const LinkHeader = require('http-link-header');
|
|
9
9
|
const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
|
|
10
10
|
const {URL} = require('../../lib/url-shim.js');
|
|
11
|
-
const NetworkRecords = require('../../computed/network-records.js');
|
|
12
|
-
const NetworkAnalyzer = require('../../lib/dependency-graph/simulator/network-analyzer.js');
|
|
13
11
|
const pageFunctions = require('../../lib/page-functions.js');
|
|
14
12
|
const DevtoolsLog = require('./devtools-log.js');
|
|
13
|
+
const MainResource = require('../../computed/main-resource.js');
|
|
15
14
|
|
|
16
15
|
/* globals HTMLLinkElement getNodeDetails */
|
|
17
16
|
|
|
@@ -114,12 +113,12 @@ class LinkElements extends FRGatherer {
|
|
|
114
113
|
|
|
115
114
|
/**
|
|
116
115
|
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
117
|
-
* @param {LH.Artifacts
|
|
118
|
-
* @return {LH.Artifacts['LinkElements']}
|
|
116
|
+
* @param {LH.Artifacts['DevtoolsLog']} devtoolsLog
|
|
117
|
+
* @return {Promise<LH.Artifacts['LinkElements']>}
|
|
119
118
|
*/
|
|
120
|
-
static getLinkElementsInHeaders(context,
|
|
121
|
-
const
|
|
122
|
-
|
|
119
|
+
static async getLinkElementsInHeaders(context, devtoolsLog) {
|
|
120
|
+
const mainDocument =
|
|
121
|
+
await MainResource.request({devtoolsLog, URL: context.baseArtifacts.URL}, context);
|
|
123
122
|
|
|
124
123
|
/** @type {LH.Artifacts['LinkElements']} */
|
|
125
124
|
const linkElements = [];
|
|
@@ -130,7 +129,7 @@ class LinkElements extends FRGatherer {
|
|
|
130
129
|
for (const link of LinkHeader.parse(header.value).refs) {
|
|
131
130
|
linkElements.push({
|
|
132
131
|
rel: link.rel || '',
|
|
133
|
-
href: normalizeUrlOrNull(link.uri, finalUrl),
|
|
132
|
+
href: normalizeUrlOrNull(link.uri, context.baseArtifacts.URL.finalUrl),
|
|
134
133
|
hrefRaw: link.uri || '',
|
|
135
134
|
hreflang: link.hreflang || '',
|
|
136
135
|
as: link.as || '',
|
|
@@ -146,12 +145,12 @@ class LinkElements extends FRGatherer {
|
|
|
146
145
|
|
|
147
146
|
/**
|
|
148
147
|
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
149
|
-
* @param {LH.Artifacts
|
|
148
|
+
* @param {LH.Artifacts['DevtoolsLog']} devtoolsLog
|
|
150
149
|
* @return {Promise<LH.Artifacts['LinkElements']>}
|
|
151
150
|
*/
|
|
152
|
-
async _getArtifact(context,
|
|
151
|
+
async _getArtifact(context, devtoolsLog) {
|
|
153
152
|
const fromDOM = await LinkElements.getLinkElementsInDOM(context);
|
|
154
|
-
const fromHeaders = LinkElements.getLinkElementsInHeaders(context,
|
|
153
|
+
const fromHeaders = await LinkElements.getLinkElementsInHeaders(context, devtoolsLog);
|
|
155
154
|
const linkElements = fromDOM.concat(fromHeaders);
|
|
156
155
|
|
|
157
156
|
for (const link of linkElements) {
|
|
@@ -168,7 +167,7 @@ class LinkElements extends FRGatherer {
|
|
|
168
167
|
* @return {Promise<LH.Artifacts['LinkElements']>}
|
|
169
168
|
*/
|
|
170
169
|
async afterPass(context, loadData) {
|
|
171
|
-
return this._getArtifact({...context, dependencies: {}}, loadData.
|
|
170
|
+
return this._getArtifact({...context, dependencies: {}}, loadData.devtoolsLog);
|
|
172
171
|
}
|
|
173
172
|
|
|
174
173
|
/**
|
|
@@ -176,8 +175,7 @@ class LinkElements extends FRGatherer {
|
|
|
176
175
|
* @return {Promise<LH.Artifacts['LinkElements']>}
|
|
177
176
|
*/
|
|
178
177
|
async getArtifact(context) {
|
|
179
|
-
|
|
180
|
-
return this._getArtifact(context, records);
|
|
178
|
+
return this._getArtifact(context, context.dependencies.DevtoolsLog);
|
|
181
179
|
}
|
|
182
180
|
}
|
|
183
181
|
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
8
|
const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
|
|
9
|
-
const NetworkAnalyzer = require('../../lib/dependency-graph/simulator/network-analyzer.js');
|
|
10
|
-
const NetworkRecords = require('../../computed/network-records.js');
|
|
11
9
|
const DevtoolsLog = require('./devtools-log.js');
|
|
12
10
|
const {fetchResponseBodyFromCache} = require('../driver/network.js');
|
|
11
|
+
const MainResource = require('../../computed/main-resource.js');
|
|
13
12
|
|
|
14
13
|
/**
|
|
15
14
|
* Collects the content of the main html document.
|
|
@@ -24,14 +23,16 @@ class MainDocumentContent extends FRGatherer {
|
|
|
24
23
|
/**
|
|
25
24
|
*
|
|
26
25
|
* @param {LH.Gatherer.FRTransitionalContext} context
|
|
27
|
-
* @param {LH.Artifacts
|
|
26
|
+
* @param {LH.Artifacts['DevtoolsLog']} devtoolsLog
|
|
28
27
|
* @return {Promise<LH.Artifacts['MainDocumentContent']>}
|
|
29
28
|
*/
|
|
30
|
-
async _getArtifact(context,
|
|
31
|
-
const mainResource =
|
|
29
|
+
async _getArtifact(context, devtoolsLog) {
|
|
30
|
+
const mainResource =
|
|
31
|
+
await MainResource.request({devtoolsLog, URL: context.baseArtifacts.URL}, context);
|
|
32
32
|
const session = context.driver.defaultSession;
|
|
33
33
|
return fetchResponseBodyFromCache(session, mainResource.requestId);
|
|
34
34
|
}
|
|
35
|
+
|
|
35
36
|
/**
|
|
36
37
|
*
|
|
37
38
|
* @param {LH.Gatherer.FRTransitionalContext<'DevtoolsLog'>} context
|
|
@@ -39,8 +40,7 @@ class MainDocumentContent extends FRGatherer {
|
|
|
39
40
|
*/
|
|
40
41
|
async getArtifact(context) {
|
|
41
42
|
const devtoolsLog = context.dependencies.DevtoolsLog;
|
|
42
|
-
|
|
43
|
-
return this._getArtifact(context, networkRecords);
|
|
43
|
+
return this._getArtifact(context, devtoolsLog);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
@@ -49,7 +49,7 @@ class MainDocumentContent extends FRGatherer {
|
|
|
49
49
|
* @return {Promise<LH.Artifacts['MainDocumentContent']>}
|
|
50
50
|
*/
|
|
51
51
|
async afterPass(passContext, loadData) {
|
|
52
|
-
return this._getArtifact({...passContext, dependencies: {}}, loadData.
|
|
52
|
+
return this._getArtifact({...passContext, dependencies: {}}, loadData.devtoolsLog);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
|
|
@@ -7,11 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {LH.Artifacts.NetworkRequest[]} networkRecords
|
|
10
|
-
* @param {LH.Artifacts.Script
|
|
10
|
+
* @param {LH.Artifacts.Script} script
|
|
11
11
|
* @return {LH.Artifacts.NetworkRequest|undefined}
|
|
12
12
|
*/
|
|
13
13
|
function getRequestForScript(networkRecords, script) {
|
|
14
|
-
if (!script) return;
|
|
15
14
|
let networkRequest = networkRecords.find(request => request.url === script.url);
|
|
16
15
|
while (networkRequest?.redirectDestination) {
|
|
17
16
|
networkRequest = networkRequest.redirectDestination;
|
package/package.json
CHANGED
|
@@ -93,29 +93,54 @@ class ReportGenerator {
|
|
|
93
93
|
const separator = ',';
|
|
94
94
|
/** @param {string} value @return {string} */
|
|
95
95
|
const escape = value => `"${value.replace(/"/g, '""')}"`;
|
|
96
|
-
/** @param {
|
|
97
|
-
const rowFormatter = row => row.map(value =>
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
96
|
+
/** @param {ReadonlyArray<string | number | null>} row @return {string[]} */
|
|
97
|
+
const rowFormatter = row => row.map(value => {
|
|
98
|
+
if (value === null) return 'null';
|
|
99
|
+
return value.toString();
|
|
100
|
+
}).map(escape);
|
|
101
|
+
|
|
102
|
+
const rows = [];
|
|
103
|
+
const topLevelKeys = /** @type {const} */(
|
|
104
|
+
['requestedUrl', 'finalUrl', 'fetchTime', 'gatherMode']);
|
|
105
|
+
|
|
106
|
+
// First we have metadata about the LHR.
|
|
107
|
+
rows.push(rowFormatter(topLevelKeys));
|
|
108
|
+
rows.push(rowFormatter(topLevelKeys.map(key => lhr[key])));
|
|
109
|
+
|
|
110
|
+
// Some spacing.
|
|
111
|
+
rows.push([]);
|
|
112
|
+
|
|
113
|
+
// Categories.
|
|
114
|
+
rows.push(['category', 'score']);
|
|
115
|
+
for (const category of Object.values(lhr.categories)) {
|
|
116
|
+
rows.push(rowFormatter([
|
|
117
|
+
category.id,
|
|
118
|
+
category.score,
|
|
119
|
+
]));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
rows.push([]);
|
|
123
|
+
|
|
124
|
+
// Audits.
|
|
125
|
+
rows.push(['category', 'audit', 'score', 'displayValue', 'description']);
|
|
126
|
+
for (const category of Object.values(lhr.categories)) {
|
|
127
|
+
for (const auditRef of category.auditRefs) {
|
|
109
128
|
const audit = lhr.audits[auditRef.id];
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
129
|
+
if (!audit) continue;
|
|
130
|
+
|
|
131
|
+
rows.push(rowFormatter([
|
|
132
|
+
category.id,
|
|
133
|
+
auditRef.id,
|
|
134
|
+
audit.score,
|
|
135
|
+
audit.displayValue || '',
|
|
136
|
+
audit.description,
|
|
137
|
+
]));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
116
140
|
|
|
117
|
-
return
|
|
118
|
-
.map(row => row.join(separator))
|
|
141
|
+
return rows
|
|
142
|
+
.map(row => row.join(separator))
|
|
143
|
+
.join(CRLF);
|
|
119
144
|
}
|
|
120
145
|
|
|
121
146
|
/**
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
'use strict';
|
|
7
7
|
|
|
8
|
+
/* eslint-disable no-irregular-whitespace */
|
|
9
|
+
|
|
8
10
|
const assert = require('assert').strict;
|
|
9
11
|
const fs = require('fs');
|
|
10
12
|
|
|
@@ -81,28 +83,33 @@ describe('ReportGenerator', () => {
|
|
|
81
83
|
|
|
82
84
|
it('creates CSV for results', async () => {
|
|
83
85
|
const path = './.results-as-csv.csv';
|
|
84
|
-
const headers = {
|
|
85
|
-
category: '',
|
|
86
|
-
name: '',
|
|
87
|
-
title: '',
|
|
88
|
-
type: '',
|
|
89
|
-
score: 42,
|
|
90
|
-
};
|
|
91
86
|
|
|
92
87
|
const csvOutput = ReportGenerator.generateReport(sampleResults, 'csv');
|
|
93
88
|
fs.writeFileSync(path, csvOutput);
|
|
94
89
|
|
|
95
90
|
const lines = csvOutput.split('\n');
|
|
96
91
|
expect(lines.length).toBeGreaterThan(100);
|
|
97
|
-
expect(lines.slice(0,
|
|
98
|
-
"requestedUrl
|
|
99
|
-
\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"
|
|
100
|
-
|
|
92
|
+
expect(lines.slice(0, 15).join('\n')).toMatchInlineSnapshot(`
|
|
93
|
+
"\\"requestedUrl\\",\\"finalUrl\\",\\"fetchTime\\",\\"gatherMode\\"
|
|
94
|
+
\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"2021-09-07T20:11:11.853Z\\",\\"navigation\\"
|
|
95
|
+
|
|
96
|
+
category,score
|
|
97
|
+
\\"performance\\",\\"0.26\\"
|
|
98
|
+
\\"accessibility\\",\\"0.78\\"
|
|
99
|
+
\\"best-practices\\",\\"0.25\\"
|
|
100
|
+
\\"seo\\",\\"0.67\\"
|
|
101
|
+
\\"pwa\\",\\"0.3\\"
|
|
102
|
+
|
|
103
|
+
category,audit,score,displayValue,description
|
|
104
|
+
\\"performance\\",\\"first-contentful-paint\\",\\"0.01\\",\\"6.8 s\\",\\"First Contentful Paint marks the time at which the first text or image is painted. [Learn more](https://web.dev/first-contentful-paint/).\\"
|
|
105
|
+
\\"performance\\",\\"interactive\\",\\"0.41\\",\\"8.2 s\\",\\"Time to interactive is the amount of time it takes for the page to become fully interactive. [Learn more](https://web.dev/interactive/).\\"
|
|
106
|
+
\\"performance\\",\\"speed-index\\",\\"0.21\\",\\"8.1 s\\",\\"Speed Index shows how quickly the contents of a page are visibly populated. [Learn more](https://web.dev/speed-index/).\\"
|
|
107
|
+
\\"performance\\",\\"total-blocking-time\\",\\"0.2\\",\\"1,220 ms\\",\\"Sum of all time periods between FCP and Time to Interactive, when task length exceeded 50ms, expressed in milliseconds. [Learn more](https://web.dev/lighthouse-total-blocking-time/).\\"
|
|
101
108
|
"
|
|
102
109
|
`);
|
|
103
110
|
|
|
104
111
|
try {
|
|
105
|
-
await csvValidator(path
|
|
112
|
+
await csvValidator(path);
|
|
106
113
|
} catch (err) {
|
|
107
114
|
assert.fail('CSV parser error:\n' + err.join('\n'));
|
|
108
115
|
} finally {
|
|
@@ -110,13 +117,13 @@ describe('ReportGenerator', () => {
|
|
|
110
117
|
}
|
|
111
118
|
});
|
|
112
119
|
|
|
113
|
-
it('creates CSV for results including
|
|
120
|
+
it('creates CSV for results including categories', () => {
|
|
114
121
|
const csvOutput = ReportGenerator.generateReport(sampleResults, 'csv');
|
|
115
|
-
expect(csvOutput).toContain('performance
|
|
116
|
-
expect(csvOutput).toContain('accessibility
|
|
117
|
-
expect(csvOutput).toContain('best-practices
|
|
118
|
-
expect(csvOutput).toContain('seo
|
|
119
|
-
expect(csvOutput).toContain('pwa
|
|
122
|
+
expect(csvOutput).toContain('performance');
|
|
123
|
+
expect(csvOutput).toContain('accessibility');
|
|
124
|
+
expect(csvOutput).toContain('best-practices');
|
|
125
|
+
expect(csvOutput).toContain('seo');
|
|
126
|
+
expect(csvOutput).toContain('pwa');
|
|
120
127
|
});
|
|
121
128
|
|
|
122
129
|
it('writes extended info', () => {
|