browsertime 14.21.1 → 15.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.
@@ -18,6 +18,30 @@ function generateUniquePageId(baseId, existingIdMap) {
18
18
  return newId;
19
19
  }
20
20
 
21
+ function getDocumentRequests(entries, pageId) {
22
+ let pageEntries = Array.from(entries);
23
+ if (pageId) {
24
+ pageEntries = Array.from(entries.filter(entry => entry.pageref === pageId));
25
+ }
26
+
27
+ const requests = [];
28
+ let entry;
29
+
30
+ do {
31
+ entry = pageEntries.shift();
32
+ requests.push(entry);
33
+ } while (entry.response.redirectURL);
34
+
35
+ return requests;
36
+ }
37
+
38
+ function getFinalURL(entries, pageref) {
39
+ const requests = getDocumentRequests(entries, pageref);
40
+
41
+ const finalEntry = requests.pop();
42
+ return finalEntry.request.url;
43
+ }
44
+
21
45
  function addExtrasToHAR(
22
46
  harPage,
23
47
  visualMetricsData,
@@ -160,6 +184,27 @@ module.exports = {
160
184
  return har;
161
185
  },
162
186
 
187
+ getMainDocumentTimings: function (har) {
188
+ const timings = [];
189
+ const entries = Array.from(har.log.entries);
190
+
191
+ for (let page of har.log.pages) {
192
+ const pageId = page.id;
193
+ const url = page._url;
194
+
195
+ let pageEntries = Array.from(entries);
196
+ const finalURL = getFinalURL(pageEntries, pageId);
197
+
198
+ pageEntries = Array.from(
199
+ pageEntries.filter(
200
+ entry => entry.pageref === pageId && entry.request.url === finalURL
201
+ )
202
+ );
203
+
204
+ timings.push({ url, timings: pageEntries[0].timings });
205
+ }
206
+ return timings;
207
+ },
163
208
  getFullyLoaded: function (har) {
164
209
  const fullyLoaded = [];
165
210
  const entries = Array.from(har.log.entries);
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "description": "Browsertime",
3
- "version": "14.21.1",
3
+ "version": "15.1.0",
4
4
  "bin": "./bin/browsertime.js",
5
5
  "dependencies": {
6
- "@sitespeed.io/throttle": "3.0.0",
6
+ "@cypress/xvfb": "1.2.4",
7
7
  "@devicefarmer/adbkit": "2.11.3",
8
- "btoa": "1.2.1",
9
8
  "@sitespeed.io/chromedriver": "98.0.4758-48b",
9
+ "@sitespeed.io/edgedriver": "98.0.1108-43",
10
+ "@sitespeed.io/geckodriver": "0.30.0",
11
+ "@sitespeed.io/throttle": "3.0.0",
12
+ "@sitespeed.io/tracium": "0.3.3",
13
+ "btoa": "1.2.1",
10
14
  "chrome-har": "0.12.0",
11
15
  "chrome-remote-interface": "0.31.0",
12
16
  "dayjs": "1.10.7",
@@ -22,27 +26,20 @@
22
26
  "lodash.merge": "4.6.2",
23
27
  "lodash.pick": "4.4.0",
24
28
  "lodash.set": "4.3.2",
25
- "selenium-webdriver": "4.1.0",
26
- "@sitespeed.io/edgedriver": "98.0.1108-43",
27
- "@sitespeed.io/geckodriver": "0.30.0",
28
- "@sitespeed.io/tracium": "0.3.3",
29
- "speedline-core": "1.4.3",
30
- "@cypress/xvfb": "1.2.4",
29
+ "selenium-webdriver": "4.1.1",
31
30
  "yargs": "17.2.1"
32
31
  },
33
32
  "optionalDependencies": {
34
33
  "jimp": "0.16.1"
35
34
  },
36
35
  "devDependencies": {
37
- "bluebird": "3.7.2",
38
- "chai": "4.3.4",
39
- "chai-as-promised": "7.1.1",
36
+ "ava": "4.0.1",
40
37
  "eslint": "8.0.1",
41
38
  "eslint-config-prettier": "8.3.0",
42
39
  "eslint-plugin-prettier": "4.0.0",
43
- "longjohn": "0.2.12",
44
- "mocha": "6.2.0",
45
- "prettier": "2.4.1"
40
+ "prettier": "2.4.1",
41
+ "serve-handler": "6.1.3",
42
+ "serve": "13.0.2"
46
43
  },
47
44
  "engines": {
48
45
  "node": ">=10.13.0"
@@ -65,21 +62,17 @@
65
62
  ],
66
63
  "main": "index.js",
67
64
  "scripts": {
68
- "test": "mocha test/unitTests && mocha test/browserTests && mocha test/commandTests",
69
- "test:unit": "mocha test/unitTests",
70
- "test:browser": "mocha test/browserTests",
71
- "test:selenium": "mocha test/browserTests/seleniumRunnerTests.js",
72
- "test:commands": "mocha test/commandTests",
65
+ "test": "ava",
66
+ "start-server": "serve test/data/html/",
67
+ "stop-server": "sudo pkill serve",
73
68
  "lint": "eslint .",
74
- "lint:fix": "eslint . --fix",
75
- "eslint-check": "eslint --print-config .eslintrc.json | eslint-config-prettier-check",
76
- "travis": "npm run eslint-check && npm run lint && npm run test"
69
+ "lint:fix": "eslint . --fix"
77
70
  },
78
71
  "name": "browsertime",
79
- "author": "Tobias Lidskog",
72
+ "author": "Peter Hedenskog",
80
73
  "contributors": [
81
74
  {
82
- "name": "Peter Hedenskog"
75
+ "name": "Tobias Lidskog"
83
76
  },
84
77
  {
85
78
  "name": "Jonathan Lee"
@@ -90,5 +83,20 @@
90
83
  "url": "https://github.com/sitespeedio/browsertime.git"
91
84
  },
92
85
  "homepage": "https://www.sitespeed.io/documentation/browsertime/",
93
- "license": "MIT"
86
+ "license": "MIT",
87
+ "ava": {
88
+ "files": [
89
+ "test/**/*",
90
+ "!test/util",
91
+ "!test/data"
92
+ ],
93
+ "concurrency": 1,
94
+ "failFast": true,
95
+ "require": [
96
+ "./test/util/setup.js"
97
+ ],
98
+ "nodeArguments": [
99
+ "--trace-deprecation"
100
+ ]
101
+ }
94
102
  }
@@ -1,9 +0,0 @@
1
- module.exports = {
2
- requires: { privilege: true },
3
- function: function() {
4
- const { AppConstants } = ChromeUtils.import(
5
- 'resource://gre/modules/AppConstants.jsm'
6
- );
7
- return AppConstants;
8
- }
9
- };
@@ -1,11 +0,0 @@
1
- module.exports = {
2
- requires: { privilege: true },
3
- function: async function() {
4
- return new Promise(resolve => {
5
- const { AppConstants } = ChromeUtils.import(
6
- 'resource://gre/modules/AppConstants.jsm'
7
- );
8
- resolve(AppConstants);
9
- });
10
- }
11
- };
@@ -1,84 +0,0 @@
1
- 'use strict';
2
-
3
- const speedline = require('speedline-core');
4
- const log = require('intel').getLogger('browsertime.chrome');
5
- const visualMetricsExtra = require('../video/postprocessing/visualmetrics/extraMetrics');
6
- const path = require('path');
7
- const images = require('../support/images');
8
-
9
- function pad(n) {
10
- const extraZeroes = 6 - n.toString().length;
11
- for (let i = 0; i < extraZeroes; i++) {
12
- n = '0' + n;
13
- }
14
- return n;
15
- }
16
-
17
- /**
18
- * Use SpeedLine to analyse the Chrome trace log to get Visual Metrics.
19
- * Not as good as using a video but maybe usable in some cases.
20
- */
21
- module.exports = async function (trace, result, index) {
22
- try {
23
- const navStart = trace.traceEvents.filter(
24
- task =>
25
- task.cat === 'blink.user_timing' && task.name === 'navigationStart'
26
- );
27
- navStart.sort(function (a, b) {
28
- return a.ts - b.ts;
29
- });
30
- log.debug('Get Speedline result from the trace');
31
- const speedlineResult = await speedline(trace.traceEvents, {
32
- timeOrigin: navStart[0].ts,
33
- fastMode: true
34
- });
35
- log.debug('Got Speedline result.');
36
- const startTs = speedlineResult.beginning;
37
- const visualProgress = speedlineResult.frames
38
- .map(frame => {
39
- const ts = Math.floor(frame.getTimeStamp() - startTs);
40
- return `${ts}=${Math.floor(frame.getProgress())}%`;
41
- })
42
- .join(', ');
43
-
44
- const visualMetrics = visualMetricsExtra({
45
- FirstVisualChange: Number(speedlineResult.first.toFixed(0)),
46
- LastVisualChange: Number(speedlineResult.complete.toFixed(0)),
47
- SpeedIndex: Number(speedlineResult.speedIndex.toFixed(0)),
48
- PerceptualSpeedIndex: Number(
49
- speedlineResult.perceptualSpeedIndex.toFixed(0)
50
- ),
51
- VisualProgress: visualProgress
52
- }).visualMetrics;
53
-
54
- const promises = [];
55
- for (let frame of speedlineResult.frames) {
56
- // follow the name standard of Visual Metrics
57
- // ms_000000.jpg
58
- const d = new Date(frame.getTimeStamp() - startTs);
59
- const name = 'ms_' + pad(d.getTime());
60
- promises.push(
61
- images.saveJpg(
62
- name,
63
- frame.getImage(),
64
- result.url,
65
- this.storageManager,
66
- {
67
- type: 'jpg',
68
- jpg: {
69
- quality: 80
70
- },
71
- maxSize: 400
72
- },
73
- path.join('filmstrip', index + ''),
74
- this.options
75
- )
76
- );
77
- }
78
-
79
- await Promise.all(promises);
80
- return visualMetrics;
81
- } catch (e) {
82
- log.error('Could not generate Visual Metrics using SpeedLine', e);
83
- }
84
- };
@@ -1,108 +0,0 @@
1
- 'use strict';
2
-
3
- const execa = require('execa');
4
- const path = require('path');
5
- const get = require('lodash.get');
6
- const log = require('intel').getLogger('browsertime.connectivity.tsproxy');
7
-
8
- const TS_PROXY_SCRIPT_PATH = path.join(
9
- __dirname,
10
- '..',
11
- '..',
12
- 'vendor',
13
- 'tsproxy.py'
14
- );
15
-
16
- function getStartupCriteriaListener(resolve, reject) {
17
- return function (data) {
18
- const logLine = data.toString();
19
- if (logLine.startsWith('Started Socks5 proxy server on')) {
20
- log.debug('Started TSproxy');
21
- return resolve();
22
- } else if (logLine.startsWith('Unable to listen on')) {
23
- return reject(new Error('TSProxy process logged: ' + logLine));
24
- }
25
- };
26
- }
27
-
28
- class TSProxy {
29
- constructor(options) {
30
- this.logVerbose = options.verbose >= 2;
31
- this.port = get(options.connectivity, 'tsproxy.port', 1080);
32
- this.bind = get(options.connectivity, 'tsproxy.bind');
33
- this.options = options;
34
- }
35
-
36
- start(profile) {
37
- const scriptArgs = [
38
- TS_PROXY_SCRIPT_PATH,
39
- '--rtt',
40
- profile.rtt,
41
- '--inkbps',
42
- profile.down,
43
- '--outkbps',
44
- profile.up
45
- ];
46
-
47
- if (this.bind) {
48
- scriptArgs.push('--bind', this.bind);
49
- }
50
-
51
- if (isFinite(this.port)) {
52
- scriptArgs.push('-p', this.port);
53
- }
54
-
55
- if (this.logVerbose) {
56
- scriptArgs.push('-vvvv');
57
- }
58
-
59
- log.info('Start TSProxy:' + scriptArgs.join(' '));
60
- this.tsProxyProcess = execa(
61
- this.options.docker ? 'python2' : 'python',
62
- scriptArgs
63
- );
64
-
65
- const tsProxyProcess = this.tsProxyProcess;
66
-
67
- if (this.logVerbose) {
68
- tsProxyProcess.stderr.on('data', function (data) {
69
- log.verbose(data.toString().trim());
70
- });
71
- }
72
-
73
- return new Promise(function (resolve, reject) {
74
- tsProxyProcess.stdout.on(
75
- 'data',
76
- getStartupCriteriaListener(resolve, reject)
77
- );
78
- });
79
- }
80
-
81
- stop() {
82
- if (this.tsProxyProcess) {
83
- this.tsProxyProcess.stdout.removeAllListeners('data');
84
- this.tsProxyProcess.stderr.removeAllListeners('data');
85
-
86
- return new Promise((resolve, reject) => {
87
- this.tsProxyProcess
88
- .once('exit', () => {
89
- // guard against exit event sent after error event,
90
- // see https://nodejs.org/api/child_process.html#child_process_event_error
91
- if (this.tsProxyProcess) {
92
- this.tsProxyProcess = null;
93
- log.debug('Closing TSproxy');
94
- resolve();
95
- }
96
- })
97
- .once('error', err => {
98
- this.tsProxyProcess = null;
99
- reject(err);
100
- });
101
- this.tsProxyProcess.kill('SIGINT');
102
- });
103
- }
104
- return Promise.resolve();
105
- }
106
- }
107
-
108
- module.exports = TSProxy;