phantomas 2.0.0 → 2.4.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 (54) hide show
  1. package/Dockerfile +39 -25
  2. package/README.md +20 -8
  3. package/bin/phantomas.js +9 -164
  4. package/bin/program.js +198 -0
  5. package/bin/utils.js +16 -0
  6. package/core/modules/navigationTiming/scope.js +7 -1
  7. package/core/modules/requestsMonitor/requestsMonitor.js +30 -13
  8. package/core/scope.js +2 -1
  9. package/extensions/cookies/cookies.js +1 -2
  10. package/extensions/filmStrip/filmStrip.js +1 -1
  11. package/extensions/pageSource/pageSource.js +2 -0
  12. package/extensions/pageStorage/pageStorage.js +82 -0
  13. package/extensions/screenshot/screenshot.js +27 -9
  14. package/extensions/scroll/scroll.js +3 -1
  15. package/extensions/userAgent/userAgent.js +55 -0
  16. package/extensions/viewport/viewport.js +1 -1
  17. package/extensions/waitForSelector/waitForSelector.js +0 -1
  18. package/hooks/build +3 -0
  19. package/lib/browser.js +81 -33
  20. package/lib/index.js +18 -9
  21. package/lib/loader.js +3 -4
  22. package/lib/metadata/metadata.json +180 -29
  23. package/modules/ajaxRequests/scope.js +1 -1
  24. package/modules/analyzeCss/analyzeCss.js +79 -76
  25. package/modules/analyzeCss/scope.js +1 -1
  26. package/modules/blockDomains/blockDomains.js +21 -21
  27. package/modules/cacheHits/cacheHits.js +6 -3
  28. package/modules/cpuTasks/cpuTasks.js +22 -0
  29. package/modules/documentHeight/scope.js +1 -1
  30. package/modules/domComplexity/scope.js +1 -1
  31. package/modules/domHiddenContent/scope.js +1 -1
  32. package/modules/domMutations/scope.js +1 -1
  33. package/modules/domQueries/domQueries.js +16 -19
  34. package/modules/domQueries/scope.js +1 -1
  35. package/modules/domains/domains.js +1 -1
  36. package/modules/events/scope.js +2 -1
  37. package/modules/globalVariables/scope.js +1 -1
  38. package/modules/jQuery/scope.js +1 -1
  39. package/modules/javaScriptBottlenecks/scope.js +1 -1
  40. package/modules/lazyLoadableImages/scope.js +2 -2
  41. package/modules/localStorage/scope.js +1 -1
  42. package/modules/protocols/protocols.js +101 -0
  43. package/modules/requestsStats/requestsStats.js +1 -1
  44. package/modules/staticAssets/staticAssets.js +2 -1
  45. package/modules/windowPerformance/windowPerformance.js +1 -0
  46. package/package.json +31 -20
  47. package/lib/fast-stats.js +0 -634
  48. package/lib/metadata/generate.js +0 -283
  49. package/lib/metadata/make_docs.js +0 -185
  50. package/reporters/csv.js +0 -54
  51. package/reporters/plain.js +0 -173
  52. package/reporters/statsd.js +0 -82
  53. package/reporters/tap.js +0 -71
  54. package/reporters/teamcity.js +0 -73
@@ -69,7 +69,7 @@ module.exports = function (phantomas) {
69
69
  return f + str.substr(1);
70
70
  }
71
71
 
