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
package/lib/index.js CHANGED
@@ -3,14 +3,13 @@
3
3
  */
4
4
  "use strict";
5
5
 
6
- var Browser = require("./browser"),
6
+ const Browser = require("./browser"),
7
7
  EventEmitter = require("./AwaitEventEmitter"),
8
8
  debug = require("debug")("phantomas:core"),
9
9
  loader = require("./loader"),
10
10
  puppeteer = require("puppeteer"),
11
11
  path = require("path"),
12
12
  Results = require("../core/results"),
13
- util = require("util"),
14
13
  VERSION = require("./../package").version;
15
14
 
16
15
  /**
@@ -35,12 +34,12 @@ function phantomas(url, opts) {
35
34
  debug("URL: <%s>", url);
36
35
 
37
36
  // options handling
38
- options = util._extend({}, opts || {}); // use util._extend to avoid #563
37
+ options = Object.assign({}, opts || {}); // avoid #563
39
38
  options.url = options.url || url || false;
40
39
 
41
40
  debug("Options: %s", JSON.stringify(options));
42
41
 
43
- events.setMaxListeners(100); // MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
42
+ events.setMaxListeners(250); // MaxListenersExceededWarning: Possible EventEmitter memory leak detected.
44
43
 
45
44
  var results = new Results();
46
45
  results.setUrl(url);
@@ -56,7 +55,7 @@ function phantomas(url, opts) {
56
55
  return reject(Error("URL must be a string"));
57
56
  }
58
57
 
59
- const page = await browser.init(),
58
+ const page = await browser.init(options),
60
59
  debugScope = require("debug")("phantomas:scope:log");
61
60
 
62
61
  // prepare a small instance object that will be passed to modules and extensions on init
@@ -83,15 +82,23 @@ function phantomas(url, opts) {
83
82
  evaluate: page.evaluate.bind(page),
84
83
 
85
84
  // @see https://github.com/GoogleChrome/puppeteer/blob/v1.11.0/docs/api.md#pageselector-1
86
- querySelectorAll: async (selector) => {
85
+ querySelectorAll: async function querySelectorAll(
86
+ selector
87
+ ) /* istanbul ignore next */ {
87
88
  debug('querySelectorAll("%s")', selector);
88
89
  return page.$$(selector);
89
90
  },
90
91
 
91
92
  // @see https://github.com/GoogleChrome/puppeteer/blob/v1.11.0/docs/api.md#pageevaluateonnewdocumentpagefunction-args
