lighthouse 12.0.0 → 12.1.0

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.
Files changed (219) hide show
  1. package/cli/run.js +5 -38
  2. package/cli/test/smokehouse/lighthouse-runners/bundle.js +1 -1
  3. package/cli/test/smokehouse/smokehouse.js +11 -1
  4. package/core/audits/accessibility/aria-allowed-role.js +7 -9
  5. package/core/audits/byte-efficiency/byte-efficiency-audit.d.ts +2 -2
  6. package/core/audits/byte-efficiency/byte-efficiency-audit.js +3 -3
  7. package/core/audits/byte-efficiency/offscreen-images.js +1 -1
  8. package/core/audits/byte-efficiency/render-blocking-resources.d.ts +3 -3
  9. package/core/audits/byte-efficiency/render-blocking-resources.js +10 -10
  10. package/core/audits/dobetterweb/uses-http2.d.ts +2 -2
  11. package/core/audits/dobetterweb/uses-http2.js +5 -5
  12. package/core/audits/long-tasks.d.ts +7 -6
  13. package/core/audits/long-tasks.js +5 -4
  14. package/core/audits/metrics/first-meaningful-paint.d.ts +1 -17
  15. package/core/audits/metrics/first-meaningful-paint.js +5 -47
  16. package/core/audits/metrics/interactive.d.ts +1 -1
  17. package/core/audits/metrics/interactive.js +1 -1
  18. package/core/audits/predictive-perf.js +0 -6
  19. package/core/audits/prioritize-lcp-image.d.ts +1 -1
  20. package/core/audits/prioritize-lcp-image.js +2 -2
  21. package/core/audits/redirects.js +2 -3
  22. package/core/audits/third-party-facades.js +1 -1
  23. package/core/audits/third-party-summary.js +1 -1
  24. package/core/audits/uses-rel-preconnect.js +2 -2
  25. package/core/audits/uses-rel-preload.js +9 -9
  26. package/core/computed/critical-request-chains.js +3 -3
  27. package/core/computed/document-urls.js +3 -2
  28. package/core/computed/load-simulator.d.ts +4 -4
  29. package/core/computed/load-simulator.js +3 -54
  30. package/core/computed/main-resource.js +3 -2
  31. package/core/computed/metrics/interactive.d.ts +6 -0
  32. package/core/computed/metrics/interactive.js +2 -2
  33. package/core/computed/metrics/lantern-first-contentful-paint.d.ts +4 -4
  34. package/core/computed/metrics/lantern-first-contentful-paint.js +3 -3
  35. package/core/computed/metrics/lantern-interactive.d.ts +4 -4
  36. package/core/computed/metrics/lantern-interactive.js +6 -6
  37. package/core/computed/metrics/lantern-largest-contentful-paint.d.ts +4 -4
  38. package/core/computed/metrics/lantern-largest-contentful-paint.js +3 -3
  39. package/core/computed/metrics/lantern-max-potential-fid.d.ts +4 -4
  40. package/core/computed/metrics/lantern-max-potential-fid.js +3 -3
  41. package/core/computed/metrics/lantern-metric.d.ts +21 -2
  42. package/core/computed/metrics/lantern-metric.js +39 -4
  43. package/core/computed/metrics/lantern-speed-index.d.ts +4 -4
  44. package/core/computed/metrics/lantern-speed-index.js +4 -4
  45. package/core/computed/metrics/lantern-total-blocking-time.d.ts +4 -4
  46. package/core/computed/metrics/lantern-total-blocking-time.js +3 -3
  47. package/core/computed/metrics/timing-summary.js +0 -6
  48. package/core/computed/metrics/total-blocking-time.js +3 -1
  49. package/core/computed/navigation-insights.d.ts +2 -20
  50. package/core/computed/network-analysis.d.ts +0 -5
  51. package/core/computed/network-analysis.js +2 -42
  52. package/core/computed/page-dependency-graph.d.ts +5 -3
  53. package/core/computed/page-dependency-graph.js +17 -7
  54. package/core/computed/processed-navigation.d.ts +1 -1
  55. package/core/computed/tbt-impact-tasks.js +4 -2
  56. package/core/computed/trace-engine-result.d.ts +0 -11
  57. package/core/computed/trace-engine-result.js +5 -19
  58. package/core/config/constants.d.ts +28 -53
  59. package/core/config/constants.js +2 -43
  60. package/core/gather/driver/navigation.js +1 -1
  61. package/core/gather/driver/network-monitor.d.ts +2 -1
  62. package/core/gather/driver/network-monitor.js +4 -4
  63. package/core/gather/driver/target-manager.d.ts +1 -1
  64. package/core/gather/driver.d.ts +0 -12
  65. package/core/gather/driver.js +1 -26
  66. package/core/gather/gatherers/inspector-issues.js +1 -0
  67. package/core/gather/gatherers/root-causes.js +0 -1
  68. package/core/gather/session.d.ts +5 -3
  69. package/core/gather/session.js +22 -1
  70. package/core/lib/asset-saver.d.ts +13 -9
  71. package/core/lib/asset-saver.js +77 -30
  72. package/core/lib/bf-cache-strings.js +2 -2
  73. package/core/lib/lantern/{base-node.d.ts → BaseNode.d.ts} +7 -9
  74. package/core/lib/lantern/{base-node.js → BaseNode.js} +6 -6
  75. package/core/lib/lantern/BaseNode.test.js +385 -0
  76. package/core/lib/lantern/CpuNode.d.ts +43 -0
  77. package/core/lib/lantern/{cpu-node.js → CpuNode.js} +8 -9
  78. package/core/lib/lantern/{lantern-error.d.ts → LanternError.d.ts} +1 -1
  79. package/core/lib/lantern/{metric.d.ts → Metric.d.ts} +23 -25
  80. package/core/lib/lantern/{metric.js → Metric.js} +14 -16
  81. package/core/lib/lantern/{network-node.d.ts → NetworkNode.d.ts} +6 -7
  82. package/core/lib/lantern/{network-node.js → NetworkNode.js} +7 -9
  83. package/core/lib/lantern/PageDependencyGraph.d.ts +82 -0
  84. package/core/lib/lantern/{page-dependency-graph.js → PageDependencyGraph.js} +185 -50
  85. package/core/lib/lantern/PageDependencyGraph.test.js +654 -0
  86. package/core/{computed/metrics/tbt-utils.d.ts → lib/lantern/TBTUtils.d.ts} +1 -1
  87. package/core/lib/lantern/TBTUtils.test.d.ts +2 -0
  88. package/core/lib/lantern/TBTUtils.test.js +130 -0
  89. package/core/lib/lantern/TraceEngineComputationData.d.ts +25 -0
  90. package/core/lib/lantern/TraceEngineComputationData.js +466 -0
  91. package/core/lib/lantern/lantern.d.ts +19 -7
  92. package/core/lib/lantern/lantern.js +21 -1
  93. package/core/lib/lantern/metrics/{first-contentful-paint.d.ts → FirstContentfulPaint.d.ts} +11 -11
  94. package/core/lib/lantern/metrics/{first-contentful-paint.js → FirstContentfulPaint.js} +11 -13
  95. package/core/lib/lantern/metrics/FirstContentfulPaint.test.js +54 -0
  96. package/core/lib/lantern/metrics/Interactive.d.ts +20 -0
  97. package/core/lib/lantern/metrics/{interactive.js → Interactive.js} +23 -26
  98. package/core/lib/lantern/metrics/Interactive.test.js +56 -0
  99. package/core/lib/lantern/metrics/LargestContentfulPaint.d.ts +19 -0
  100. package/core/lib/lantern/metrics/{largest-contentful-paint.js → LargestContentfulPaint.js} +16 -19
  101. package/core/lib/lantern/metrics/LargestContentfulPaint.test.js +42 -0
  102. package/core/lib/lantern/metrics/MaxPotentialFID.d.ts +24 -0
  103. package/core/lib/lantern/metrics/{max-potential-fid.js → MaxPotentialFID.js} +12 -13
  104. package/core/lib/lantern/metrics/MetricTestUtils.d.ts +19 -0
  105. package/core/lib/lantern/metrics/MetricTestUtils.js +48 -0
  106. package/core/lib/lantern/metrics/{speed-index.d.ts → SpeedIndex.d.ts} +7 -13
  107. package/core/lib/lantern/metrics/{speed-index.js → SpeedIndex.js} +14 -16
  108. package/core/lib/lantern/metrics/SpeedIndex.test.js +83 -0
  109. package/core/lib/lantern/metrics/TotalBlockingTime.d.ts +25 -0
  110. package/core/lib/lantern/metrics/{total-blocking-time.js → TotalBlockingTime.js} +13 -16
  111. package/core/lib/lantern/metrics/__snapshots__/FirstContentfulPaint.test.js.snap +11 -0
  112. package/core/lib/lantern/metrics/__snapshots__/Interactive.test.js.snap +17 -0
  113. package/core/lib/lantern/metrics/metrics.d.ts +9 -0
  114. package/core/lib/lantern/metrics/metrics.js +16 -0
  115. package/core/lib/lantern/{simulator/connection-pool.d.ts → simulation/ConnectionPool.d.ts} +15 -15
  116. package/core/lib/lantern/{simulator/connection-pool.js → simulation/ConnectionPool.js} +25 -25
  117. package/core/lib/lantern/simulation/ConnectionPool.test.js +195 -0
  118. package/core/lib/lantern/simulation/Constants.d.ts +52 -0
  119. package/core/lib/lantern/simulation/Constants.js +48 -0
  120. package/core/lib/lantern/{simulator/dns-cache.d.ts → simulation/DNSCache.d.ts} +3 -3
  121. package/core/lib/lantern/{simulator/dns-cache.js → simulation/DNSCache.js} +2 -2
  122. package/core/lib/lantern/simulation/DNSCache.test.js +72 -0
  123. package/core/lib/lantern/{simulator/network-analyzer.d.ts → simulation/NetworkAnalyzer.d.ts} +34 -21
  124. package/core/lib/lantern/{simulator/network-analyzer.js → simulation/NetworkAnalyzer.js} +106 -57
  125. package/core/lib/lantern/simulation/NetworkAnalyzer.test.js +475 -0
  126. package/core/lib/lantern/{simulator/simulator-timing-map.d.ts → simulation/SimulationTimingMap.d.ts} +7 -7
  127. package/core/lib/lantern/{simulator/simulator-timing-map.js → simulation/SimulationTimingMap.js} +5 -6
  128. package/core/lib/lantern/{simulator/simulator.d.ts → simulation/Simulator.d.ts} +21 -19
  129. package/core/lib/lantern/{simulator/simulator.js → simulation/Simulator.js} +100 -45
  130. package/core/lib/lantern/simulation/Simulator.test.js +434 -0
  131. package/core/lib/lantern/simulation/TCPConnection.test.d.ts +2 -0
  132. package/core/lib/lantern/simulation/TCPConnection.test.js +374 -0
  133. package/core/lib/lantern/{simulator/tcp-connection.d.ts → simulation/TcpConnection.d.ts} +2 -2
  134. package/core/lib/lantern/{simulator/tcp-connection.js → simulation/TcpConnection.js} +1 -1
  135. package/core/lib/lantern/simulation/simulation.d.ts +21 -0
  136. package/core/lib/lantern/simulation/simulation.js +28 -0
  137. package/core/lib/lantern/types/lantern.d.ts +145 -20
  138. package/core/lib/lantern-trace-saver.d.ts +4 -4
  139. package/core/lib/lantern-trace-saver.js +4 -4
  140. package/core/lib/navigation-error.js +3 -3
  141. package/core/lib/network-recorder.js +2 -2
  142. package/core/lib/network-request.d.ts +29 -3
  143. package/core/lib/network-request.js +20 -13
  144. package/core/lib/tracehouse/trace-processor.d.ts +0 -2
  145. package/core/lib/tracehouse/trace-processor.js +1 -31
  146. package/core/lib/traces/metric-trace-events.js +0 -5
  147. package/dist/report/bundle.esm.js +1 -1
  148. package/dist/report/flow.js +1 -1
  149. package/dist/report/standalone.js +1 -1
  150. package/package.json +14 -13
  151. package/report/renderer/performance-category-renderer.js +1 -1
  152. package/shared/localization/locales/ar-XB.json +43 -4
  153. package/shared/localization/locales/ar.json +43 -4
  154. package/shared/localization/locales/bg.json +43 -4
  155. package/shared/localization/locales/ca.json +44 -5
  156. package/shared/localization/locales/cs.json +43 -4
  157. package/shared/localization/locales/da.json +43 -4
  158. package/shared/localization/locales/de.json +43 -4
  159. package/shared/localization/locales/el.json +43 -4
  160. package/shared/localization/locales/en-GB.json +42 -3
  161. package/shared/localization/locales/en-US.json +4 -4
  162. package/shared/localization/locales/en-XA.json +43 -4
  163. package/shared/localization/locales/en-XL.json +4 -4
  164. package/shared/localization/locales/es-419.json +43 -4
  165. package/shared/localization/locales/es.json +42 -3
  166. package/shared/localization/locales/fi.json +43 -4
  167. package/shared/localization/locales/fil.json +42 -3
  168. package/shared/localization/locales/fr.json +42 -3
  169. package/shared/localization/locales/he.json +48 -9
  170. package/shared/localization/locales/hi.json +43 -4
  171. package/shared/localization/locales/hr.json +43 -4
  172. package/shared/localization/locales/hu.json +42 -3
  173. package/shared/localization/locales/id.json +42 -3
  174. package/shared/localization/locales/it.json +43 -4
  175. package/shared/localization/locales/ja.json +42 -3
  176. package/shared/localization/locales/ko.json +43 -4
  177. package/shared/localization/locales/lt.json +42 -3
  178. package/shared/localization/locales/lv.json +43 -4
  179. package/shared/localization/locales/nl.json +44 -5
  180. package/shared/localization/locales/no.json +42 -3
  181. package/shared/localization/locales/pl.json +43 -4
  182. package/shared/localization/locales/pt-PT.json +43 -4
  183. package/shared/localization/locales/pt.json +43 -4
  184. package/shared/localization/locales/ro.json +43 -4
  185. package/shared/localization/locales/ru.json +43 -4
  186. package/shared/localization/locales/sk.json +43 -4
  187. package/shared/localization/locales/sl.json +42 -3
  188. package/shared/localization/locales/sr-Latn.json +43 -4
  189. package/shared/localization/locales/sr.json +43 -4
  190. package/shared/localization/locales/sv.json +42 -3
  191. package/shared/localization/locales/ta.json +42 -3
  192. package/shared/localization/locales/te.json +43 -4
  193. package/shared/localization/locales/th.json +44 -5
  194. package/shared/localization/locales/tr.json +43 -4
  195. package/shared/localization/locales/uk.json +43 -4
  196. package/shared/localization/locales/vi.json +43 -4
  197. package/shared/localization/locales/zh-HK.json +43 -4
  198. package/shared/localization/locales/zh-TW.json +43 -4
  199. package/shared/localization/locales/zh.json +43 -4
  200. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -0
  201. package/tsconfig-all.json +1 -0
  202. package/tsconfig.json +11 -7
  203. package/types/artifacts.d.ts +23 -25
  204. package/types/gatherer.d.ts +2 -3
  205. package/types/lhr/lhr.d.ts +2 -0
  206. package/core/computed/metrics/first-meaningful-paint.d.ts +0 -21
  207. package/core/computed/metrics/first-meaningful-paint.js +0 -44
  208. package/core/computed/metrics/lantern-first-meaningful-paint.d.ts +0 -25
  209. package/core/computed/metrics/lantern-first-meaningful-paint.js +0 -43
  210. package/core/lib/lantern/cpu-node.d.ts +0 -44
  211. package/core/lib/lantern/metrics/first-meaningful-paint.d.ts +0 -6
  212. package/core/lib/lantern/metrics/first-meaningful-paint.js +0 -64
  213. package/core/lib/lantern/metrics/interactive.d.ts +0 -26
  214. package/core/lib/lantern/metrics/largest-contentful-paint.d.ts +0 -19
  215. package/core/lib/lantern/metrics/max-potential-fid.d.ts +0 -30
  216. package/core/lib/lantern/metrics/total-blocking-time.d.ts +0 -31
  217. package/core/lib/lantern/page-dependency-graph.d.ts +0 -58
  218. /package/core/lib/lantern/{lantern-error.js → LanternError.js} +0 -0
  219. /package/core/{computed/metrics/tbt-utils.js → lib/lantern/TBTUtils.js} +0 -0