72
- function analyzeCss(css, context, callback) {
72
+ async function analyzeCss(css, context) {
73
73
  /**
74
74
  // force JSON output format
75
75
  options.push('--json');
@@ -94,90 +94,89 @@ module.exports = function (phantomas) {
94
94
 
95
95
  // https://www.npmjs.com/package/analyze-css#commonjs-module
96
96
  var options = {};
97
-
98
- new analyzer(css, options, function (err, results) {
99
- var offenderSrc = context || "[inline CSS]";
100
-
101
- if (err !== null) {
102
- phantomas.log("analyzeCss: sub-process failed! - %s", err);
103
-
104
- // report failed CSS parsing (issue #494(
105
- var offender = offenderSrc;
106
- if (err.message) {
107
- // Error object returned
108
- if (err.message.indexOf("Unable to parse JSON string") > 0) {
109
- offender += " (analyzeCss output error)";
110
- }
111
- } else {
112
- // Error string returned (stderror)
113
- if (
114
- err.indexOf("CSS parsing failed") > 0 ||
115
- err.indexOf("is an invalid expression") > 0
116
- ) {
117
- offender += " (" + err.trim() + ")";
118
- } else if (err.indexOf("Empty CSS was provided") > 0) {
119
- offender += " (Empty CSS was provided)";
120
- }
97
+ let results;
98
+
99
+ try {
100
+ results = await analyzer(css, options);
101
+ } catch (err) {
102
+ phantomas.log("analyzeCss: sub-process failed! - %s", err);
103
+
104
+ // report failed CSS parsing (issue #494(
105
+ var offender = offenderSrc;
106
+ if (err.message) {
107
+ // Error object returned
108
+ if (err.message.indexOf("Unable to parse JSON string") > 0) {
109
+ offender += " (analyzeCss output error)";
110
+ }
111
+ } else {
112
+ // Error string returned (stderror)
113
+ if (
114
+ err.indexOf("CSS parsing failed") > 0 ||
115
+ err.indexOf("is an invalid expression") > 0
116
+ ) {
117
+ offender += " (" + err.trim() + ")";
118
+ } else if (err.indexOf("Empty CSS was provided") > 0) {
119
+ offender += " (Empty CSS was provided)";
121
120
  }
121
+ }
122
122
 
123
- phantomas.incrMetric("cssParsingErrors");
124
- phantomas.addOffender("cssParsingErrors", offender);
123
+ phantomas.incrMetric("cssParsingErrors");
124
+ phantomas.addOffender("cssParsingErrors", offender);
125
+ return;
126
+ }
125
127
 
126
- callback();
127
- return;
128
- }
128
+ var offenderSrc = context || "[inline CSS]";
129
129
 
130
- phantomas.log(
131
- "Got results for %s from %s",
132
- offenderSrc,
133
- results.generator
134
- );
130
+ phantomas.log("Got results for %s from %s", offenderSrc, results.generator);
135
131
 
136
- var metrics = results.metrics || {},
137
- offenders = results.offenders || {};
132
+ const metrics = results.metrics,
133
+ offenders = results.offenders;
138
134
 
139
- Object.keys(metrics).forEach(function (metric) {
140
- var metricPrefixed = "css" + ucfirst(metric);
135
+ Object.keys(metrics).forEach((metric) => {
136
+ var metricPrefixed = "css" + ucfirst(metric);
141
137
 
142
- if (/Avg$/.test(metricPrefixed)) {
143
- // update the average value (see #641)
144
- phantomas.addToAvgMetric(metricPrefixed, metrics[metric]);
145
- } else {
146
- // increase metrics
147
- phantomas.incrMetric(metricPrefixed, metrics[metric]);
148
- }
138
+ if (/Avg$/.test(metricPrefixed)) {
139
+ // update the average value (see #641)
140
+ phantomas.addToAvgMetric(metricPrefixed, metrics[metric]);
141
+ } else {
142
+ // increase metrics
143
+ phantomas.incrMetric(metricPrefixed, metrics[metric]);
144
+ }
149
145
 
150
- // and add offenders
151
- if (typeof offenders[metric] !== "undefined") {
152
- offenders[metric].forEach(function (msg) {
146
+ // and add offenders
147
+ if (typeof offenders[metric] !== "undefined") {
148
+ offenders[metric].forEach((offender) => {
149
+ phantomas.addOffender(metricPrefixed, {
150
+ url: offenderSrc,
151
+ value: {
152
+ message: offender.message,
153
+ position: {
154
+ ...offender.position,
155
+ source: offender.source || "undefined",
156
+ }, // cast to object
157
+ },
158
+ });
159
+ });
160
+ }
161
+ // add more offenders (#578)
162
+ else {
163
+ switch (metricPrefixed) {
164
+ case "cssLength":
165
+ case "cssRules":
166
+ case "cssSelectors":
167
+ case "cssDeclarations":
168
+ case "cssNotMinified":
169
+ case "cssSelectorLengthAvg":
170
+ case "cssSpecificityIdAvg":
171
+ case "cssSpecificityClassAvg":
172
+ case "cssSpecificityTagAvg":
153
173
  phantomas.addOffender(metricPrefixed, {
154
174
  url: offenderSrc,
155
- value: msg,
175
+ value: metrics[metric],
156
176
  });
157
- });
158
- }
159
- // add more offenders (#578)
160
- else {
161
- switch (metricPrefixed) {
162
- case "cssLength":
163
- case "cssRules":
164
- case "cssSelectors":
165
- case "cssDeclarations":
166
- case "cssNotMinified":
167
- case "cssSelectorLengthAvg":
168
- case "cssSpecificityIdAvg":
169
- case "cssSpecificityClassAvg":
170
- case "cssSpecificityTagAvg":
171
- phantomas.addOffender(metricPrefixed, {
172
- url: offenderSrc,
173
- value: metrics[metric],
174
- });
175
- break;
176
- }
177
+ break;
177
178
  }
178
- });
179
-
180
- callback();
179
+ }
181
180
  });
182
181
  }
183
182
 
@@ -195,19 +194,23 @@ module.exports = function (phantomas) {
195
194
 
196
195
  // ok, now let's analyze the collect CSS
197
196
  phantomas.on("beforeClose", () => {
198
- var promises = [];
197
+ const promises = [];
199
198
 
200
199
  stylesheets.forEach((entry) => {
201
200
  promises.push(
202
201
  new Promise(async (resolve) => {
203
- var css = entry.inline;
202
+ let css = entry.inline;
204
203
  phantomas.log("Analyzing %s", entry.url || "inline CSS");
205
204
 
206
205
  if (entry.content) {
207
206
  css = await entry.content();
208
207
  }
209
208
 
210
- analyzeCss(css, entry.url, resolve);
209
+ if (css) {
210
+ await analyzeCss(css, entry.url);
211
+ }
212
+
213
+ resolve();
211
214
  })
212
215
  );
213
216
  });
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function analyzeCssScope(phantomas) {
2
2
  document.addEventListener("DOMContentLoaded", function () {
3
3
  // both DOM and CSSOM are constructed, no stylesheets are blocking JavaScript execution
4
4
  phantomas.spyEnabled(false, "Checking inline scripts");
@@ -6,8 +6,6 @@
6
6
  "use strict";
7
7
 
8
8
  module.exports = function (phantomas) {
9
- const { parse } = require("url");
10
-
11
9
  var ourDomain,
12
10
  // --no-externals
13
11
  noExternalsMode = phantomas.getParam("no-externals") === true,
@@ -18,7 +16,7 @@ module.exports = function (phantomas) {
18
16
  blockedDomains = phantomas.getParam("block-domain"),
19
17
  blockedDomainsRegExp;
20
18
 
21
- ourDomain = parse(phantomas.getParam("url")).hostname;
19
+ ourDomain = new URL(phantomas.getParam("url")).hostname;
22
20
 
23
21
  phantomas.setMetric("blockedRequests"); // @desc number of requests blocked due to domain filtering @optional
24
22
 
@@ -76,27 +74,29 @@ module.exports = function (phantomas) {
76
74
  blockedDomainsRegExp = new RegExp("(" + blockedDomains.join("|") + ")$");
77
75
  }
78
76
 
79
- // https://github.com/GoogleChrome/puppeteer/blob/v1.11.0/docs/api.md#pagesetrequestinterceptionvalue
80
- phantomas.on("init", async (page) => {
81
- await page.setRequestInterception(true);
77
+ if (noExternalsMode || allowedDomains !== false || blockedDomains !== false) {
78
+ // https://github.com/GoogleChrome/puppeteer/blob/v1.11.0/docs/api.md#pagesetrequestinterceptionvalue
79
+ phantomas.on("init", async (page) => {
80
+ await page.setRequestInterception(true);
82
81
 
83
- page.on("request", (interceptedRequest) => {
84
- const url = interceptedRequest.url(),
85
- domain = parse(url).hostname;
82
+ page.on("request", (interceptedRequest) => {
83
+ const url = interceptedRequest.url(),
84
+ domain = new URL(url).hostname;
86
85
 
87
- if (checkBlock(domain)) {
88
- interceptedRequest.abort();
86
+ if (checkBlock(domain)) {
87
+ interceptedRequest.abort();
89
88
 
90
- phantomas.log("Request has been blocked: <%s>", url);
89
+ phantomas.log("Request has been blocked: <%s>", url);
91
90
 
92
- // stats
93
- phantomas.incrMetric("blockedRequests");
94
- phantomas.addOffender("blockedRequests", url);
95
- } else {
96
- interceptedRequest.continue();
97
- }
98
- });
91
+ // stats
92
+ phantomas.incrMetric("blockedRequests");
93
+ phantomas.addOffender("blockedRequests", url);
94
+ } else {
95
+ interceptedRequest.continue();
96
+ }
97
+ });
99
98
 
100
- phantomas.log("Requests intercepting enabled");
101
- });
99
+ phantomas.log("Requests intercepting enabled");
100
+ });
101
+ }
102
102
  };
@@ -9,15 +9,18 @@ module.exports = function (phantomas) {
9
9
  phantomas.setMetric("cachePasses"); // @desc number of cache passes @offenders
10
10
 
11
11
  phantomas.on("recv", (entry) => {
12
- var age, xCacheHeader, isHit, isMiss, isPass;
12
+ let isHit, isMiss, isPass;
13
13
 
14
14
  // parser response headers
15
15
  //
16
16
  // X-Cache:HIT, HIT
17
17
  // X-Cache:arsenic miss (0)
18
18
  // Age: 170221
19
- age = parseInt(entry.headers.Age, 10);
20
- xCacheHeader = (entry.headers["X-Cache"] || "").toLowerCase();
19
+ const age =
20
+ typeof entry.headers.Age !== "undefined"
21
+ ? parseInt(entry.headers.Age, 10)
22
+ : undefined,
23
+ xCacheHeader = (entry.headers["X-Cache"] || "").toLowerCase();
21
24
 
22
25
  if (xCacheHeader !== "") {
23
26
  isHit = xCacheHeader.indexOf("hit") > -1;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Retrieves stats about layouts, style recalcs and JS execution
3
+ *
4
+ * Metrics from https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagemetrics
5
+ */
6
+ "use strict";
7
+
8
+ module.exports = function (phantomas) {
9
+ // Converts seconds into milliseconds
10
+ function ms(value) {
11
+ return Math.round(value * 1000);
12
+ }
13
+
14
+ phantomas.on("metrics", (metrics) => {
15
+ phantomas.setMetric("layoutCount", metrics.LayoutCount); // @desc total number of full or partial page layout
16
+ phantomas.setMetric("layoutDuration", ms(metrics.LayoutDuration)); // @desc combined durations of all page layouts
17
+ phantomas.setMetric("recalcStyleCount", metrics.RecalcStyleCount); // @desc total number of page style recalculations
18
+ phantomas.setMetric("recalcStyleDuration", ms(metrics.RecalcStyleDuration)); // @desc combined duration of style recalculations
19
+ phantomas.setMetric("scriptDuration", ms(metrics.ScriptDuration)); // @desc combined duration of JavaScript execution
20
+ phantomas.setMetric("taskDuration", ms(metrics.TaskDuration)); // @desc combined duration of all tasks performed by the browser
21
+ });
22
+ };
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function documentHeightScope(phantomas) {
2
2
  document.addEventListener("DOMContentLoaded", () => {
3
3
  // @see https://github.com/HTTPArchive/httparchive/blob/master/custom_metrics/document_height.js
4
4
  var doc = document,
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function domComplexityScope(phantomas) {
2
2
  phantomas.spyEnabled(false, "initializing domComplexity metrics");
3
3
 
4
4
  window.addEventListener("load", () => {
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function domHiddenContentScope(phantomas) {
2
2
  phantomas.spyEnabled(false, "initializing hidden content analysis");
3
3
 
4
4
  window.addEventListener("load", () => {
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function DOMmutationsScope(phantomas) {
2
2
  if ("MutationObserver" in window) {
3
3
  // wait for DOM ready
4
4
  document.addEventListener("readystatechange", function () {
@@ -19,27 +19,24 @@ module.exports = (phantomas) => {
19
19
  //
20
20
 
21
21
  // report DOM queries that return no results (issue #420)
22
- phantomas.on("domQuery", function (
23
- type,
24
- query,
25
- fnName,
26
- context,
27
- hasNoResults
28
- ) {
29
- // ignore DOM queries within DOM fragments (used internally by jQuery)
30
- if (context.indexOf("body") !== 0 && context.indexOf("#document") !== 0) {
31
- return;
32
- }
22
+ phantomas.on(
23
+ "domQuery",
24
+ function (type, query, fnName, context, hasNoResults) {
25
+ // ignore DOM queries within DOM fragments (used internally by jQuery)
26
+ if (context.indexOf("body") !== 0 && context.indexOf("#document") !== 0) {
27
+ return;
28
+ }
33
29
 
34
- if (hasNoResults === true) {
35
- phantomas.incrMetric("DOMqueriesWithoutResults");
36
- phantomas.addOffender("DOMqueriesWithoutResults", {
37
- query,
38
- node: context,
39
- function: fnName,
40
- });
30
+ if (hasNoResults === true) {
31
+ phantomas.incrMetric("DOMqueriesWithoutResults");
32
+ phantomas.addOffender("DOMqueriesWithoutResults", {
33
+ query,
34
+ node: context,
35
+ function: fnName,
36
+ });
37
+ }
41
38
  }
42
- });
39
+ );
43
40
 
44
41
  // count DOM queries by either ID, tag name, class name and selector query
45
42
  // @see https://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-doctype
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function domQueriesScope(phantomas) {
2
2
  phantomas.log("domQueries: initializing page scope code");
3
3
 
4
4
  function querySpy(type, query, fnName, context, hasNoResults) {
@@ -3,7 +3,7 @@
3
3
  */
4
4
  "use strict";
5
5
 
6
- const Stats = require("../../lib/fast-stats").Stats;
6
+ const Stats = require("fast-stats").Stats;
7
7
 
8
8
  module.exports = function (phantomas) {
9
9
  var Collection = require("../../lib/collection"),
@@ -1,4 +1,5 @@
1
- (function (phantomas) {
1
+ /* istanbul ignore next */
2
+ (function eventsScope(phantomas) {
2
3
  // spy calls to EventTarget.addEventListener
3
4
  // @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
4
5
  function eventSpy(eventType) {
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function globalVariablesScope(phantomas) {
2
2
  // get the list of initial, built-in global variables
3
3
  var allowed = [],
4
4
  varName;
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function jQueryScope(phantomas) {
2
2
  // read & write DOM operations (issue #436)
3
3
  function spyReadsAndWrites(jQuery) {
4
4
  var TYPE_SET = "write",
@@ -1,4 +1,4 @@
1
- (async (phantomas) => {
1
+ (async function javaScriptBottlenecksScope(phantomas) {
2
2
  // spy calls to eval only when requested (issue #467)
3
3
  var spyEval = (await phantomas.getParam("spy-eval")) === true;
4
4
 
@@ -1,10 +1,10 @@
1
- ((phantomas) => {
1
+ (function lazyLoadableImages(phantomas) {
2
2
  phantomas.spyEnabled(
3
3
  false,
4
4
  "setting up which images can be lazy-loaded analysis"
5
5
  );
6
6
 
7
- window.addEventListener("beforeunload", () => {
7
+ window.addEventListener("load", () => {
8
8
  phantomas.spyEnabled(false, "analyzing which images can be lazy-loaded");
9
9
 
10
10
  var images = document.body.getElementsByTagName("img"),
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function localStorageScope(phantomas) {
2
2
  window.addEventListener("load", () => {
3
3
  try {
4
4
  var entries = Object.keys(window.localStorage);
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Checks versions of HTTP and TLS protocols
3
+ */
4
+ "use strict";
5
+
6
+ module.exports = function (phantomas) {
7
+ var domains = new Map(),
8
+ mainDomain = undefined,
9
+ beforeDomReady = true;
10
+
11
+ phantomas.setMetric("mainDomainHttpProtocol"); // @desc HTTP protocol used by the main domain [string]
12
+ phantomas.setMetric("oldHttpProtocol"); // @desc number of domains using HTTP/1.0 or 1.1
13
+ phantomas.setMetric("mainDomainTlsProtocol"); // @desc TLS protocol used by the main domain [string]
14
+ phantomas.setMetric("oldTlsProtocol"); // @desc number of domains using TLS 1.1 or 1.2
15
+
16
+ // spy all requests
17
+ phantomas.on("recv", (entry) => {
18
+ if (entry.domain) {
19
+ var domain = (entry.isSSL ? "https://" : "http://") + entry.domain;
20
+
21
+ if (domains.size === 0) {
22
+ mainDomain = domain;
23
+ phantomas.log("Our main domain is now %s", mainDomain);
24
+ }
25
+
26
+ if (domain == mainDomain) {
27
+ // our first request represents the main domain
28
+ // h3 protocol is used for subsequent requests for the same domain
29
+ // we need to keep updating these metrics on each response we get
30
+ phantomas.setMetric("mainDomainHttpProtocol", entry.httpVersion);
31
+ phantomas.setMetric("mainDomainTlsProtocol", entry.tlsVersion);
32
+ }
33
+
34
+ if (!domains.has(domain)) {
35
+ phantomas.log(
36
+ "New domain %s uses HTTP version %s and TLS version %s",
37
+ domain,
38
+ entry.httpVersion,
39
+ entry.tlsVersion
40
+ );
41
+
42
+ // add the new domain to the Map
43
+ domains.set(domain, {
44
+ requests: 1,
45
+ httpVersion: entry.httpVersion,
46
+ tlsVersion: entry.tlsVersion,
47
+ beforeDomReady: beforeDomReady,
48
+ });
49
+ } else {
50
+ // just increment the number of requests
51
+ domains.get(domain).requests++;
52
+
53
+ // h3 protocol is used for subsequent requests for the same domain
54
+ // initial ones are performed using h2
55
+ domains.get(domain).httpVersion = entry.httpVersion;
56
+ domains.get(domain).tlsVersion = entry.tlsVersion;
57
+ }
58
+ }
59
+ });
60
+
61
+ // listen to DOM Ready
62
+ phantomas.on("milestone", (name) => {
63
+ if (name === "domReady") {
64
+ beforeDomReady = false;
65
+ }
66
+ });
67
+
68
+ // set metrics
69
+ phantomas.on("report", () => {
70
+ domains.forEach(function (value, key) {
71
+ // As of 2020, h2 is the latest protocol, h3 is coming in 2021
72
+ if (value.httpVersion.indexOf("http/1") === 0) {
73
+ phantomas.incrMetric("oldHttpProtocol");
74
+ phantomas.addOffender("oldHttpProtocol", {
75
+ domain: key,
76
+ httpVersion: value.httpVersion,
77
+ requests: value.requests, // the more requests, the more h2 is important
78
+ });
79
+ }
80
+
81
+ // As of 2020, TLS 1.3 is the latest protocol and it brings speed improvements over 1.2
82
+ if (value.tlsVersion) {
83
+ // parse version number
84
+ var tlsVersion =
85
+ value.tlsVersion === "QUIC"
86
+ ? "quic"
87
+ : parseFloat(value.tlsVersion.substring(4));
88
+ phantomas.log(`tlsVersion for ${key} domain is ${tlsVersion}`);
89
+
90
+ if (tlsVersion !== "quic" && tlsVersion < 1.3) {
91
+ phantomas.incrMetric("oldTlsProtocol");
92
+ phantomas.addOffender("oldTlsProtocol", {
93
+ domain: key,
94
+ tlsVersion: value.tlsVersion,
95
+ beforeDomReady: value.beforeDomReady, // identifies the most critical domains
96
+ });
97
+ }
98
+ }
99
+ });
100
+ });
101
+ };
@@ -12,7 +12,7 @@
12
12
  */
13
13
  "use strict";
14
14
 
15
- var Stats = require("../../lib/fast-stats").Stats;
15
+ var Stats = require("fast-stats").Stats;
16
16
 
17
17
  module.exports = function (phantomas) {
18
18
  var stack = {};
@@ -11,7 +11,8 @@ module.exports = function (phantomas) {
11
11
  assetsReqCounter = new Collection(),
12
12
  cookieDomains = new Collection(),
13
13
  // TODO: use 3pc database with tracking services
14
- trackingUrls = /google-analytics.com\/__utm.gif|pixel.quantserve.com\/pixel/;
14
+ trackingUrls =
15
+ /google-analytics.com\/__utm.gif|pixel.quantserve.com\/pixel/;
15
16
 
16
17
  phantomas.setMetric("assetsNotGzipped"); // @desc number of static assets that were not gzipped
17
18
  phantomas.setMetric("assetsWithQueryString"); // @desc number of static assets requested with query string (e.g. ?foo) in URL
@@ -25,6 +25,7 @@ module.exports = function (phantomas) {
25
25
  phantomas.setMetric("timeFrontend"); // @desc time to window.load compared to the total loading time [%]
26
26
 
27
27
  phantomas.on("beforeClose", async function () {
28
+ /* istanbul ignore next */
28
29
  const timing = await phantomas.evaluate(() => {
29
30
  return window.performance.timing.toJSON();
30
31
  });