browsertime 15.2.0 → 16.0.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.
- package/CHANGELOG.md +21 -0
- package/browsertime/visualmetrics-portable.py +2767 -0
- package/docs/examples/firefox.md +3 -1
- package/lib/chrome/webdriver/chromium.js +23 -1
- package/lib/core/engine/iteration.js +1 -1
- package/lib/support/cli.js +18 -1
- package/lib/support/dns.js +2 -2
- package/lib/support/fileUtil.js +4 -0
- package/lib/video/postprocessing/visualmetrics/visualMetrics.js +32 -5
- package/package.json +3 -3
package/docs/examples/firefox.md
CHANGED
|
@@ -3,6 +3,8 @@ Firefox Examples
|
|
|
3
3
|
|
|
4
4
|
This page shows a few of the options specific to Firefox.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
```
|
|
7
|
+
browsertime https://www.sitespeed.io -b firefox --firefox.binaryPath '/Applications/Firefox.app/Contents/MacOS/firefox-bin'
|
|
8
|
+
```
|
|
7
9
|
|
|
8
10
|
- Path to custom Firefox binary (e.g. Firefox Nightly). On OS X, the path should be to the binary inside the app bundle. (e.g. /Applications/Firefox.app/Contents/MacOS/firefox-bin)
|
|
@@ -9,12 +9,14 @@ const path = require('path');
|
|
|
9
9
|
const parseCpuTrace = require('../parseCpuTrace');
|
|
10
10
|
const har = require('../har');
|
|
11
11
|
const harBuilder = require('../../support/har');
|
|
12
|
+
const util = require('../../support/util');
|
|
12
13
|
const webdriver = require('selenium-webdriver');
|
|
13
14
|
const traceCategoriesParser = require('../traceCategoriesParser');
|
|
14
15
|
const pathToFolder = require('../../support/pathToFolder');
|
|
15
16
|
const ChromeDevtoolsProtocol = require('../chromeDevtoolsProtocol');
|
|
16
17
|
const { Android } = require('../../android');
|
|
17
18
|
const unlink = promisify(fs.unlink);
|
|
19
|
+
const rm = promisify(fs.rm);
|
|
18
20
|
|
|
19
21
|
class Chromium {
|
|
20
22
|
constructor(storageManager, options) {
|
|
@@ -408,7 +410,27 @@ class Chromium {
|
|
|
408
410
|
/**
|
|
409
411
|
* Before the browser is stopped/closed.
|
|
410
412
|
*/
|
|
411
|
-
async afterBrowserStopped() {
|
|
413
|
+
async afterBrowserStopped() {
|
|
414
|
+
// If we supply a user data dir on desktop, we want to clean up before each start
|
|
415
|
+
if (
|
|
416
|
+
this.chrome.args &&
|
|
417
|
+
this.chrome.cleanUserDataDir &&
|
|
418
|
+
!this.chrome.android
|
|
419
|
+
) {
|
|
420
|
+
const args = util.toArray(this.chrome.args);
|
|
421
|
+
for (let arg of args) {
|
|
422
|
+
if (arg.includes('user-data-dir')) {
|
|
423
|
+
const userDataDir = arg.split('=')[1];
|
|
424
|
+
try {
|
|
425
|
+
await rm(userDataDir, { recursive: true });
|
|
426
|
+
log.info(`Deleted user data dir: ${userDataDir}`);
|
|
427
|
+
} catch (e) {
|
|
428
|
+
log.error(`Could not delete user data dir: ${userDataDir}`, e);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
412
434
|
|
|
413
435
|
async getHARs() {
|
|
414
436
|
if (!this.skipHar) {
|
|
@@ -102,7 +102,7 @@ class Iteration {
|
|
|
102
102
|
const engineDelegate = this.engineDelegate;
|
|
103
103
|
|
|
104
104
|
try {
|
|
105
|
-
if (
|
|
105
|
+
if (options.flushDNS) {
|
|
106
106
|
await flushDNS(options);
|
|
107
107
|
}
|
|
108
108
|
if (options.connectivity && options.connectivity.variance) {
|
package/lib/support/cli.js
CHANGED
|
@@ -287,6 +287,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
287
287
|
'Prevent Browsertime from setting its default options for Chrome',
|
|
288
288
|
group: 'chrome'
|
|
289
289
|
})
|
|
290
|
+
.option('chrome.cleanUserDataDir', {
|
|
291
|
+
type: 'boolean',
|
|
292
|
+
describe:
|
|
293
|
+
'If you use --user-data-dir as an argument to Chrome and want to clean that directory between each iteration you should use --chrome.cleanUserDataDir true.',
|
|
294
|
+
group: 'chrome'
|
|
295
|
+
})
|
|
290
296
|
.option('cpu', {
|
|
291
297
|
type: 'boolean',
|
|
292
298
|
describe:
|
|
@@ -634,6 +640,11 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
634
640
|
type: 'boolean',
|
|
635
641
|
describe: 'Collect Contentful Speed Index when you run --visualMetrics.'
|
|
636
642
|
})
|
|
643
|
+
.option('visualMetricsPortable', {
|
|
644
|
+
type: 'boolean',
|
|
645
|
+
describe:
|
|
646
|
+
'Use the portable visual-metrics processing script (no ImageMagick dependencies).'
|
|
647
|
+
})
|
|
637
648
|
.option('scriptInput.visualElements', {
|
|
638
649
|
describe:
|
|
639
650
|
'Include specific elements in visual elements. Give the element a name and select it with document.body.querySelector. Use like this: --scriptInput.visualElements name:domSelector see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors. Add multiple instances to measure multiple elements. Visual Metrics will use these elements and calculate when they are visible and fully rendered.'
|
|
@@ -964,7 +975,7 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
964
975
|
})
|
|
965
976
|
.option('block', {
|
|
966
977
|
describe:
|
|
967
|
-
'Domain to block
|
|
978
|
+
'Domain to block or URL or URL pattern to block. If you use Chrome you can also use --blockDomainsExcept (that is more performant). Works in Chrome/Edge. For Firefox you can only block domains.'
|
|
968
979
|
})
|
|
969
980
|
.option('percentiles', {
|
|
970
981
|
type: 'array',
|
|
@@ -1106,6 +1117,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1106
1117
|
describe:
|
|
1107
1118
|
'Start gnirehtet and reverse tethering the traffic from your Android phone.'
|
|
1108
1119
|
})
|
|
1120
|
+
.option('flushDNS', {
|
|
1121
|
+
type: 'boolean',
|
|
1122
|
+
default: false,
|
|
1123
|
+
describe:
|
|
1124
|
+
'Flush DNS between runs, works on Mac OS and Linux. Your user needs sudo rights to be able to flush the DNS.'
|
|
1125
|
+
})
|
|
1109
1126
|
.option('extension', {
|
|
1110
1127
|
describe:
|
|
1111
1128
|
'Path to a WebExtension to be installed in the browser. Note that --extension can be passed multiple times.'
|
package/lib/support/dns.js
CHANGED
|
@@ -14,7 +14,7 @@ module.exports = async function (options) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
if (process.platform === 'darwin') {
|
|
17
|
-
log.
|
|
17
|
+
log.info('Flush DNS cache on MacOS');
|
|
18
18
|
await execa('sudo', ['killall', '-HUP', 'mDNSResponder'], {
|
|
19
19
|
reject: false
|
|
20
20
|
});
|
|
@@ -25,7 +25,7 @@ module.exports = async function (options) {
|
|
|
25
25
|
reject: false
|
|
26
26
|
});
|
|
27
27
|
} else if (process.platform === 'linux') {
|
|
28
|
-
log.
|
|
28
|
+
log.info('Flush DNS cache on Linux');
|
|
29
29
|
await execa('sudo', ['systemd-resolve', '--flush-caches'], {
|
|
30
30
|
reject: false
|
|
31
31
|
});
|
package/lib/support/fileUtil.js
CHANGED
|
@@ -6,6 +6,7 @@ const readdir = promisify(fs.readdir);
|
|
|
6
6
|
const lstat = promisify(fs.lstat);
|
|
7
7
|
const unlink = promisify(fs.unlink);
|
|
8
8
|
const rmdir = promisify(fs.rmdir);
|
|
9
|
+
const copyFile = promisify(fs.copyFile);
|
|
9
10
|
const rename = promisify(fs.rename);
|
|
10
11
|
const readFile = promisify(fs.readFile);
|
|
11
12
|
const filters = require('./filters');
|
|
@@ -15,6 +16,9 @@ module.exports = {
|
|
|
15
16
|
async rename(old, newName) {
|
|
16
17
|
return rename(old, newName);
|
|
17
18
|
},
|
|
19
|
+
async copyFile(source, destination) {
|
|
20
|
+
return copyFile(source, destination);
|
|
21
|
+
},
|
|
18
22
|
async removeFile(fileName) {
|
|
19
23
|
return unlink(fileName);
|
|
20
24
|
},
|
|
@@ -4,7 +4,7 @@ const execa = require('execa');
|
|
|
4
4
|
const log = require('intel').getLogger('browsertime.video');
|
|
5
5
|
const get = require('lodash.get');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const { readFile, removeFile } = require('../../../support/fileUtil');
|
|
7
|
+
const { readFile, removeFile, copyFile } = require('../../../support/fileUtil');
|
|
8
8
|
|
|
9
9
|
const SCRIPT_PATH = path.join(
|
|
10
10
|
__dirname,
|
|
@@ -16,9 +16,29 @@ const SCRIPT_PATH = path.join(
|
|
|
16
16
|
'visualmetrics.py'
|
|
17
17
|
);
|
|
18
18
|
|
|
19
|
+
const PORTABLE_SCRIPT_PATH = path.join(
|
|
20
|
+
__dirname,
|
|
21
|
+
'..',
|
|
22
|
+
'..',
|
|
23
|
+
'..',
|
|
24
|
+
'..',
|
|
25
|
+
'browsertime',
|
|
26
|
+
'visualmetrics-portable.py'
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
function getScript(options) {
|
|
30
|
+
if (options.visualMetricsPortable) {
|
|
31
|
+
return PORTABLE_SCRIPT_PATH;
|
|
32
|
+
}
|
|
33
|
+
return SCRIPT_PATH;
|
|
34
|
+
}
|
|
35
|
+
|
|
19
36
|
module.exports = {
|
|
20
|
-
async checkDependencies() {
|
|
21
|
-
return execa(process.env.PYTHON || 'python', [
|
|
37
|
+
async checkDependencies(options) {
|
|
38
|
+
return execa(process.env.PYTHON || 'python', [
|
|
39
|
+
getScript(options),
|
|
40
|
+
'--check'
|
|
41
|
+
]);
|
|
22
42
|
},
|
|
23
43
|
async run(
|
|
24
44
|
videoPath,
|
|
@@ -46,7 +66,13 @@ module.exports = {
|
|
|
46
66
|
'--renderignore',
|
|
47
67
|
5,
|
|
48
68
|
'--json',
|
|
49
|
-
'--viewport'
|
|
69
|
+
'--viewport',
|
|
70
|
+
'--viewportretries',
|
|
71
|
+
60,
|
|
72
|
+
'--viewportminheight',
|
|
73
|
+
100,
|
|
74
|
+
'--viewportminwidth',
|
|
75
|
+
100
|
|
50
76
|
];
|
|
51
77
|
|
|
52
78
|
if (options.visualMetricsPerceptual) {
|
|
@@ -103,7 +129,7 @@ module.exports = {
|
|
|
103
129
|
scriptArgs.push('-vvv');
|
|
104
130
|
}
|
|
105
131
|
|
|
106
|
-
scriptArgs.unshift(
|
|
132
|
+
scriptArgs.unshift(getScript(options));
|
|
107
133
|
|
|
108
134
|
log.debug('Running visualmetrics.py ' + scriptArgs.join(' '));
|
|
109
135
|
log.info('Get visual metrics from the video');
|
|
@@ -123,6 +149,7 @@ module.exports = {
|
|
|
123
149
|
return JSON.parse(result.stdout);
|
|
124
150
|
} catch (e) {
|
|
125
151
|
log.error('VisualMetrics failed to run', e);
|
|
152
|
+
await copyFile(videoPath, videoPath + '.failed.mp4');
|
|
126
153
|
// If something goes wrong, dump the visual metrics log to our log
|
|
127
154
|
const visualMetricLog = await readFile(visualMetricsLogFile);
|
|
128
155
|
log.error('Log from VisualMetrics: %s', visualMetricLog);
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"description": "Browsertime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0",
|
|
4
4
|
"bin": "./bin/browsertime.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@cypress/xvfb": "1.2.4",
|
|
7
7
|
"@devicefarmer/adbkit": "2.11.3",
|
|
8
|
-
"@sitespeed.io/chromedriver": "
|
|
9
|
-
"@sitespeed.io/edgedriver": "
|
|
8
|
+
"@sitespeed.io/chromedriver": "100.0.4896-20",
|
|
9
|
+
"@sitespeed.io/edgedriver": "100.0.1185-29",
|
|
10
10
|
"@sitespeed.io/geckodriver": "0.30.0",
|
|
11
11
|
"@sitespeed.io/throttle": "3.0.0",
|
|
12
12
|
"@sitespeed.io/tracium": "0.3.3",
|