lighthouse 12.0.0-dev.20240610 → 12.0.0-dev.20240612
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/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
- package/core/audits/byte-efficiency/byte-efficiency-audit.js +2 -2
- package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
- package/core/audits/byte-efficiency/render-blocking-resources.js +4 -4
- package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
- package/core/audits/dobetterweb/uses-http2.js +2 -2
- package/core/audits/long-tasks.d.ts +7 -6
- package/core/audits/long-tasks.js +5 -4
- package/core/audits/prioritize-lcp-image.d.ts +1 -1
- package/core/computed/document-urls.js +3 -2
- package/core/computed/load-simulator.d.ts +4 -4
- package/core/computed/load-simulator.js +3 -3
- package/core/computed/main-resource.js +3 -2
- package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
- package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
- package/core/computed/metrics/lantern-interactive.d.ts +4 -4
- package/core/computed/metrics/lantern-interactive.js +3 -3
- package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
- package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
- package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
- package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
- package/core/computed/metrics/lantern-metric.d.ts +4 -3
- package/core/computed/metrics/lantern-metric.js +4 -4
- package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
- package/core/computed/metrics/lantern-speed-index.js +3 -3
- package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
- package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
- package/core/computed/metrics/total-blocking-time.js +3 -1
- package/core/computed/network-analysis.js +2 -2
- package/core/computed/page-dependency-graph.d.ts +2 -2
- package/core/computed/page-dependency-graph.js +6 -6
- package/core/computed/processed-navigation.d.ts +1 -1
- package/core/computed/tbt-impact-tasks.js +4 -2
- package/core/config/constants.d.ts +28 -53
- package/core/config/constants.js +2 -43
- package/core/lib/asset-saver.js +2 -2
- package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
- package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
- package/core/lib/lantern/BaseNode.test.js +385 -0
- package/core/lib/lantern/CpuNode.d.ts +43 -0
- package/core/lib/lantern/{cpu-node.js → CpuNode.js} +8 -9
- package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
- package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +17 -17
- package/core/lib/lantern/{metric.js → Metric.js} +10 -12
- package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +4 -5
- package/core/lib/lantern/{network-node.js → NetworkNode.js} +4 -5
- package/core/lib/lantern/{page-dependency-graph.d.ts → PageDependencyGraph.d.ts} +22 -11
- package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +56 -22
- package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
- package/core/lib/lantern/{tbt-utils.d.ts → TBTUtils.d.ts} +1 -1
- package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
- package/core/lib/lantern/TBTUtils.test.js +130 -0
- package/core/lib/lantern/{trace-engine-computation-data.d.ts → TraceEngineComputationData.d.ts} +7 -7
- package/core/lib/lantern/{trace-engine-computation-data.js → TraceEngineComputationData.js} +18 -16
- package/core/lib/lantern/lantern.d.ts +19 -7
- package/core/lib/lantern/lantern.js +21 -1
- package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
- package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +8 -10
- package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
- package/core/lib/lantern/metrics/Interactive.d.ts +20 -0
- package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +14 -17
- package/core/lib/lantern/metrics/Interactive.test.js +56 -0
- package/core/lib/lantern/metrics/LargestContentfulPaint.d.ts +19 -0
- package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +12 -15
- package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
- package/core/lib/lantern/metrics/MaxPotentialFID.d.ts +24 -0
- package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +12 -13
- package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
- package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
- package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +7 -13
- package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +12 -14
- package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
- package/core/lib/lantern/metrics/TotalBlockingTime.d.ts +25 -0
- package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +13 -16
- package/core/lib/lantern/metrics/__snapshots__/first-contentful-paint-test.js.snap +11 -0
- package/core/lib/lantern/metrics/__snapshots__/interactive-test.js.snap +17 -0
- package/core/lib/lantern/metrics/metrics.d.ts +9 -0
- package/core/lib/lantern/metrics/metrics.js +16 -0
- package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +5 -5
- package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +3 -3
- package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
- package/core/lib/lantern/simulation/Constants.d.ts +52 -0
- package/core/lib/lantern/simulation/Constants.js +48 -0
- package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +2 -2
- package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +1 -1
- package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
- package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +8 -8
- package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +3 -3
- package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
- package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
- package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
- package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +13 -15
- package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +29 -30
- package/core/lib/lantern/simulation/Simulator.test.js +434 -0
- package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
- package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
- package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
- package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
- package/core/lib/lantern/simulation/simulation.d.ts +21 -0
- package/core/lib/lantern/simulation/simulation.js +28 -0
- package/core/lib/lantern/types/lantern.d.ts +81 -9
- package/core/lib/lantern-trace-saver.d.ts +4 -4
- package/core/lib/lantern-trace-saver.js +3 -3
- package/core/lib/navigation-error.js +3 -3
- package/core/lib/network-recorder.js +2 -2
- package/core/lib/network-request.d.ts +1 -1
- package/core/lib/network-request.js +1 -1
- package/package.json +5 -5
- package/tsconfig.json +10 -8
- package/types/artifacts.d.ts +3 -10
- package/types/gatherer.d.ts +1 -1
- package/core/lib/lantern/cpu-node.d.ts +0 -44
- package/core/lib/lantern/metrics/interactive.d.ts +0 -26
- package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +0 -19
- package/core/lib/lantern/metrics/max-potential-fid.d.ts +0 -30
- package/core/lib/lantern/metrics/total-blocking-time.d.ts +0 -31
- /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
- /package/core/lib/lantern/{tbt-utils.js → TBTUtils.js} +0 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import * as Lantern from './lantern.js';
|
|
8
|
+
|
|
9
|
+
const {calculateSumOfBlockingTime} = Lantern.TBTUtils;
|
|
10
|
+
|
|
11
|
+
describe('TotalBlockingTime utils', () => {
|
|
12
|
+
it('reports 0 when no task is longer than 50ms', () => {
|
|
13
|
+
const events = [
|
|
14
|
+
{start: 1000, end: 1050, duration: 50},
|
|
15
|
+
{start: 2000, end: 2010, duration: 10},
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const fcpTimeMs = 500;
|
|
19
|
+
const interactiveTimeMs = 4000;
|
|
20
|
+
|
|
21
|
+
expect(
|
|
22
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
23
|
+
).toBe(0);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('only looks at tasks within FCP and TTI', () => {
|
|
27
|
+
const events = [
|
|
28
|
+
{start: 1000, end: 1060, duration: 60},
|
|
29
|
+
{start: 2000, end: 2100, duration: 100},
|
|
30
|
+
{start: 2300, end: 2450, duration: 150},
|
|
31
|
+
{start: 2600, end: 2800, duration: 200},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const fcpTimeMs = 1500;
|
|
35
|
+
const interactiveTimeMs = 2500;
|
|
36
|
+
|
|
37
|
+
expect(
|
|
38
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
39
|
+
).toBe(150);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('clips before finding blocking regions', () => {
|
|
43
|
+
const fcpTimeMs = 150;
|
|
44
|
+
const interactiveTimeMs = 300;
|
|
45
|
+
|
|
46
|
+
const events = [
|
|
47
|
+
// The clipping is done first, so the task becomes [150, 200] after clipping and contributes
|
|
48
|
+
// 0ms of blocking time. This is in contrast to first calculating the blocking region ([100,
|
|
49
|
+
// 200]) and then clipping at FCP (150ms), which yields 50ms blocking time.
|
|
50
|
+
{start: 50, end: 200, duration: 150},
|
|
51
|
+
// Similarly, the task is first clipped above to be [240, 300], and then contributes 10ms
|
|
52
|
+
// blocking time.
|
|
53
|
+
{start: 240, end: 460, duration: 120},
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
expect(
|
|
57
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
58
|
+
).toBe(10); // 0ms + 10ms.
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// TTI can happen in the middle of a task, for example, if TTI is at FMP which occurs as part
|
|
62
|
+
// of a larger task, or in the lantern case where we use estimate TTI using a different graph
|
|
63
|
+
// from the one used to estimate TBT.
|
|
64
|
+
it('clips properly if TTI falls in the middle of a task', () => {
|
|
65
|
+
const fcpTimeMs = 1000;
|
|
66
|
+
const interactiveTimeMs = 2000;
|
|
67
|
+
|
|
68
|
+
expect(
|
|
69
|
+
calculateSumOfBlockingTime(
|
|
70
|
+
[{start: 1951, end: 2100, duration: 149}],
|
|
71
|
+
fcpTimeMs,
|
|
72
|
+
interactiveTimeMs
|
|
73
|
+
)
|
|
74
|
+
).toBe(0); // Duration after clipping is 49, which is < 50.
|
|
75
|
+
expect(
|
|
76
|
+
calculateSumOfBlockingTime(
|
|
77
|
+
[{start: 1950, end: 2100, duration: 150}],
|
|
78
|
+
fcpTimeMs,
|
|
79
|
+
interactiveTimeMs
|
|
80
|
+
)
|
|
81
|
+
).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms.
|
|
82
|
+
expect(
|
|
83
|
+
calculateSumOfBlockingTime(
|
|
84
|
+
[{start: 1949, end: 2100, duration: 151}],
|
|
85
|
+
fcpTimeMs,
|
|
86
|
+
interactiveTimeMs
|
|
87
|
+
)
|
|
88
|
+
).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms.
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('clips properly if FCP falls in the middle of a task', () => {
|
|
92
|
+
const fcpTimeMs = 1000;
|
|
93
|
+
const interactiveTimeMs = 2000;
|
|
94
|
+
|
|
95
|
+
expect(
|
|
96
|
+
calculateSumOfBlockingTime(
|
|
97
|
+
[{start: 900, end: 1049, duration: 149}],
|
|
98
|
+
fcpTimeMs,
|
|
99
|
+
interactiveTimeMs
|
|
100
|
+
)
|
|
101
|
+
).toBe(0); // Duration after clipping is 49, which is < 50.
|
|
102
|
+
expect(
|
|
103
|
+
calculateSumOfBlockingTime(
|
|
104
|
+
[{start: 900, end: 1050, duration: 150}],
|
|
105
|
+
fcpTimeMs,
|
|
106
|
+
interactiveTimeMs
|
|
107
|
+
)
|
|
108
|
+
).toBe(0); // Duration after clipping is 50, so time after 50ms is 0ms.
|
|
109
|
+
expect(
|
|
110
|
+
calculateSumOfBlockingTime(
|
|
111
|
+
[{start: 900, end: 1051, duration: 151}],
|
|
112
|
+
fcpTimeMs,
|
|
113
|
+
interactiveTimeMs
|
|
114
|
+
)
|
|
115
|
+
).toBe(1); // Duration after clipping is 51, so time after 50ms is 1ms.
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// This can happen in the lantern metric case, where we use the optimistic
|
|
119
|
+
// TTI and pessimistic FCP.
|
|
120
|
+
it('returns 0 if interactiveTime is earlier than FCP', () => {
|
|
121
|
+
const fcpTimeMs = 2050;
|
|
122
|
+
const interactiveTimeMs = 1050;
|
|
123
|
+
|
|
124
|
+
const events = [{start: 500, end: 3000, duration: 2500}];
|
|
125
|
+
|
|
126
|
+
expect(
|
|
127
|
+
calculateSumOfBlockingTime(events, fcpTimeMs, interactiveTimeMs)
|
|
128
|
+
).toBe(0);
|
|
129
|
+
});
|
|
130
|
+
});
|
package/core/lib/lantern/{trace-engine-computation-data.d.ts → TraceEngineComputationData.d.ts}
RENAMED
|
@@ -8,18 +8,18 @@ export type MetricScore = import('@paulirish/trace_engine/models/trace/handlers/
|
|
|
8
8
|
*/
|
|
9
9
|
export function createProcessedNavigation(traceEngineData: TraceEngine.Handlers.Types.TraceParseData): Lantern.Simulation.ProcessedNavigation;
|
|
10
10
|
/**
|
|
11
|
-
* @param {
|
|
11
|
+
* @param {Lantern.Trace} trace
|
|
12
12
|
* @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData
|
|
13
13
|
* @return {Lantern.NetworkRequest[]}
|
|
14
14
|
*/
|
|
15
|
-
export function createNetworkRequests(trace:
|
|
15
|
+
export function createNetworkRequests(trace: Lantern.Trace, traceEngineData: TraceEngine.Handlers.Types.TraceParseData): Lantern.NetworkRequest[];
|
|
16
16
|
/**
|
|
17
17
|
* @param {Lantern.NetworkRequest[]} requests
|
|
18
|
-
* @param {
|
|
18
|
+
* @param {Lantern.Trace} trace
|
|
19
19
|
* @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData
|
|
20
|
-
* @param {
|
|
20
|
+
* @param {Lantern.Simulation.URL=} URL
|
|
21
21
|
*/
|
|
22
|
-
export function createGraph(requests: Lantern.NetworkRequest[], trace:
|
|
22
|
+
export function createGraph(requests: Lantern.NetworkRequest[], trace: Lantern.Trace, traceEngineData: TraceEngine.Handlers.Types.TraceParseData, URL?: Lantern.Simulation.URL | undefined): import("./PageDependencyGraph.js").Node;
|
|
23
23
|
import * as TraceEngine from '@paulirish/trace_engine';
|
|
24
|
-
import * as Lantern from './
|
|
25
|
-
//# sourceMappingURL=
|
|
24
|
+
import * as Lantern from './lantern.js';
|
|
25
|
+
//# sourceMappingURL=TraceEngineComputationData.d.ts.map
|
|
@@ -5,10 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as TraceEngine from '@paulirish/trace_engine';
|
|
8
|
+
import * as Protocol from '@paulirish/trace_engine/generated/protocol.js';
|
|
8
9
|
|
|
9
|
-
import * as Lantern from './
|
|
10
|
-
import {PageDependencyGraph} from './page-dependency-graph.js';
|
|
11
|
-
import {RESOURCE_TYPES} from '../network-request.js';
|
|
10
|
+
import * as Lantern from './lantern.js';
|
|
12
11
|
|
|
13
12
|
/** @typedef {import('@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js').MetricName} MetricName */
|
|
14
13
|
/** @typedef {import('@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js').MetricScore} MetricScore */
|
|
@@ -71,7 +70,7 @@ function createParsedUrl(url) {
|
|
|
71
70
|
|
|
72
71
|
/**
|
|
73
72
|
* Returns a map of `pid` -> `tid[]`.
|
|
74
|
-
* @param {
|
|
73
|
+
* @param {Lantern.Trace} trace
|
|
75
74
|
* @return {Map<number, number[]>}
|
|
76
75
|
*/
|
|
77
76
|
function findWorkerThreads(trace) {
|
|
@@ -140,6 +139,9 @@ function createLanternRequest(traceEngineData, workerThreads, request) {
|
|
|
140
139
|
fromWorker = true;
|
|
141
140
|
}
|
|
142
141
|
|
|
142
|
+
// typescript const enums.... gotta stop using those ...
|
|
143
|
+
const Other = /** @type {Protocol.Network.InitiatorType.Other} */ ('other');
|
|
144
|
+
|
|
143
145
|
// `initiator` in the trace does not contain the stack trace for JS-initiated
|
|
144
146
|
// requests. Instead, that is stored in the `stackTrace` property of the SyntheticNetworkRequest.
|
|
145
147
|
// There are some minor differences in the fields, accounted for here.
|
|
@@ -148,11 +150,11 @@ function createLanternRequest(traceEngineData, workerThreads, request) {
|
|
|
148
150
|
// which means less edges in the graph, which mean worse results.
|
|
149
151
|
// TODO: Should fix in Chromium.
|
|
150
152
|
/** @type {Lantern.NetworkRequest['initiator']} */
|
|
151
|
-
const initiator = request.args.data.initiator ?? {type:
|
|
153
|
+
const initiator = request.args.data.initiator ?? {type: Other};
|
|
152
154
|
if (request.args.data.stackTrace) {
|
|
153
155
|
const callFrames = request.args.data.stackTrace.map(f => {
|
|
154
156
|
return {
|
|
155
|
-
scriptId: String(f.scriptId),
|
|
157
|
+
scriptId: /** @type {Protocol.Runtime.ScriptId} */(String(f.scriptId)),
|
|
156
158
|
url: f.url,
|
|
157
159
|
lineNumber: f.lineNumber - 1,
|
|
158
160
|
columnNumber: f.columnNumber - 1,
|
|
@@ -160,6 +162,7 @@ function createLanternRequest(traceEngineData, workerThreads, request) {
|
|
|
160
162
|
};
|
|
161
163
|
});
|
|
162
164
|
initiator.stack = {callFrames};
|
|
165
|
+
// Note: there is no `parent` to set ...
|
|
163
166
|
}
|
|
164
167
|
|
|
165
168
|
let resourceType = request.args.data.resourceType;
|
|
@@ -227,7 +230,7 @@ function chooseInitiatorRequest(request, requestsByURL) {
|
|
|
227
230
|
return request.redirectSource;
|
|
228
231
|
}
|
|
229
232
|
|
|
230
|
-
const initiatorURL = PageDependencyGraph.getNetworkInitiators(request)[0];
|
|
233
|
+
const initiatorURL = Lantern.PageDependencyGraph.getNetworkInitiators(request)[0];
|
|
231
234
|
let candidates = requestsByURL.get(initiatorURL) || [];
|
|
232
235
|
// The (valid) initiator must come before the initiated request.
|
|
233
236
|
candidates = candidates.filter(c => {
|
|
@@ -238,7 +241,7 @@ function chooseInitiatorRequest(request, requestsByURL) {
|
|
|
238
241
|
// Disambiguate based on prefetch. Prefetch requests have type 'Other' and cannot
|
|
239
242
|
// initiate requests, so we drop them here.
|
|
240
243
|
const nonPrefetchCandidates = candidates.filter(
|
|
241
|
-
cand => cand.resourceType !==
|
|
244
|
+
cand => cand.resourceType !== Lantern.NetworkRequestTypes.Other);
|
|
242
245
|
if (nonPrefetchCandidates.length) {
|
|
243
246
|
candidates = nonPrefetchCandidates;
|
|
244
247
|
}
|
|
@@ -253,7 +256,7 @@ function chooseInitiatorRequest(request, requestsByURL) {
|
|
|
253
256
|
if (candidates.length > 1 && request.initiator.type === 'parser') {
|
|
254
257
|
// Filter to just Documents when initiator type is parser.
|
|
255
258
|
const documentCandidates = candidates.filter(cand =>
|
|
256
|
-
cand.resourceType ===
|
|
259
|
+
cand.resourceType === Lantern.NetworkRequestTypes.Document);
|
|
257
260
|
if (documentCandidates.length) {
|
|
258
261
|
candidates = documentCandidates;
|
|
259
262
|
}
|
|
@@ -296,7 +299,7 @@ function linkInitiators(lanternRequests) {
|
|
|
296
299
|
}
|
|
297
300
|
|
|
298
301
|
/**
|
|
299
|
-
* @param {
|
|
302
|
+
* @param {Lantern.Trace} trace
|
|
300
303
|
* @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData
|
|
301
304
|
* @return {Lantern.NetworkRequest[]}
|
|
302
305
|
*/
|
|
@@ -390,9 +393,9 @@ function createNetworkRequests(trace, traceEngineData) {
|
|
|
390
393
|
}
|
|
391
394
|
|
|
392
395
|
/**
|
|
393
|
-
* @param {
|
|
396
|
+
* @param {Lantern.Trace} trace
|
|
394
397
|
* @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData
|
|
395
|
-
* @return {
|
|
398
|
+
* @return {Lantern.TraceEvent[]}
|
|
396
399
|
*/
|
|
397
400
|
function collectMainThreadEvents(trace, traceEngineData) {
|
|
398
401
|
const Meta = traceEngineData.Meta;
|
|
@@ -431,9 +434,9 @@ function collectMainThreadEvents(trace, traceEngineData) {
|
|
|
431
434
|
|
|
432
435
|
/**
|
|
433
436
|
* @param {Lantern.NetworkRequest[]} requests
|
|
434
|
-
* @param {
|
|
437
|
+
* @param {Lantern.Trace} trace
|
|
435
438
|
* @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData
|
|
436
|
-
* @param {
|
|
439
|
+
* @param {Lantern.Simulation.URL=} URL
|
|
437
440
|
*/
|
|
438
441
|
function createGraph(requests, trace, traceEngineData, URL) {
|
|
439
442
|
const mainThreadEvents = collectMainThreadEvents(trace, traceEngineData);
|
|
@@ -444,7 +447,6 @@ function createGraph(requests, trace, traceEngineData, URL) {
|
|
|
444
447
|
URL = {
|
|
445
448
|
requestedUrl: requests[0].url,
|
|
446
449
|
mainDocumentUrl: '',
|
|
447
|
-
finalDisplayedUrl: '',
|
|
448
450
|
};
|
|
449
451
|
|
|
450
452
|
let request = requests[0];
|
|
@@ -454,7 +456,7 @@ function createGraph(requests, trace, traceEngineData, URL) {
|
|
|
454
456
|
URL.mainDocumentUrl = request.url;
|
|
455
457
|
}
|
|
456
458
|
|
|
457
|
-
return PageDependencyGraph.createGraph(mainThreadEvents, requests, URL);
|
|
459
|
+
return Lantern.PageDependencyGraph.createGraph(mainThreadEvents, requests, URL);
|
|
458
460
|
}
|
|
459
461
|
|
|
460
462
|
export {
|
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export
|
|
1
|
+
export { BaseNode } from "./BaseNode.js";
|
|
2
|
+
export { CPUNode } from "./CpuNode.js";
|
|
3
|
+
export { LanternError as Error } from "./LanternError.js";
|
|
4
|
+
export { Metric } from "./Metric.js";
|
|
5
|
+
export { NetworkNode } from "./NetworkNode.js";
|
|
6
|
+
export { PageDependencyGraph } from "./PageDependencyGraph.js";
|
|
7
|
+
export * as Metrics from "./metrics/metrics.js";
|
|
8
|
+
export * as Simulation from "./simulation/simulation.js";
|
|
9
|
+
export * as TBTUtils from "./TBTUtils.js";
|
|
10
|
+
export * as TraceEngineComputationData from "./TraceEngineComputationData.js";
|
|
11
|
+
export type NetworkRequest<T = any> = Lantern.NetworkRequest<T>;
|
|
12
|
+
export type ResourcePriority = Lantern.ResourcePriority;
|
|
13
|
+
export type ResourceTiming = Lantern.ResourceTiming;
|
|
14
|
+
export type ResourceType = Lantern.ResourceType;
|
|
15
|
+
export type Trace = Lantern.Trace;
|
|
16
|
+
export type TraceEvent = Lantern.TraceEvent;
|
|
17
|
+
/** @type {Lantern.Util.SelfMap<Lantern.ResourceType>} */
|
|
18
|
+
export const NetworkRequestTypes: Lantern.Util.SelfMap<Lantern.ResourceType>;
|
|
19
|
+
import * as Lantern from './types/lantern.js';
|
|
8
20
|
//# sourceMappingURL=lantern.d.ts.map
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import * as Lantern from './types/lantern.js';
|
|
8
|
+
|
|
9
|
+
/** @type {Lantern.Util.SelfMap<Lantern.ResourceType>} */
|
|
8
10
|
const NetworkRequestTypes = {
|
|
9
11
|
XHR: 'XHR',
|
|
10
12
|
Fetch: 'Fetch',
|
|
@@ -26,6 +28,24 @@ const NetworkRequestTypes = {
|
|
|
26
28
|
Prefetch: 'Prefetch',
|
|
27
29
|
};
|
|
28
30
|
|
|
31
|
+
export {BaseNode} from './BaseNode.js';
|
|
32
|
+
export {CPUNode} from './CpuNode.js';
|
|
33
|
+
export {LanternError as Error} from './LanternError.js';
|
|
34
|
+
export {Metric} from './Metric.js';
|
|
35
|
+
export {NetworkNode} from './NetworkNode.js';
|
|
36
|
+
export {PageDependencyGraph} from './PageDependencyGraph.js';
|
|
37
|
+
export * as Metrics from './metrics/metrics.js';
|
|
38
|
+
export * as Simulation from './simulation/simulation.js';
|
|
39
|
+
export * as TBTUtils from './TBTUtils.js';
|
|
40
|
+
export * as TraceEngineComputationData from './TraceEngineComputationData.js';
|
|
41
|
+
|
|
42
|
+
/** @template [T=any] @typedef {Lantern.NetworkRequest<T>} NetworkRequest */
|
|
43
|
+
/** @typedef {Lantern.ResourcePriority} ResourcePriority */
|
|
44
|
+
/** @typedef {Lantern.ResourceTiming} ResourceTiming */
|
|
45
|
+
/** @typedef {Lantern.ResourceType} ResourceType */
|
|
46
|
+
/** @typedef {Lantern.Trace} Trace */
|
|
47
|
+
/** @typedef {Lantern.TraceEvent} TraceEvent */
|
|
48
|
+
|
|
29
49
|
export {
|
|
30
50
|
NetworkRequestTypes,
|
|
31
51
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
export type Node = import('../
|
|
2
|
-
export type NetworkNode<T> = import('../
|
|
3
|
-
export type CpuNode = import('../
|
|
4
|
-
/** @typedef {import('../
|
|
5
|
-
/** @template T @typedef {import('../
|
|
6
|
-
/** @typedef {import('../
|
|
7
|
-
export class FirstContentfulPaint extends Metric {
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
export type NetworkNode<T> = import('../NetworkNode.js').NetworkNode<T>;
|
|
3
|
+
export type CpuNode = import('../CpuNode.js').CPUNode;
|
|
4
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
5
|
+
/** @template T @typedef {import('../NetworkNode.js').NetworkNode<T>} NetworkNode */
|
|
6
|
+
/** @typedef {import('../CpuNode.js').CPUNode} CpuNode */
|
|
7
|
+
export class FirstContentfulPaint extends Lantern.Metric {
|
|
8
8
|
/**
|
|
9
9
|
* @template T
|
|
10
10
|
* @typedef FirstPaintBasedGraphOpts
|
|
@@ -37,7 +37,7 @@ export class FirstContentfulPaint extends Metric {
|
|
|
37
37
|
* The function that determines
|
|
38
38
|
* which resources should be considered *possibly* render-blocking.
|
|
39
39
|
*/
|
|
40
|
-
treatNodeAsRenderBlocking: (arg0:
|
|
40
|
+
treatNodeAsRenderBlocking: (arg0: Lantern.NetworkNode<T>) => boolean;
|
|
41
41
|
/**
|
|
42
42
|
* The function that
|
|
43
43
|
* determines which CPU nodes should also be included in our blocking node IDs set,
|
|
@@ -66,7 +66,7 @@ export class FirstContentfulPaint extends Metric {
|
|
|
66
66
|
* The function that determines
|
|
67
67
|
* which resources should be considered *possibly* render-blocking.
|
|
68
68
|
*/
|
|
69
|
-
treatNodeAsRenderBlocking: (arg0:
|
|
69
|
+
treatNodeAsRenderBlocking: (arg0: Lantern.NetworkNode<T_1>) => boolean;
|
|
70
70
|
/**
|
|
71
71
|
* The function that
|
|
72
72
|
* determines which CPU nodes should also be included in our blocking node IDs set,
|
|
@@ -75,5 +75,5 @@ export class FirstContentfulPaint extends Metric {
|
|
|
75
75
|
additionalCpuNodesToTreatAsRenderBlocking?: ((arg0: CpuNode) => boolean) | undefined;
|
|
76
76
|
}): Node;
|
|
77
77
|
}
|
|
78
|
-
import
|
|
79
|
-
//# sourceMappingURL=
|
|
78
|
+
import * as Lantern from '../lantern.js';
|
|
79
|
+
//# sourceMappingURL=FirstContentfulPaint.d.ts.map
|
|
@@ -4,15 +4,13 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as Lantern from '../
|
|
8
|
-
import {Metric} from '../metric.js';
|
|
9
|
-
import {BaseNode} from '../base-node.js';
|
|
7
|
+
import * as Lantern from '../lantern.js';
|
|
10
8
|
|
|
11
|
-
/** @typedef {import('../
|
|
12
|
-
/** @template T @typedef {import('../
|
|
13
|
-
/** @typedef {import('../
|
|
9
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
10
|
+
/** @template T @typedef {import('../NetworkNode.js').NetworkNode<T>} NetworkNode */
|
|
11
|
+
/** @typedef {import('../CpuNode.js').CPUNode} CpuNode */
|
|
14
12
|
|
|
15
|
-
class FirstContentfulPaint extends Metric {
|
|
13
|
+
class FirstContentfulPaint extends Lantern.Metric {
|
|
16
14
|
/**
|
|
17
15
|
* @return {Lantern.Simulation.MetricCoefficients}
|
|
18
16
|
*/
|
|
@@ -57,7 +55,7 @@ class FirstContentfulPaint extends Metric {
|
|
|
57
55
|
/** @type {Array<CpuNode>} */
|
|
58
56
|
const cpuNodes = [];
|
|
59
57
|
graph.traverse(node => {
|
|
60
|
-
if (node.type === BaseNode.TYPES.CPU) {
|
|
58
|
+
if (node.type === Lantern.BaseNode.TYPES.CPU) {
|
|
61
59
|
// A task is *possibly* render blocking if it *started* before cutoffTimestamp.
|
|
62
60
|
// We use startTime here because the paint event can be *inside* the task that was render blocking.
|
|
63
61
|
if (node.startTime <= cutoffTimestamp) cpuNodes.push(node);
|
|
@@ -75,7 +73,7 @@ class FirstContentfulPaint extends Metric {
|
|
|
75
73
|
cpuNodes.sort((a, b) => a.startTime - b.startTime);
|
|
76
74
|
|
|
77
75
|
// A script is *possibly* render blocking if it finished loading before cutoffTimestamp.
|
|
78
|
-
const possiblyRenderBlockingScriptUrls = Metric.getScriptUrls(graph, node => {
|
|
76
|
+
const possiblyRenderBlockingScriptUrls = Lantern.Metric.getScriptUrls(graph, node => {
|
|
79
77
|
// The optimistic LCP treatNodeAsRenderBlocking fn wants to exclude some images in the graph,
|
|
80
78
|
// but here it only receives scripts to evaluate. It's a no-op in this case, but it will
|
|
81
79
|
// matter below in the getFirstPaintBasedGraph clone operation.
|
|
@@ -147,7 +145,7 @@ class FirstContentfulPaint extends Metric {
|
|
|
147
145
|
const {definitelyNotRenderBlockingScriptUrls, renderBlockingCpuNodeIds} = rbData;
|
|
148
146
|
|
|
149
147
|
return dependencyGraph.cloneWithRelationships(node => {
|
|
150
|
-
if (node.type === BaseNode.TYPES.NETWORK) {
|
|
148
|
+
if (node.type === Lantern.BaseNode.TYPES.NETWORK) {
|
|
151
149
|
// Exclude all nodes that ended after cutoffTimestamp (except for the main document which we always consider necessary)
|
|
152
150
|
// endTime is negative if request does not finish, make sure startTime isn't after cutoffTimestamp in this case.
|
|
153
151
|
const endedAfterPaint = node.endTime > cutoffTimestamp || node.startTime > cutoffTimestamp;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import assert from 'assert/strict';
|
|
8
|
+
|
|
9
|
+
import * as Lantern from '../lantern.js';
|
|
10
|
+
import {readJson} from '../../../test/test-utils.js';
|
|
11
|
+
import {getComputationDataFromFixture} from './MetricTestUtils.js';
|
|
12
|
+
|
|
13
|
+
const {FirstContentfulPaint} = Lantern.Metrics;
|
|
14
|
+
|
|
15
|
+
const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta);
|
|
16
|
+
|
|
17
|
+
describe('Metrics: Lantern FCP', () => {
|
|
18
|
+
it('should compute predicted value', async () => {
|
|
19
|
+
const data = await getComputationDataFromFixture({trace});
|
|
20
|
+
const result = await FirstContentfulPaint.compute(data);
|
|
21
|
+
|
|
22
|
+
expect({
|
|
23
|
+
timing: Math.round(result.timing),
|
|
24
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
25
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs),
|
|
26
|
+
optimisticNodeTimings: result.optimisticEstimate.nodeTimings.size,
|
|
27
|
+
pessimisticNodeTimings: result.pessimisticEstimate.nodeTimings.size,
|
|
28
|
+
}).toMatchSnapshot();
|
|
29
|
+
assert.ok(result.optimisticGraph, 'should have created optimistic graph');
|
|
30
|
+
assert.ok(result.pessimisticGraph, 'should have created pessimistic graph');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle negative request networkEndTime', async () => {
|
|
34
|
+
const data = await getComputationDataFromFixture({trace});
|
|
35
|
+
data.graph.request.networkEndTime = -1;
|
|
36
|
+
const result = await FirstContentfulPaint.compute(data);
|
|
37
|
+
|
|
38
|
+
const optimisticNodes = [];
|
|
39
|
+
result.optimisticGraph.traverse(node => {
|
|
40
|
+
if (node.type === 'network') {
|
|
41
|
+
optimisticNodes.push(node);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
expect(optimisticNodes.map(node => node.request.url)).toEqual(['https://squoosh.app/']);
|
|
45
|
+
|
|
46
|
+
const pessimisticNodes = [];
|
|
47
|
+
result.pessimisticGraph.traverse(node => {
|
|
48
|
+
if (node.type === 'network') {
|
|
49
|
+
pessimisticNodes.push(node);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
expect(pessimisticNodes.map(node => node.request.url)).toEqual(['https://squoosh.app/']);
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type Node = import('../BaseNode.js').Node;
|
|
2
|
+
export class Interactive extends Lantern.Metric {
|
|
3
|
+
/**
|
|
4
|
+
* @param {Node} dependencyGraph
|
|
5
|
+
* @return {Node}
|
|
6
|
+
*/
|
|
7
|
+
static getOptimisticGraph(dependencyGraph: Node): Node;
|
|
8
|
+
/**
|
|
9
|
+
* @param {Node} dependencyGraph
|
|
10
|
+
* @return {Node}
|
|
11
|
+
*/
|
|
12
|
+
static getPessimisticGraph(dependencyGraph: Node): Node;
|
|
13
|
+
/**
|
|
14
|
+
* @param {Lantern.Simulation.Result['nodeTimings']} nodeTimings
|
|
15
|
+
* @return {number}
|
|
16
|
+
*/
|
|
17
|
+
static getLastLongTaskEndTime(nodeTimings: Lantern.Simulation.Result['nodeTimings'], duration?: number): number;
|
|
18
|
+
}
|
|
19
|
+
import * as Lantern from '../lantern.js';
|
|
20
|
+
//# sourceMappingURL=Interactive.d.ts.map
|
|
@@ -4,19 +4,16 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import * as Lantern from '../
|
|
8
|
-
import {Metric} from '../metric.js';
|
|
9
|
-
import {BaseNode} from '../base-node.js';
|
|
10
|
-
import {NetworkRequestTypes} from '../lantern.js';
|
|
7
|
+
import * as Lantern from '../lantern.js';
|
|
11
8
|
|
|
12
|
-
/** @typedef {import('../
|
|
9
|
+
/** @typedef {import('../BaseNode.js').Node} Node */
|
|
13
10
|
|
|
14
11
|
// Any CPU task of 20 ms or more will end up being a critical long task on mobile
|
|
15
12
|
const CRITICAL_LONG_TASK_THRESHOLD = 20;
|
|
16
13
|
|
|
17
|
-
class Interactive extends Metric {
|
|
14
|
+
class Interactive extends Lantern.Metric {
|
|
18
15
|
/**
|
|
19
|
-
* @return {
|
|
16
|
+
* @return {Lantern.Simulation.MetricCoefficients}
|
|
20
17
|
*/
|
|
21
18
|
static get COEFFICIENTS() {
|
|
22
19
|
return {
|
|
@@ -36,13 +33,13 @@ class Interactive extends Metric {
|
|
|
36
33
|
|
|
37
34
|
return dependencyGraph.cloneWithRelationships(node => {
|
|
38
35
|
// Include everything that might be a long task
|
|
39
|
-
if (node.type === BaseNode.TYPES.CPU) {
|
|
36
|
+
if (node.type === Lantern.BaseNode.TYPES.CPU) {
|
|
40
37
|
return node.duration > minimumCpuTaskDuration;
|
|
41
38
|
}
|
|
42
39
|
|
|
43
40
|
// Include all scripts and high priority requests, exclude all images
|
|
44
|
-
const isImage = node.request.resourceType === NetworkRequestTypes.Image;
|
|
45
|
-
const isScript = node.request.resourceType === NetworkRequestTypes.Script;
|
|
41
|
+
const isImage = node.request.resourceType === Lantern.NetworkRequestTypes.Image;
|
|
42
|
+
const isScript = node.request.resourceType === Lantern.NetworkRequestTypes.Script;
|
|
46
43
|
return (
|
|
47
44
|
!isImage &&
|
|
48
45
|
(isScript ||
|
|
@@ -61,9 +58,9 @@ class Interactive extends Metric {
|
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
/**
|
|
64
|
-
* @param {
|
|
65
|
-
* @param {import('../
|
|
66
|
-
* @return {
|
|
61
|
+
* @param {Lantern.Simulation.Result} simulationResult
|
|
62
|
+
* @param {import('../Metric.js').Extras} extras
|
|
63
|
+
* @return {Lantern.Simulation.Result}
|
|
67
64
|
*/
|
|
68
65
|
static getEstimateFromSimulation(simulationResult, extras) {
|
|
69
66
|
if (!extras.lcpResult) throw new Error('missing lcpResult');
|
|
@@ -80,8 +77,8 @@ class Interactive extends Metric {
|
|
|
80
77
|
|
|
81
78
|
/**
|
|
82
79
|
* @param {Lantern.Simulation.MetricComputationDataInput} data
|
|
83
|
-
* @param {Omit<import('../
|
|
84
|
-
* @return {Promise<
|
|
80
|
+
* @param {Omit<import('../Metric.js').Extras, 'optimistic'>=} extras
|
|
81
|
+
* @return {Promise<Lantern.Metrics.Result>}
|
|
85
82
|
*/
|
|
86
83
|
static async compute(data, extras) {
|
|
87
84
|
const lcpResult = extras?.lcpResult;
|
|
@@ -95,13 +92,13 @@ class Interactive extends Metric {
|
|
|
95
92
|
}
|
|
96
93
|
|
|
97
94
|
/**
|
|
98
|
-
* @param {
|
|
95
|
+
* @param {Lantern.Simulation.Result['nodeTimings']} nodeTimings
|
|
99
96
|
* @return {number}
|
|
100
97
|
*/
|
|
101
98
|
static getLastLongTaskEndTime(nodeTimings, duration = 50) {
|
|
102
99
|
return Array.from(nodeTimings.entries())
|
|
103
100
|
.filter(([node, timing]) => {
|
|
104
|
-
if (node.type !== BaseNode.TYPES.CPU) return false;
|
|
101
|
+
if (node.type !== Lantern.BaseNode.TYPES.CPU) return false;
|
|
105
102
|
return timing.duration > duration;
|
|
106
103
|
})
|
|
107
104
|
.map(([_, timing]) => timing.endTime)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2024 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import assert from 'assert/strict';
|
|
8
|
+
|
|
9
|
+
import * as Lantern from '../lantern.js';
|
|
10
|
+
import {getComputationDataFromFixture} from './MetricTestUtils.js';
|
|
11
|
+
import {readJson} from '../../../test/test-utils.js';
|
|
12
|
+
|
|
13
|
+
const {Interactive, FirstContentfulPaint, LargestContentfulPaint} = Lantern.Metrics;
|
|
14
|
+
|
|
15
|
+
const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta);
|
|
16
|
+
const iframeTrace = readJson('../../../fixtures/artifacts/iframe/trace.json', import.meta);
|
|
17
|
+
|
|
18
|
+
describe('Metrics: Lantern TTI', () => {
|
|
19
|
+
it('should compute predicted value', async () => {
|
|
20
|
+
const data = await getComputationDataFromFixture({trace});
|
|
21
|
+
const result = await Interactive.compute(data, {
|
|
22
|
+
lcpResult: await LargestContentfulPaint.compute(data, {
|
|
23
|
+
fcpResult: await FirstContentfulPaint.compute(data),
|
|
24
|
+
}),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
expect({
|
|
28
|
+
timing: Math.round(result.timing),
|
|
29
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
30
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs),
|
|
31
|
+
}).toMatchSnapshot();
|
|
32
|
+
assert.equal(result.optimisticEstimate.nodeTimings.size, 14);
|
|
33
|
+
assert.equal(result.pessimisticEstimate.nodeTimings.size, 31);
|
|
34
|
+
assert.ok(result.optimisticGraph, 'should have created optimistic graph');
|
|
35
|
+
assert.ok(result.pessimisticGraph, 'should have created pessimistic graph');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should compute predicted value on iframes with substantial layout', async () => {
|
|
39
|
+
const data = await getComputationDataFromFixture({
|
|
40
|
+
trace: iframeTrace,
|
|
41
|
+
});
|
|
42
|
+
const result = await Interactive.compute(data, {
|
|
43
|
+
lcpResult: await LargestContentfulPaint.compute(data, {
|
|
44
|
+
fcpResult: await FirstContentfulPaint.compute(data),
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect({
|
|
49
|
+
timing: Math.round(result.timing),
|
|
50
|
+
optimistic: Math.round(result.optimisticEstimate.timeInMs),
|
|
51
|
+
pessimistic: Math.round(result.pessimisticEstimate.timeInMs),
|
|
52
|
+
}).toMatchSnapshot();
|
|
53
|
+
assert.ok(result.optimisticGraph, 'should have created optimistic graph');
|
|
54
|
+
assert.ok(result.pessimisticGraph, 'should have created pessimistic graph');
|
|
55
|
+
});
|
|
56
|
+
});
|