@@ -0,0 +1,374 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2017 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
+
11
+ const {TcpConnection} = Lantern.Simulation;
12
+
13
+ describe('DependencyGraph/Simulator/TcpConnection', () => {
14
+ describe('#constructor', () => {
15
+ it('should create the connection', () => {
16
+ const rtt = 150;
17
+ const throughput = 1600 * 1024;
18
+ const connection = new TcpConnection(rtt, throughput);
19
+ assert.ok(connection);
20
+ assert.equal(connection._rtt, rtt);
21
+ });
22
+ });
23
+
24
+ describe('#maximumSaturatedConnections', () => {
25
+ it('should compute number of supported simulated requests', () => {
26
+ const availableThroughput = 1460 * 8 * 10; // 10 TCP segments/second
27
+ assert.equal(TcpConnection.maximumSaturatedConnections(100, availableThroughput), 1);
28
+ assert.equal(TcpConnection.maximumSaturatedConnections(300, availableThroughput), 3);
29
+ assert.equal(TcpConnection.maximumSaturatedConnections(1000, availableThroughput), 10);
30
+ });
31
+ });
32
+
33
+ describe('.setWarmed', () => {
34
+ it('adjusts the time to download appropriately', () => {
35
+ const connection = new TcpConnection(100, Infinity);
36
+ assert.equal(connection.simulateDownloadUntil(0).timeElapsed, 300);
37
+ connection.setWarmed(true);
38
+ assert.equal(connection.simulateDownloadUntil(0).timeElapsed, 100);
39
+ });
40
+ });
41
+
42
+ describe('.setCongestionWindow', () => {
43
+ it('adjusts the time to download appropriately', () => {
44
+ const connection = new TcpConnection(100, Infinity);
45
+ assert.deepEqual(connection.simulateDownloadUntil(50000), {
46
+ bytesDownloaded: 50000,
47
+ extraBytesDownloaded: 0,
48
+ congestionWindow: 40,
49
+ roundTrips: 5,
50
+ timeElapsed: 500,
51
+ connectionTiming: {
52
+ connectionTime: 250,
53
+ dnsResolutionTime: 0,
54
+ sslTime: 100,
55
+ timeToFirstByte: 300,
56
+ },
57
+ });
58
+ connection.setCongestionWindow(40); // will download all in one round trip
59
+ assert.deepEqual(connection.simulateDownloadUntil(50000), {
60
+ bytesDownloaded: 50000,
61
+ extraBytesDownloaded: 0,
62
+ congestionWindow: 40,
63
+ roundTrips: 3,
64
+ timeElapsed: 300,
65
+ connectionTiming: {
66
+ connectionTime: 250,
67
+ dnsResolutionTime: 0,
68
+ sslTime: 100,
69
+ timeToFirstByte: 300,
70
+ },
71
+ });
72
+ });
73
+ });
74
+
75
+ describe('.setH2OverflowBytesDownloaded', () => {
76
+ it('adjusts the time to download appropriately for H2 connections', () => {
77
+ const connection = new TcpConnection(100, Infinity, 0, true, true);
78
+ connection.setWarmed(true);
79
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
80
+ connection.setH2OverflowBytesDownloaded(20000);
81
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 100);
82
+ connection.setH2OverflowBytesDownloaded(50000);
83
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 0);
84
+ });
85
+
86
+ it('does not adjust the time to download for non-H2 connections', () => {
87
+ const connection = new TcpConnection(100, Infinity, 0, true, false);
88
+ connection.setWarmed(true);
89
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
90
+ connection.setH2OverflowBytesDownloaded(20000);
91
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
92
+ connection.setH2OverflowBytesDownloaded(50000);
93
+ assert.equal(connection.simulateDownloadUntil(30000).timeElapsed, 200);
94
+ });
95
+ });
96
+
97
+ describe('.simulateDownloadUntil', () => {
98
+ describe('when maximumTime is not set', () => {
99
+ it('should provide the correct values small payload non-SSL', () => {
100
+ const connection = new TcpConnection(100, Infinity, 0, false);
101
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
102
+ bytesDownloaded: 7300,
103
+ extraBytesDownloaded: 0,
104
+ congestionWindow: 10,
105
+ roundTrips: 2,
106
+ timeElapsed: 200,
107
+ connectionTiming: {
108
+ connectionTime: 150,
109
+ dnsResolutionTime: 0,
110
+ sslTime: undefined, // non-SSL
111
+ timeToFirstByte: 200,
112
+ },
113
+ });
114
+ });
115
+
116
+ it('should provide the correct values small payload SSL', () => {
117
+ const connection = new TcpConnection(100, Infinity, 0, true);
118
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
119
+ bytesDownloaded: 7300,
120
+ extraBytesDownloaded: 0,
121
+ congestionWindow: 10,
122
+ roundTrips: 3,
123
+ timeElapsed: 300,
124
+ connectionTiming: {
125
+ connectionTime: 250,
126
+ dnsResolutionTime: 0,
127
+ sslTime: 100,
128
+ timeToFirstByte: 300,
129
+ },
130
+ });
131
+ });
132
+
133
+ it('should provide the correct values small payload H2', () => {
134
+ const connection = new TcpConnection(100, Infinity, 0, true, true);
135
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
136
+ bytesDownloaded: 7300,
137
+ extraBytesDownloaded: 7300,
138
+ congestionWindow: 10,
139
+ roundTrips: 3,
140
+ timeElapsed: 300,
141
+ connectionTiming: {
142
+ connectionTime: 250,
143
+ dnsResolutionTime: 0,
144
+ sslTime: 100,
145
+ timeToFirstByte: 300,
146
+ },
147
+ });
148
+ });
149
+
150
+ it('should provide the correct values response time', () => {
151
+ const responseTime = 78;
152
+ const connection = new TcpConnection(100, Infinity, responseTime, true);
153
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
154
+ bytesDownloaded: 7300,
155
+ extraBytesDownloaded: 0,
156
+ congestionWindow: 10,
157
+ roundTrips: 3,
158
+ timeElapsed: 300 + responseTime,
159
+ connectionTiming: {
160
+ connectionTime: 250,
161
+ dnsResolutionTime: 0,
162
+ sslTime: 100,
163
+ timeToFirstByte: 378,
164
+ },
165
+ });
166
+ });
167
+
168
+ it('should provide the correct values large payload', () => {
169
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
170
+ const bytesToDownload = 10 * 1000 * 1000; // 10 mb
171
+ assert.deepEqual(connection.simulateDownloadUntil(bytesToDownload), {
172
+ bytesDownloaded: bytesToDownload,
173
+ extraBytesDownloaded: 0,
174
+ congestionWindow: 68,
175
+ roundTrips: 105,
176
+ timeElapsed: 10500,
177
+ connectionTiming: {
178
+ connectionTime: 250,
179
+ dnsResolutionTime: 0,
180
+ sslTime: 100,
181
+ timeToFirstByte: 300,
182
+ },
183
+ });
184
+ });
185
+
186
+ it('should provide the correct values resumed small payload', () => {
187
+ const connection = new TcpConnection(100, Infinity, 0, true);
188
+ assert.deepEqual(connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 250}), {
189
+ bytesDownloaded: 7300,
190
+ extraBytesDownloaded: 0,
191
+ congestionWindow: 10,
192
+ roundTrips: 3,
193
+ timeElapsed: 50,
194
+ connectionTiming: {
195
+ connectionTime: 250,
196
+ dnsResolutionTime: 0,
197
+ sslTime: 100,
198
+ timeToFirstByte: 300,
199
+ },
200
+ });
201
+ });
202
+
203
+ it('should provide the correct values resumed small payload H2', () => {
204
+ const connection = new TcpConnection(100, Infinity, 0, true, true);
205
+ connection.setWarmed(true);
206
+ connection.setH2OverflowBytesDownloaded(10000);
207
+ assert.deepEqual(connection.simulateDownloadUntil(7300), {
208
+ bytesDownloaded: 0,
209
+ extraBytesDownloaded: 2700, // 10000 - 7300
210
+ congestionWindow: 10,
211
+ roundTrips: 0,
212
+ timeElapsed: 0,
213
+ connectionTiming: {
214
+ timeToFirstByte: 0,
215
+ },
216
+ });
217
+ });
218
+
219
+ it('should provide the correct values resumed large payload', () => {
220
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
221
+ const bytesToDownload = 5 * 1000 * 1000; // 5 mb
222
+ connection.setCongestionWindow(68);
223
+ assert.deepEqual(
224
+ connection.simulateDownloadUntil(bytesToDownload, {timeAlreadyElapsed: 5234}),
225
+ {
226
+ bytesDownloaded: bytesToDownload,
227
+ extraBytesDownloaded: 0,
228
+ congestionWindow: 68,
229
+ roundTrips: 51, // 5 mb / (1460 * 68)
230
+ timeElapsed: 5100,
231
+ connectionTiming: {
232
+ connectionTime: 250,
233
+ dnsResolutionTime: 0,
234
+ sslTime: 100,
235
+ timeToFirstByte: 300,
236
+ },
237
+ }
238
+ );
239
+ });
240
+ });
241
+
242
+ describe('when maximumTime is set', () => {
243
+ it('should provide the correct values less than TTFB', () => {
244
+ const connection = new TcpConnection(100, Infinity, 0, false);
245
+ assert.deepEqual(
246
+ connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 68}),
247
+ {
248
+ bytesDownloaded: 7300,
249
+ extraBytesDownloaded: 0,
250
+ congestionWindow: 10,
251
+ roundTrips: 2,
252
+ timeElapsed: 200,
253
+ connectionTiming: {
254
+ connectionTime: 150,
255
+ dnsResolutionTime: 0,
256
+ sslTime: undefined, // non-SSL
257
+ timeToFirstByte: 200,
258
+ },
259
+ }
260
+ );
261
+ });
262
+
263
+ it('should provide the correct values just over TTFB', () => {
264
+ const connection = new TcpConnection(100, Infinity, 0, false);
265
+ assert.deepEqual(
266
+ connection.simulateDownloadUntil(7300, {timeAlreadyElapsed: 0, maximumTimeToElapse: 250}),
267
+ {
268
+ bytesDownloaded: 7300,
269
+ extraBytesDownloaded: 0,
270
+ congestionWindow: 10,
271
+ roundTrips: 2,
272
+ timeElapsed: 200,
273
+ connectionTiming: {
274
+ connectionTime: 150,
275
+ dnsResolutionTime: 0,
276
+ sslTime: undefined, // non-SSL
277
+ timeToFirstByte: 200,
278
+ },
279
+ }
280
+ );
281
+ });
282
+
283
+ it('should provide the correct values with already elapsed', () => {
284
+ const connection = new TcpConnection(100, Infinity, 0, false);
285
+ assert.deepEqual(
286
+ connection.simulateDownloadUntil(7300, {
287
+ timeAlreadyElapsed: 75,
288
+ maximumTimeToElapse: 250,
289
+ }),
290
+ {
291
+ bytesDownloaded: 7300,
292
+ extraBytesDownloaded: 0,
293
+ congestionWindow: 10,
294
+ roundTrips: 2,
295
+ timeElapsed: 125,
296
+ connectionTiming: {
297
+ connectionTime: 150,
298
+ dnsResolutionTime: 0,
299
+ sslTime: undefined, // non-SSL
300
+ timeToFirstByte: 200,
301
+ },
302
+ }
303
+ );
304
+ });
305
+
306
+ it('should provide the correct values large payloads', () => {
307
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
308
+ const bytesToDownload = 10 * 1000 * 1000; // 10 mb
309
+ assert.deepEqual(
310
+ connection.simulateDownloadUntil(bytesToDownload, {
311
+ timeAlreadyElapsed: 500,
312
+ maximumTimeToElapse: 740,
313
+ }),
314
+ {
315
+ bytesDownloaded: 683280, // should be less than 68 * 1460 * 8
316
+ extraBytesDownloaded: 0,
317
+ congestionWindow: 68,
318
+ roundTrips: 8,
319
+ timeElapsed: 800, // skips the handshake because time already elapsed
320
+ connectionTiming: {
321
+ connectionTime: 250,
322
+ dnsResolutionTime: 0,
323
+ sslTime: 100,
324
+ timeToFirstByte: 300,
325
+ },
326
+ }
327
+ );
328
+ });
329
+
330
+ it('should all add up', () => {
331
+ const connection = new TcpConnection(100, 8 * 1000 * 1000);
332
+ const bytesToDownload = 10 * 1000 * 1000; // 10 mb
333
+ const firstStoppingPoint = 5234;
334
+ const secondStoppingPoint = 315;
335
+ const thirdStoppingPoint = 10500 - firstStoppingPoint - secondStoppingPoint;
336
+
337
+ const firstSegment = connection.simulateDownloadUntil(bytesToDownload, {
338
+ timeAlreadyElapsed: 0,
339
+ maximumTimeToElapse: firstStoppingPoint,
340
+ });
341
+ const firstOvershoot = firstSegment.timeElapsed - firstStoppingPoint;
342
+
343
+ connection.setCongestionWindow(firstSegment.congestionWindow);
344
+ const secondSegment = connection.simulateDownloadUntil(
345
+ bytesToDownload - firstSegment.bytesDownloaded,
346
+ {
347
+ timeAlreadyElapsed: firstSegment.timeElapsed,
348
+ maximumTimeToElapse: secondStoppingPoint - firstOvershoot,
349
+ }
350
+ );
351
+ const secondOvershoot = firstOvershoot + secondSegment.timeElapsed - secondStoppingPoint;
352
+
353
+ connection.setCongestionWindow(secondSegment.congestionWindow);
354
+ const thirdSegment = connection.simulateDownloadUntil(
355
+ bytesToDownload - firstSegment.bytesDownloaded - secondSegment.bytesDownloaded,
356
+ {timeAlreadyElapsed: firstSegment.timeElapsed + secondSegment.timeElapsed}
357
+ );
358
+ const thirdOvershoot = secondOvershoot + thirdSegment.timeElapsed - thirdStoppingPoint;
359
+
360
+ assert.equal(thirdOvershoot, 0);
361
+ assert.equal(
362
+ firstSegment.bytesDownloaded +
363
+ secondSegment.bytesDownloaded +
364
+ thirdSegment.bytesDownloaded,
365
+ bytesToDownload
366
+ );
367
+ assert.equal(
368
+ firstSegment.timeElapsed + secondSegment.timeElapsed + thirdSegment.timeElapsed,
369
+ 10500
370
+ );
371
+ });
372
+ });
373
+ });
374
+ });
@@ -1,4 +1,4 @@
1
- export type ConnectionTiming = import('./simulator-timing-map.js').ConnectionTiming;
1
+ export type ConnectionTiming = import('./SimulationTimingMap.js').ConnectionTiming;
2
2
  export type DownloadOptions = {
3
3
  dnsResolutionTime?: number | undefined;
4
4
  timeAlreadyElapsed?: number | undefined;
@@ -86,4 +86,4 @@ export class TcpConnection {
86
86
  */
87
87
  simulateDownloadUntil(bytesToDownload: number, options?: DownloadOptions | undefined): DownloadResults;
88
88
  }
89
- //# sourceMappingURL=tcp-connection.d.ts.map
89
+ //# sourceMappingURL=TcpConnection.d.ts.map
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- /** @typedef {import('./simulator-timing-map.js').ConnectionTiming} ConnectionTiming */
7
+ /** @typedef {import('./SimulationTimingMap.js').ConnectionTiming} ConnectionTiming */
8
8
 
9
9
  const INITIAL_CONGESTION_WINDOW = 10;
10
10
  const TCP_SEGMENT_SIZE = 1460;
@@ -0,0 +1,21 @@
1
+ export { ConnectionPool } from "./ConnectionPool.js";
2
+ export { Constants } from "./Constants.js";
3
+ export { DNSCache } from "./DNSCache.js";
4
+ export { NetworkAnalyzer } from "./NetworkAnalyzer.js";
5
+ export { Simulator } from "./Simulator.js";
6
+ export { SimulatorTimingMap } from "./SimulationTimingMap.js";
7
+ export { TcpConnection } from "./TcpConnection.js";
8
+ export type GraphNetworkNode<T = any> = Lantern.Simulation.GraphNetworkNode<T>;
9
+ export type GraphNode<T = any> = Lantern.Simulation.GraphNode<T>;
10
+ export type Result<T = any> = Lantern.Simulation.Result<T>;
11
+ export type GraphCPUNode = Lantern.Simulation.GraphCPUNode;
12
+ export type MetricCoefficients = Lantern.Simulation.MetricCoefficients;
13
+ export type MetricComputationDataInput = Lantern.Simulation.MetricComputationDataInput;
14
+ export type NodeTiming = Lantern.Simulation.NodeTiming;
15
+ export type Options = Lantern.Simulation.Options;
16
+ export type PrecomputedLanternData = Lantern.Simulation.PrecomputedLanternData;
17
+ export type ProcessedNavigation = Lantern.Simulation.ProcessedNavigation;
18
+ export type Settings = Lantern.Simulation.Settings;
19
+ export type URL = Lantern.Simulation.URL;
20
+ import * as Lantern from '../types/lantern.js';
21
+ //# sourceMappingURL=simulation.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2024 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import * as Lantern from '../types/lantern.js';
8
+
9
+ export {ConnectionPool} from './ConnectionPool.js';
10
+ export {Constants} from './Constants.js';
11
+ export {DNSCache} from './DNSCache.js';
12
+ export {NetworkAnalyzer} from './NetworkAnalyzer.js';
13
+ export {Simulator} from './Simulator.js';
14
+ export {SimulatorTimingMap} from './SimulationTimingMap.js';
15
+ export {TcpConnection} from './TcpConnection.js';
16
+
17
+ /** @template [T=any] @typedef {Lantern.Simulation.GraphNetworkNode<T>} GraphNetworkNode */
18
+ /** @template [T=any] @typedef {Lantern.Simulation.GraphNode<T>} GraphNode */
19
+ /** @template [T=any] @typedef {Lantern.Simulation.Result<T>} Result */
20
+ /** @typedef {Lantern.Simulation.GraphCPUNode} GraphCPUNode */
21
+ /** @typedef {Lantern.Simulation.MetricCoefficients} MetricCoefficients */
22
+ /** @typedef {Lantern.Simulation.MetricComputationDataInput} MetricComputationDataInput */
23
+ /** @typedef {Lantern.Simulation.NodeTiming} NodeTiming */
24
+ /** @typedef {Lantern.Simulation.Options} Options */
25
+ /** @typedef {Lantern.Simulation.PrecomputedLanternData} PrecomputedLanternData */
26
+ /** @typedef {Lantern.Simulation.ProcessedNavigation} ProcessedNavigation */
27
+ /** @typedef {Lantern.Simulation.Settings} Settings */
28
+ /** @typedef {Lantern.Simulation.URL} URL */
@@ -4,7 +4,58 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import * as LH from '../../../../types/lh.js';
7
+ import * as Protocol from '@paulirish/trace_engine/generated/protocol.js';
8
+
9
+ declare module Util {
10
+ /** An object with the keys in the union K mapped to themselves as values. */
11
+ type SelfMap<K extends string> = {
12
+ [P in K]: P;
13
+ };
14
+ }
15
+
16
+ type TraceEvent = {
17
+ name: string;
18
+ cat: string;
19
+ args: {
20
+ name?: string;
21
+ fileName?: string;
22
+ snapshot?: string;
23
+ sync_id?: string;
24
+ beginData?: {
25
+ frame?: string;
26
+ startLine?: number;
27
+ url?: string;
28
+ };
29
+ data?: {
30
+ frame?: string;
31
+ readyState?: number;
32
+ stackTrace?: {
33
+ url: string
34
+ }[];
35
+ url?: string;
36
+ };
37
+ };
38
+ pid: number;
39
+ tid: number;
40
+ /** Timestamp of the event in microseconds. */
41
+ ts: number;
42
+ dur: number;
43
+ }
44
+ type Trace = {traceEvents: TraceEvent[]};
45
+ type ResourcePriority = ('VeryLow' | 'Low' | 'Medium' | 'High' | 'VeryHigh');
46
+ type ResourceType = ('Document' | 'Stylesheet' | 'Image' | 'Media' | 'Font' | 'Script' | 'TextTrack' | 'XHR' | 'Fetch' | 'Prefetch' | 'EventSource' | 'WebSocket' | 'Manifest' | 'SignedExchange' | 'Ping' | 'CSPViolationReport' | 'Preflight' | 'Other');
47
+ type InitiatorType = ('parser' | 'script' | 'preload' | 'SignedExchange' | 'preflight' | 'other');
48
+ type ResourceTiming = Protocol.Network.ResourceTiming;
49
+ type CallStack = {
50
+ callFrames: Array<{
51
+ scriptId: string;
52
+ url: string;
53
+ lineNumber: number;
54
+ columnNumber: number;
55
+ functionName: string;
56
+ }>;
57
+ parent?: CallStack;
58
+ }
8
59
 
9
60
  type ParsedURL = {
10
61
  /**
@@ -38,15 +89,16 @@ type LightriderStatistics = {
38
89
 
39
90
  export class NetworkRequest<T = any> {
40
91
  /**
41
- * The canonical network record.
42
- * Users of Lantern must create NetworkRequests matching this interface,
43
- * but can store the source-of-truth for their network model in this `record`
44
- * property. This is then accessible as a read-only property on NetworkNode.
92
+ * Implementation-specifc canoncial data structure that this Lantern NetworkRequest
93
+ * was derived from.
94
+ * Users of Lantern create a NetworkRequest matching this interface,
95
+ * but can store the source-of-truth for their network model in this property.
96
+ * This is then accessible as a read-only property on NetworkNode.
45
97
  */
46
- record?: T;
98
+ rawRequest?: T;
47
99
 
48
100
  requestId: string;
49
- connectionId: string;
101
+ connectionId: number;
50
102
  connectionReused: boolean;
51
103
  url: string;
52
104
  protocol: string;
@@ -59,7 +111,11 @@ export class NetworkRequest<T = any> {
59
111
  * HTTP cache or going to the network for DNS/connection setup, in milliseconds.
60
112
  */
61
113
  networkRequestTime: number;
62
- /** When the last byte of the response headers is received, in milliseconds. */
114
+ /**
115
+ * When the last byte of the response headers is received, in milliseconds.
116
+ * Equal to networkRequestTime if no data is recieved over the
117
+ * network (ex: cached requests or data urls).
118
+ */
63
119
  responseHeadersEndTime: number;
64
120
  /** When the last byte of the response body is received, in milliseconds. */
65
121
  networkEndTime: number;
@@ -67,33 +123,57 @@ export class NetworkRequest<T = any> {
67
123
  resourceSize: number;
68
124
  fromDiskCache: boolean;
69
125
  fromMemoryCache: boolean;
126
+ isLinkPreload: boolean;
70
127
  finished: boolean;
128
+ failed: boolean;
71
129
  statusCode: number;
130
+ /** The network request that redirected to this one */
131
+ redirectSource: NetworkRequest<T> | undefined;
72
132
  /** The network request that this one redirected to */
73
133
  redirectDestination: NetworkRequest<T> | undefined;
74
- failed: boolean;
75
- initiator: LH.Crdp.Network.Initiator;
134
+ // TODO: can't use Protocol.Network.Initiator because of type mismatch in Lighthouse initiator.
135
+ initiator: {
136
+ type: InitiatorType;
137
+ url?: string;
138
+ stack?: CallStack;
139
+ };
76
140
  initiatorRequest: NetworkRequest<T> | undefined;
77
141
  /** The chain of network requests that redirected to this one */
78
142
  redirects: NetworkRequest[] | undefined;
79
- timing: LH.Crdp.Network.ResourceTiming | undefined;
143
+ timing: Protocol.Network.ResourceTiming | undefined;
80
144
  /**
81
145
  * Optional value for how long the server took to respond to this request.
82
146
  * When not provided, the server response time is derived from the timing object.
83
147
  */
84
- serverResponseTime: number | undefined;
85
- resourceType: LH.Crdp.Network.ResourceType | undefined;
148
+ serverResponseTime?: number;
149
+ resourceType: ResourceType | undefined;
86
150
  mimeType: string;
87
- priority: LH.Crdp.Network.ResourcePriority;
151
+ priority: ResourcePriority;
88
152
  frameId: string | undefined;
89
- sessionTargetType: LH.Protocol.TargetType | undefined;
153
+ fromWorker: boolean;
154
+ }
155
+
156
+ interface MetricResult<T = any> {
157
+ timing: number;
158
+ timestamp?: never;
159
+ optimisticEstimate: Simulation.Result<T>;
160
+ pessimisticEstimate: Simulation.Result<T>;
161
+ optimisticGraph: Simulation.GraphNode<T>;
162
+ pessimisticGraph: Simulation.GraphNode<T>;
90
163
  }
91
164
 
92
165
  export namespace Simulation {
93
- type GraphNode<T> = import('../base-node.js').Node<T>;
94
- type GraphNetworkNode<T> = import('../network-node.js').NetworkNode<T>;
95
- type GraphCPUNode = import('../cpu-node.js').CPUNode;
96
- type Simulator<T> = import('../simulator/simulator.js').Simulator<T>;
166
+ type URL = {
167
+ /** URL of the initially requested URL */
168
+ requestedUrl?: string;
169
+ /** URL of the last document request */
170
+ mainDocumentUrl?: string;
171
+ };
172
+
173
+ type GraphNode<T> = import('../BaseNode.js').Node<T>;
174
+ type GraphNetworkNode<T> = import('../NetworkNode.js').NetworkNode<T>;
175
+ type GraphCPUNode = import('../CpuNode.js').CPUNode;
176
+ type Simulator<T> = import('../simulation/Simulator.js').Simulator<T>;
97
177
 
98
178
  interface MetricCoefficients {
99
179
  intercept: number;
@@ -101,6 +181,44 @@ export namespace Simulation {
101
181
  pessimistic: number;
102
182
  }
103
183
 
184
+ /** Simulation settings that control the amount of network & cpu throttling in the run. */
185
+ interface ThrottlingSettings {
186
+ /** The round trip time in milliseconds. */
187
+ rttMs?: number;
188
+ /** The network throughput in kilobits per second. */
189
+ throughputKbps?: number;
190
+ // devtools settings
191
+ /** The network request latency in milliseconds. */
192
+ requestLatencyMs?: number;
193
+ /** The network download throughput in kilobits per second. */
194
+ downloadThroughputKbps?: number;
195
+ /** The network upload throughput in kilobits per second. */
196
+ uploadThroughputKbps?: number;
197
+ // used by both
198
+ /** The amount of slowdown applied to the cpu (1/<cpuSlowdownMultiplier>). */
199
+ cpuSlowdownMultiplier?: number
200
+ }
201
+
202
+ interface PrecomputedLanternData {
203
+ additionalRttByOrigin: {[origin: string]: number};
204
+ serverResponseTimeByOrigin: {[origin: string]: number};
205
+ }
206
+
207
+ interface Settings {
208
+ networkAnalysis: {
209
+ rtt: number;
210
+ additionalRttByOrigin: Map<string, number>;
211
+ serverResponseTimeByOrigin: Map<string, number>;
212
+ throughput: number;
213
+ };
214
+ /** The method used to throttle the network. */
215
+ throttlingMethod: 'devtools'|'simulate'|'provided';
216
+ /** The throttling config settings. */
217
+ throttling: Required<ThrottlingSettings>;
218
+ /** Precomputed lantern estimates to use instead of observed analysis. */
219
+ precomputedLanternData?: PrecomputedLanternData | null;
220
+ }
221
+
104
222
  interface Options {
105
223
  rtt?: number;
106
224
  throughput?: number;
@@ -123,9 +241,16 @@ export namespace Simulation {
123
241
  nodeTimings: Map<GraphNode<T>, NodeTiming>;
124
242
  }
125
243
 
244
+ interface ProcessedNavigation {
245
+ timestamps: {
246
+ firstContentfulPaint: number;
247
+ largestContentfulPaint?: number;
248
+ };
249
+ }
250
+
126
251
  interface MetricComputationDataInput {
127
252
  simulator: Simulator<any>;
128
253
  graph: GraphNode<any>;
129
- processedNavigation: LH.Artifacts.ProcessedNavigation;
254
+ processedNavigation: ProcessedNavigation;
130
255
  }
131
256
  }