92
93
  injectJs: async (script) => {
93
- const debug = require("debug")("phantomas:injectJs"),
94
- preloadFile = require("fs").readFileSync(script, "utf8");
94
+ const debug = require("debug")("phantomas:injectJs");
95
+
96
+ // Make sure we're on an HTML document, not an XML document for example
97
+ const prefix = "if (document.constructor.name === 'HTMLDocument') {",
98
+ suffix = "}";
99
+
100
+ const preloadFile =
101
+ prefix + require("fs").readFileSync(script, "utf8") + suffix;
95
102
 
96
103
  await page.evaluateOnNewDocument(preloadFile);
97
104
 
@@ -101,6 +108,7 @@ function phantomas(url, opts) {
101
108
 
102
109
  // pass phantomas options to page scope
103
110
  // https://github.com/GoogleChrome/puppeteer/blob/v1.11.0/docs/api.md#pageevaluateonnewdocumentpagefunction-args
111
+ /* istanbul ignore next */
104
112
  await page.evaluateOnNewDocument((options) => {
105
113
  window.__phantomas_options = options;
106
114
  }, options);
@@ -127,6 +135,7 @@ function phantomas(url, opts) {
127
135
  scope[type].apply(scope, args);
128
136
  break;
129
137
 
138
+ /* istanbul ignore next */
130
139
  default:
131
140
  debug("Unrecognized event type: " + type);
132
141
  }
@@ -167,7 +176,7 @@ function phantomas(url, opts) {
167
176
  debug("Loading modules...");
168
177
  loader.loadModules(scope);
169
178
 
170
- await events.emit("init", page, browser); // @desc Browser's scope and modules are set up, the page is about to be loaded
179
+ await events.emit("init", page, browser.getPuppeteerBrowser()); // @desc Browser's scope and modules are set up, the page is about to be loaded
171
180
 
172
181
  // https://github.com/GoogleChrome/puppeteer/blob/v1.11.0/docs/api.md#pagegotourl-options
173
182
  const waitUntil = options["wait-for-network-idle"]
package/lib/loader.js CHANGED
@@ -2,7 +2,6 @@
2
2
  * Handles loading of modules and extensions
3
3
  */
4
4
  const debug = require("debug"),
5
- extend = require("util")._extend,
6
5
  fs = require("fs");
7
6
 
8
7
  /**
@@ -35,7 +34,7 @@ function loadCoreModules(scope) {
35
34
 
36
35
  modules.forEach((name) => {
37
36
  var log = debug("phantomas:modules:" + name),
38
- _scope = extend({}, scope);
37
+ _scope = Object.assign({}, scope);
39
38
 
40
39
  _scope.log = log;
41
40
 
@@ -55,7 +54,7 @@ function loadExtensions(scope) {
55
54
 
56
55
  extensions.forEach((name) => {
57
56
  var log = debug("phantomas:extensions:" + name),
58
- _scope = extend({}, scope);
57
+ _scope = Object.assign({}, scope);
59
58
 
60
59
  _scope.log = log;
61
60
 
@@ -69,7 +68,7 @@ function loadModules(scope) {
69
68
 
70
69
  extensions.forEach((name) => {
71
70
  var log = debug("phantomas:modules:" + name),
72
- _scope = extend({}, scope);
71
+ _scope = Object.assign({}, scope);
73
72
 
74
73
  _scope.log = log;
75
74
 
@@ -117,6 +117,11 @@
117
117
  "desc": "Allow page to be scrolled after it is loaded\nPass --scroll as an option in CLI mode",
118
118
  "options": []
119
119
  },
120
+ "viewport": {
121
+ "file": "/extensions/viewport/viewport.js",
122
+ "desc": "Provides the --viewport option to set any device resolution and pixel density ratio.\nIf the user sets a viewport size as well as a device option (--phone, --tablet, ...),\nwe assume that he or she wants to overwrite the device values.\nTwo syntaxes are supported:\n - 1200x800 will set a 1x pixel density ratio\n - 1200x800x2 will set the given ratio (float values such as 1.5 are accepted)",
123
+ "options": []
124
+ },
120
125
  "waitForEvent": {
121
126
  "file": "/extensions/waitForEvent/waitForEvent.js",
122
127
  "desc": "Delays report generation until given phantomas event is emitted (issue #453)",
@@ -138,7 +143,11 @@
138
143
  "requestsMonitor": {
139
144
  "file": "/core/modules/requestsMonitor/requestsMonitor.js",
140
145
  "desc": "Simple HTTP requests monitor and analyzer",
141
- "events": ["send", "base64recv", "recv"],
146
+ "events": [
147
+ "send",
148
+ "base64recv",
149
+ "recv"
150
+ ],
142
151
  "metrics": [
143
152
  "requests",
144
153
  "gzipRequests",
@@ -153,20 +162,32 @@
153
162
  "timeToFirstByte": {
154
163
  "file": "/core/modules/timeToFirstByte/timeToFirstByte.js",
155
164
  "desc": "Takes a look at \"time to first (last) byte\" metrics",
156
- "events": ["responseEnd"],
157
- "metrics": ["timeToFirstByte", "timeToLastByte"]
165
+ "events": [
166
+ "responseEnd"
167
+ ],
168
+ "metrics": [
169
+ "timeToFirstByte",
170
+ "timeToLastByte"
171
+ ]
158
172
  },
159
173
  "ajaxRequests": {
160
174
  "file": "/modules/ajaxRequests/ajaxRequests.js",
161
175
  "desc": "Analyzes AJAX requests",
162
176
  "events": [],
163
- "metrics": ["ajaxRequests", "synchronousXHR"]
177
+ "metrics": [
178
+ "ajaxRequests",
179
+ "synchronousXHR"
180
+ ]
164
181
  },
165
182
  "alerts": {
166
183
  "file": "/modules/alerts/alerts.js",
167
184
  "desc": "Meters number of invocations of window.alert, window.confirm, and\nwindow.prompt.",
168
185
  "events": [],
169
- "metrics": ["windowAlerts", "windowConfirms", "windowPrompts"]
186
+ "metrics": [
187
+ "windowAlerts",
188
+ "windowConfirms",
189
+ "windowPrompts"
190
+ ]
170
191
  },
171
192
  "analyzeCss": {
172
193
  "file": "/modules/analyzeCss/analyzeCss.js",
@@ -241,13 +262,19 @@
241
262
  "file": "/modules/blockDomains/blockDomains.js",
242
263
  "desc": "Aborts requests to external resources or given domains\nDoes not emit any metrics",
243
264
  "events": [],
244
- "metrics": ["blockedRequests"]
265
+ "metrics": [
266
+ "blockedRequests"
267
+ ]
245
268
  },
246
269
  "cacheHits": {
247
270
  "file": "/modules/cacheHits/cacheHits.js",
248
271
  "desc": "Analyzes Age and X-Cache headers from caching servers like Squid or Varnish",
249
272
  "events": [],
250
- "metrics": ["cacheHits", "cacheMisses", "cachePasses"]
273
+ "metrics": [
274
+ "cacheHits",
275
+ "cacheMisses",
276
+ "cachePasses"
277
+ ]
251
278
  },
252
279
  "caching": {
253
280
  "file": "/modules/caching/caching.js",
@@ -265,7 +292,9 @@
265
292
  "file": "/modules/console/console.js",
266
293
  "desc": "Meters number of console logs",
267
294
  "events": [],
268
- "metrics": ["consoleMessages"]
295
+ "metrics": [
296
+ "consoleMessages"
297
+ ]
269
298
  },
270
299
  "cookies": {
271
300
  "file": "/modules/cookies/cookies.js",
@@ -279,17 +308,36 @@
279
308
  "documentCookiesCount"
280
309
  ]
281
310
  },
311
+ "cpuTasks": {
312
+ "file": "/modules/cpuTasks/cpuTasks.js",
313
+ "desc": "",
314
+ "events": [],
315
+ "metrics": [
316
+ "layoutCount",
317
+ "layoutDuration",
318
+ "recalcStyleCount",
319
+ "recalcStyleDuration",
320
+ "scriptDuration",
321
+ "taskDuration"
322
+ ]
323
+ },
282
324
  "documentHeight": {
283
325
  "file": "/modules/documentHeight/documentHeight.js",
284
326
  "desc": "Measure document height",
285
327
  "events": [],
286
- "metrics": ["documentHeight"]
328
+ "metrics": [
329
+ "documentHeight"
330
+ ]
287
331
  },
288
332
  "domains": {
289
333
  "file": "/modules/domains/domains.js",
290
334
  "desc": "Domains monitor",
291
335
  "events": [],
292
- "metrics": ["domains", "maxRequestsPerDomain", "medianRequestsPerDomain"]
336
+ "metrics": [
337
+ "domains",
338
+ "maxRequestsPerDomain",
339
+ "medianRequestsPerDomain"
340
+ ]
293
341
  },
294
342
  "domComplexity": {
295
343
  "file": "/modules/domComplexity/domComplexity.js",
@@ -312,7 +360,10 @@
312
360
  "file": "/modules/domHiddenContent/domHiddenContent.js",
313
361
  "desc": "Analyzes DOM hidden content",
314
362
  "events": [],
315
- "metrics": ["hiddenContentSize", "hiddenImages"]
363
+ "metrics": [
364
+ "hiddenContentSize",
365
+ "hiddenImages"
366
+ ]
316
367
  },
317
368
  "domMutations": {
318
369
  "file": "/modules/domMutations/domMutations.js",
@@ -344,13 +395,20 @@
344
395
  "file": "/modules/events/events.js",
345
396
  "desc": "Analyzes events bound to DOM elements",
346
397
  "events": [],
347
- "metrics": ["eventsBound", "eventsDispatched", "eventsScrollBound"]
398
+ "metrics": [
399
+ "eventsBound",
400
+ "eventsDispatched",
401
+ "eventsScrollBound"
402
+ ]
348
403
  },
349
404
  "globalVariables": {
350
405
  "file": "/modules/globalVariables/globalVariables.js",
351
406
  "desc": "Counts global JavaScript variables",
352
407
  "events": [],
353
- "metrics": ["globalVariables", "globalVariablesFalsy"]
408
+ "metrics": [
409
+ "globalVariables",
410
+ "globalVariablesFalsy"
411
+ ]
354
412
  },
355
413
  "headers": {
356
414
  "file": "/modules/headers/headers.js",
@@ -368,9 +426,12 @@
368
426
  },
369
427
  "javaScriptBottlenecks": {
370
428
  "file": "/modules/javaScriptBottlenecks/javaScriptBottlenecks.js",
371
- "desc": "Reports the use of functions known to be serious performance bottlenecks in JS\n\nRun phantomas with --spy-eval to count eval() calls (see issue #467)",
429
+ "desc": "Reports the use of functions known to be serious performance bottlenecks in JS\nRun phantomas with --spy-eval to count eval() calls (see issue #467)",
372
430
  "events": [],
373
- "metrics": ["documentWriteCalls", "evalCalls"]
431
+ "metrics": [
432
+ "documentWriteCalls",
433
+ "evalCalls"
434
+ ]
374
435
  },
375
436
  "jQuery": {
376
437
  "file": "/modules/jQuery/jQuery.js",
@@ -392,37 +453,61 @@
392
453
  "file": "/modules/jserrors/jserrors.js",
393
454
  "desc": "Meters the number of page errors, and provides traces as offenders for \"jsErrors\" metric",
394
455
  "events": [],
395
- "metrics": ["jsErrors"]
456
+ "metrics": [
457
+ "jsErrors"
458
+ ]
396
459
  },
397
460
  "keepAlive": {
398
461
  "file": "/modules/keepAlive/keepAlive.js",
399
462
  "desc": "Analyzes if HTTP responses keep the connections alive.",
400
463
  "events": [],
401
- "metrics": ["closedConnections"]
464
+ "metrics": [
465
+ "closedConnections"
466
+ ]
402
467
  },
403
468
  "lazyLoadableImages": {
404
469
  "file": "/modules/lazyLoadableImages/lazyLoadableImages.js",
405
470
  "desc": "Analyzes images and detects which one can be lazy-loaded (are below the fold)",
406
471
  "events": [],
407
- "metrics": ["lazyLoadableImagesBelowTheFold"]
472
+ "metrics": [
473
+ "lazyLoadableImagesBelowTheFold"
474
+ ]
408
475
  },
409
476
  "localStorage": {
410
477
  "file": "/modules/localStorage/localStorage.js",
411
478
  "desc": "localStorage metrics",
412
479
  "events": [],
413
- "metrics": ["localStorageEntries"]
480
+ "metrics": [
481
+ "localStorageEntries"
482
+ ]
414
483
  },
415
484
  "mainRequest": {
416
485
  "file": "/modules/mainRequest/mainRequest.js",
417
486
  "desc": "Analyzes bits of data pertaining to the main request only",
418
487
  "events": [],
419
- "metrics": ["statusCodesTrail"]
488
+ "metrics": [
489
+ "statusCodesTrail"
490
+ ]
491
+ },
492
+ "protocols": {
493
+ "file": "/modules/protocols/protocols.js",
494
+ "desc": "Checks versions of HTTP and TLS protocols",
495
+ "events": [],
496
+ "metrics": [
497
+ "mainDomainHttpProtocol",
498
+ "oldHttpProtocol",
499
+ "mainDomainTlsProtocol",
500
+ "oldTlsProtocol"
501
+ ]
420
502
  },
421
503
  "redirects": {
422
504
  "file": "/modules/redirects/redirects.js",
423
505
  "desc": "Analyzes HTTP redirects",
424
506
  "events": [],
425
- "metrics": ["redirects", "redirectsTime"]
507
+ "metrics": [
508
+ "redirects",
509
+ "redirectsTime"
510
+ ]
426
511
  },
427
512
  "requestsStats": {
428
513
  "file": "/modules/requestsStats/requestsStats.js",
@@ -470,7 +555,11 @@
470
555
  "file": "/modules/timeToFirst/timeToFirst.js",
471
556
  "desc": "Provides metrics for time to first image, CSS and JS file",
472
557
  "events": [],
473
- "metrics": ["timeToFirstCss", "timeToFirstJs", "timeToFirstImage"]
558
+ "metrics": [
559
+ "timeToFirstCss",
560
+ "timeToFirstJs",
561
+ "timeToFirstImage"
562
+ ]
474
563
  },
475
564
  "windowPerformance": {
476
565
  "file": "/modules/windowPerformance/windowPerformance.js",
@@ -987,7 +1076,7 @@
987
1076
  "offenders": true,
988
1077
  "unit": "number",
989
1078
  "module": "assetsTypes",
990
- "testsCovered": true
1079
+ "testsCovered": false
991
1080
  },
992
1081
  "otherSize": {
993
1082
  "desc": "size of other responses (with compression)",
@@ -1098,6 +1187,42 @@
1098
1187
  "module": "cookies",
1099
1188
  "testsCovered": false
1100
1189
  },
1190
+ "layoutCount": {
1191
+ "desc": "total number of full or partial page layout",
1192
+ "unit": "number",
1193
+ "module": "cpuTasks",
1194
+ "testsCovered": false
1195
+ },
1196
+ "layoutDuration": {
1197
+ "desc": "combined durations of all page layouts",
1198
+ "unit": "ms",
1199
+ "module": "cpuTasks",
1200
+ "testsCovered": false
1201
+ },
1202
+ "recalcStyleCount": {
1203
+ "desc": "total number of page style recalculations",
1204
+ "unit": "number",
1205
+ "module": "cpuTasks",
1206
+ "testsCovered": false
1207
+ },
1208
+ "recalcStyleDuration": {
1209
+ "desc": "combined duration of all page style recalculations",
1210
+ "unit": "ms",
1211
+ "module": "cpuTasks",
1212
+ "testsCovered": false
1213
+ },
1214
+ "scriptDuration": {
1215
+ "desc": "combined duration of JavaScript execution",
1216
+ "unit": "ms",
1217
+ "module": "cpuTasks",
1218
+ "testsCovered": false
1219
+ },
1220
+ "taskDuration": {
1221
+ "desc": "combined duration of all tasks performed by the browser",
1222
+ "unit": "ms",
1223
+ "module": "cpuTasks",
1224
+ "testsCovered": false
1225
+ },
1101
1226
  "documentHeight": {
1102
1227
  "desc": "the page height",
1103
1228
  "unit": "px",
@@ -1475,6 +1600,32 @@
1475
1600
  "module": "mainRequest",
1476
1601
  "testsCovered": false
1477
1602
  },
1603
+ "mainDomainHttpProtocol": {
1604
+ "desc": "HTTP protocol used by the main domain",
1605
+ "unit": "string",
1606
+ "module": "protocols",
1607
+ "testsCovered": true
1608
+ },
1609
+ "oldHttpProtocol": {
1610
+ "desc": "number of domains using HTTP/1.0 or 1.1",
1611
+ "offenders": true,
1612
+ "unit": "number",
1613
+ "module": "protocols",
1614
+ "testsCovered": true
1615
+ },
1616
+ "mainDomainTlsProtocol": {
1617
+ "desc": "TLS protocol used by the main domain",
1618
+ "unit": "string",
1619
+ "module": "protocols",
1620
+ "testsCovered": true
1621
+ },
1622
+ "oldTlsProtocol": {
1623
+ "desc": "number of domains using TLS 1.1 or 1.2",
1624
+ "offenders": true,
1625
+ "unit": "number",
1626
+ "module": "protocols",
1627
+ "testsCovered": true
1628
+ },
1478
1629
  "redirects": {
1479
1630
  "desc": "number of HTTP redirects (either 301, 302 or 303)",
1480
1631
  "offenders": true,
@@ -1688,7 +1839,7 @@
1688
1839
  "desc": "time it took to resolve the domain before making the first HTTP request",
1689
1840
  "unit": "ms",
1690
1841
  "module": "windowPerformance",
1691
- "testsCovered": true
1842
+ "testsCovered": false
1692
1843
  },
1693
1844
  "performanceTimingPageLoad": {
1694
1845
  "desc": "time it took to fully load the page",
@@ -1715,8 +1866,8 @@
1715
1866
  "testsCovered": false
1716
1867
  }
1717
1868
  },
1718
- "metricsCount": 177,
1719
- "modulesCount": 34,
1720
- "extensionsCount": 11,
1721
- "version": "2.0.0-beta"
1722
- }
1869
+ "metricsCount": 187,
1870
+ "modulesCount": 36,
1871
+ "extensionsCount": 12,
1872
+ "version": "2.0.0"
1873
+ }
@@ -1,4 +1,4 @@
1
- (function (phantomas) {
1
+ (function ajaxRequestsScope(phantomas) {
2
2
  phantomas.spy(
3
3
  window.XMLHttpRequest.prototype,
4
4
  "open",