browsertime 14.4.0 → 14.7.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 +29 -1
- package/bin/browsertime.js +1 -1
- package/lib/android/index.js +1 -1
- package/lib/chrome/har.js +4 -4
- package/lib/chrome/longTaskMetrics.js +1 -1
- package/lib/chrome/speedline.js +2 -2
- package/lib/chrome/webdriver/builder.js +1 -1
- package/lib/chrome/webdriver/setupChromiumOptions.js +7 -2
- package/lib/connectivity/trafficShapeParser.js +2 -2
- package/lib/connectivity/tsProxy.js +3 -3
- package/lib/core/engine/command/measure.js +16 -10
- package/lib/core/engine/command/mouse/clickAndHold.js +146 -0
- package/lib/core/engine/command/mouse/contextClick.js +61 -0
- package/lib/core/engine/command/mouse/doubleClick.js +76 -0
- package/lib/core/engine/command/mouse/index.js +9 -0
- package/lib/core/engine/command/mouse/mouseMove.js +81 -0
- package/lib/core/engine/command/mouse/singleClick.js +79 -0
- package/lib/core/engine/command/switch.js +2 -8
- package/lib/core/engine/iteration.js +5 -6
- package/lib/core/engine/run.js +2 -2
- package/lib/core/seleniumRunner.js +23 -22
- package/lib/core/webdriver/index.js +1 -1
- package/lib/edge/webdriver/builder.js +1 -1
- package/lib/extensionserver/setup.js +1 -1
- package/lib/firefox/geckoProfiler.js +2 -3
- package/lib/firefox/getHAR.js +1 -1
- package/lib/firefox/webdriver/builder.js +12 -7
- package/lib/firefox/webdriver/firefox.js +6 -7
- package/lib/safari/webdriver/builder.js +1 -1
- package/lib/support/browserScript.js +1 -1
- package/lib/support/cli.js +12 -0
- package/lib/support/engineUtils.js +1 -1
- package/lib/support/getViewPort.js +1 -1
- package/lib/support/har/index.js +13 -14
- package/lib/support/pathToFolder.js +4 -10
- package/lib/support/preURL.js +1 -1
- package/lib/support/setResourceTimingBufferSize.js +1 -1
- package/lib/support/statistics.js +1 -1
- package/lib/support/stop.js +1 -1
- package/lib/support/storageManager.js +5 -10
- package/lib/video/postprocessing/finetune/addTextToVideo.js +1 -1
- package/lib/video/postprocessing/finetune/convertFps.js +1 -1
- package/lib/video/postprocessing/finetune/getFont.js +1 -1
- package/lib/video/postprocessing/finetune/getTimingMetrics.js +5 -4
- package/lib/video/postprocessing/finetune/index.js +1 -1
- package/lib/video/postprocessing/finetune/removeOrange.js +1 -1
- package/lib/video/postprocessing/visualmetrics/extraMetrics.js +1 -1
- package/lib/video/postprocessing/visualmetrics/getVideoMetrics.js +1 -1
- package/lib/video/screenRecording/desktop/ffmpegRecorder.js +3 -3
- package/lib/video/screenRecording/desktop/osx/getSPDisplaysDataType.js +1 -1
- package/lib/video/screenRecording/desktop/osx/getScreen.js +1 -1
- package/lib/video/screenRecording/firefox/firefoxWindowRecorder.js +2 -2
- package/lib/video/screenRecording/setOrangeBackground.js +1 -1
- package/package.json +9 -9
- package/lib/core/engine/command/mouse.js +0 -314
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const log = require('intel').getLogger('browsertime.command.mouse');
|
|
4
|
+
const webdriver = require('selenium-webdriver');
|
|
5
|
+
|
|
6
|
+
class SingleClick {
|
|
7
|
+
constructor(browser, pageCompleteCheck) {
|
|
8
|
+
this.browser = browser;
|
|
9
|
+
this.actions = this.browser.getDriver().actions({ async: true });
|
|
10
|
+
this.pageCompleteCheck = pageCompleteCheck;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Perform mouse single click on an element matches a XPath selector.
|
|
15
|
+
* @param {string} xpath
|
|
16
|
+
* @returns {Promise} Promise object represents when the element has been clicked.
|
|
17
|
+
* @throws Will throw an error if the element is not found.
|
|
18
|
+
*/
|
|
19
|
+
async byXpath(xpath, options) {
|
|
20
|
+
try {
|
|
21
|
+
const element = await this.browser
|
|
22
|
+
.getDriver()
|
|
23
|
+
.findElement(webdriver.By.xpath(xpath));
|
|
24
|
+
await this.actions.click(element).perform();
|
|
25
|
+
if (options && 'wait' in options && options.wait === true) {
|
|
26
|
+
return this.browser.extraWait(this.pageCompleteCheck);
|
|
27
|
+
}
|
|
28
|
+
} catch (e) {
|
|
29
|
+
log.error('Could not single click on element with xpath %s', xpath);
|
|
30
|
+
log.verbose(e);
|
|
31
|
+
throw Error('Could not single click on element with xpath ' + xpath);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Perform mouse single click on an element matches a CSS selector.
|
|
37
|
+
* @param {string} selector
|
|
38
|
+
* @returns {Promise} Promise object represents when the element has been clicked.
|
|
39
|
+
* @throws Will throw an error if the element is not found.
|
|
40
|
+
*/
|
|
41
|
+
async bySelector(selector, options) {
|
|
42
|
+
try {
|
|
43
|
+
const element = await this.browser
|
|
44
|
+
.getDriver()
|
|
45
|
+
.findElement(webdriver.By.css(selector));
|
|
46
|
+
await this.actions.click(element).perform();
|
|
47
|
+
if (options && 'wait' in options && options.wait === true) {
|
|
48
|
+
return this.browser.extraWait(this.pageCompleteCheck);
|
|
49
|
+
}
|
|
50
|
+
} catch (e) {
|
|
51
|
+
log.error('Could not single click on element with selector %s', selector);
|
|
52
|
+
log.verbose(e);
|
|
53
|
+
throw Error(
|
|
54
|
+
'Could not single click on element with selector ' + selector
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Perform mouse single click at the cursor's position.
|
|
61
|
+
* @param {string} xpath
|
|
62
|
+
* @returns {Promise} Promise object represents when double click occurs.
|
|
63
|
+
* @throws Will throw an error if double click cannot be performed.
|
|
64
|
+
*/
|
|
65
|
+
async atCursor(options) {
|
|
66
|
+
try {
|
|
67
|
+
await this.actions.click().perform();
|
|
68
|
+
if (options && 'wait' in options && options.wait === true) {
|
|
69
|
+
return this.browser.extraWait(this.pageCompleteCheck);
|
|
70
|
+
}
|
|
71
|
+
} catch (e) {
|
|
72
|
+
log.error('Could not perform single click');
|
|
73
|
+
log.verbose(e);
|
|
74
|
+
throw Error('Could not perform single click');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = SingleClick;
|
|
@@ -58,10 +58,7 @@ class Switch {
|
|
|
58
58
|
*/
|
|
59
59
|
async toNewTab(url) {
|
|
60
60
|
try {
|
|
61
|
-
await this.browser
|
|
62
|
-
.getDriver()
|
|
63
|
-
.switchTo()
|
|
64
|
-
.newWindow('tab');
|
|
61
|
+
await this.browser.getDriver().switchTo().newWindow('tab');
|
|
65
62
|
if (url) {
|
|
66
63
|
await this.navigate(url);
|
|
67
64
|
await this.browser.extraWait(this.pageCompleteCheck);
|
|
@@ -80,10 +77,7 @@ class Switch {
|
|
|
80
77
|
*/
|
|
81
78
|
async toNewWindow(url) {
|
|
82
79
|
try {
|
|
83
|
-
await this.browser
|
|
84
|
-
.getDriver()
|
|
85
|
-
.switchTo()
|
|
86
|
-
.newWindow('window');
|
|
80
|
+
await this.browser.getDriver().switchTo().newWindow('window');
|
|
87
81
|
if (url) {
|
|
88
82
|
await this.navigate(url);
|
|
89
83
|
await this.browser.extraWait(this.pageCompleteCheck);
|
|
@@ -31,7 +31,7 @@ const {
|
|
|
31
31
|
ClickAndHold,
|
|
32
32
|
ContextClick,
|
|
33
33
|
MouseMove
|
|
34
|
-
} = require('./command/mouse');
|
|
34
|
+
} = require('./command/mouse/');
|
|
35
35
|
|
|
36
36
|
const { isAndroidConfigured, Android } = require('../../android');
|
|
37
37
|
const Scroll = require('./command/scroll');
|
|
@@ -262,11 +262,10 @@ class Iteration {
|
|
|
262
262
|
'PerceptualSpeedIndexProgress'
|
|
263
263
|
]) {
|
|
264
264
|
if (videoMetrics.visualMetrics[progress]) {
|
|
265
|
-
videoMetrics.visualMetrics[
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
);
|
|
265
|
+
videoMetrics.visualMetrics[progress] =
|
|
266
|
+
util.jsonifyVisualProgress(
|
|
267
|
+
videoMetrics.visualMetrics[progress]
|
|
268
|
+
);
|
|
270
269
|
}
|
|
271
270
|
}
|
|
272
271
|
result[i].videoRecordingStart = videoMetrics.videoRecordingStart;
|
package/lib/core/engine/run.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
module.exports = function(urlOrFunctions) {
|
|
4
|
-
return async function(context, commands) {
|
|
3
|
+
module.exports = function (urlOrFunctions) {
|
|
4
|
+
return async function (context, commands) {
|
|
5
5
|
for (let urlOrFunction of urlOrFunctions) {
|
|
6
6
|
if (typeof urlOrFunction === 'function') {
|
|
7
7
|
await urlOrFunction(context, commands);
|
|
@@ -70,8 +70,9 @@ class SeleniumRunner {
|
|
|
70
70
|
this.driver = await timeout(
|
|
71
71
|
builder.createWebDriver(this.baseDir, this.options),
|
|
72
72
|
this.options.timeouts.browserStart,
|
|
73
|
-
`Failed to start ${this.options.browser} in ${
|
|
74
|
-
.browserStart / 1000
|
|
73
|
+
`Failed to start ${this.options.browser} in ${
|
|
74
|
+
this.options.timeouts.browserStart / 1000
|
|
75
|
+
} seconds.`
|
|
75
76
|
);
|
|
76
77
|
break;
|
|
77
78
|
} catch (e) {
|
|
@@ -85,9 +86,9 @@ class SeleniumRunner {
|
|
|
85
86
|
throw e;
|
|
86
87
|
} else {
|
|
87
88
|
log.info(
|
|
88
|
-
`${this.options.browser} failed to start, trying ${
|
|
89
|
-
i -
|
|
90
|
-
|
|
89
|
+
`${this.options.browser} failed to start, trying ${
|
|
90
|
+
tries - i - 1
|
|
91
|
+
} more time(s): ${e.message}`
|
|
91
92
|
);
|
|
92
93
|
}
|
|
93
94
|
}
|
|
@@ -167,11 +168,13 @@ class SeleniumRunner {
|
|
|
167
168
|
try {
|
|
168
169
|
const pageCompleteCheckCondition = new Condition(
|
|
169
170
|
'for page complete check script to return true',
|
|
170
|
-
function(d) {
|
|
171
|
-
return d
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
function (d) {
|
|
172
|
+
return d
|
|
173
|
+
.executeScript(pageCompleteCheck, waitTime)
|
|
174
|
+
.then(function (t) {
|
|
175
|
+
log.verbose('PageCompleteCheck returned %s', t);
|
|
176
|
+
return t === true;
|
|
177
|
+
});
|
|
175
178
|
}
|
|
176
179
|
);
|
|
177
180
|
log.debug(
|
|
@@ -297,9 +300,9 @@ class SeleniumRunner {
|
|
|
297
300
|
log.info(
|
|
298
301
|
`URL ${url} failed to load, the ${
|
|
299
302
|
this.options.browser
|
|
300
|
-
} are still on ${startURI} , trying ${
|
|
301
|
-
i -
|
|
302
|
-
|
|
303
|
+
} are still on ${startURI} , trying ${
|
|
304
|
+
tries - i - 1
|
|
305
|
+
} more time(s) but first wait for ${waitTime} ms.`
|
|
303
306
|
);
|
|
304
307
|
|
|
305
308
|
if (i === tries - 1) {
|
|
@@ -476,13 +479,11 @@ class SeleniumRunner {
|
|
|
476
479
|
*/
|
|
477
480
|
async getLogs(logType) {
|
|
478
481
|
return timeout(
|
|
479
|
-
this.driver
|
|
480
|
-
.manage()
|
|
481
|
-
.logs()
|
|
482
|
-
.get(logType),
|
|
482
|
+
this.driver.manage().logs().get(logType),
|
|
483
483
|
this.options.timeouts.logs,
|
|
484
|
-
`Extracting logs from ${this.options.browser} took more than ${
|
|
485
|
-
.options.timeouts.logs / 1000
|
|
484
|
+
`Extracting logs from ${this.options.browser} took more than ${
|
|
485
|
+
this.options.timeouts.logs / 1000
|
|
486
|
+
} seconds.`
|
|
486
487
|
);
|
|
487
488
|
}
|
|
488
489
|
|
|
@@ -626,9 +627,9 @@ class SeleniumRunner {
|
|
|
626
627
|
if (!script) {
|
|
627
628
|
let func = category[scriptName].function;
|
|
628
629
|
if (!func) {
|
|
629
|
-
throw
|
|
630
|
-
scriptName +
|
|
631
|
-
|
|
630
|
+
throw (
|
|
631
|
+
'Function and script cannot both be null in ' + scriptName + '.'
|
|
632
|
+
);
|
|
632
633
|
}
|
|
633
634
|
// We wrap the source code of the function in parenthesis
|
|
634
635
|
// "(...)" to contain it in a separate scope. We add a
|
|
@@ -13,7 +13,7 @@ const safari = require('../../safari/webdriver/builder');
|
|
|
13
13
|
* @returns {!Promise<webdriver.WebDriver>} a promise that resolves to the webdriver,
|
|
14
14
|
* or rejects if the current configuration is invalid.
|
|
15
15
|
*/
|
|
16
|
-
module.exports.createWebDriver = async function(baseDir, options) {
|
|
16
|
+
module.exports.createWebDriver = async function (baseDir, options) {
|
|
17
17
|
const browser = options.browser || 'chrome';
|
|
18
18
|
const seleniumUrl = options.selenium ? options.selenium.url : undefined;
|
|
19
19
|
const capabilities = options.selenium
|
|
@@ -7,7 +7,7 @@ const isEmpty = require('lodash.isempty');
|
|
|
7
7
|
const webdriver = require('selenium-webdriver');
|
|
8
8
|
const setupChromiumOptions = require('../../chrome/webdriver/setupChromiumOptions');
|
|
9
9
|
|
|
10
|
-
module.exports.configureBuilder = function(builder, baseDir, options) {
|
|
10
|
+
module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
11
11
|
const edgeConfig = options.edge || {};
|
|
12
12
|
const chromeConfig = options.chrome || {};
|
|
13
13
|
|
|
@@ -46,7 +46,7 @@ function generateURL(port, testUrl, options) {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
module.exports = async function(url, browser, port, options) {
|
|
49
|
+
module.exports = async function (url, browser, port, options) {
|
|
50
50
|
const configUrl = generateURL(port, url, options);
|
|
51
51
|
log.debug('Configuring browser plugin via %s', configUrl);
|
|
52
52
|
await browser.loadAndWait(configUrl);
|
|
@@ -40,9 +40,8 @@ class GeckoProfiler {
|
|
|
40
40
|
const runner = this.runner;
|
|
41
41
|
const firefoxConfig = this.firefoxConfig;
|
|
42
42
|
const options = this.options;
|
|
43
|
-
const chosenFeatures =
|
|
44
|
-
','
|
|
45
|
-
);
|
|
43
|
+
const chosenFeatures =
|
|
44
|
+
firefoxConfig.geckoProfilerParams.features.split(',');
|
|
46
45
|
const featureString = '["' + chosenFeatures.join('","') + '"]';
|
|
47
46
|
|
|
48
47
|
const chosenThreads = firefoxConfig.geckoProfilerParams.threads.split(',');
|
package/lib/firefox/getHAR.js
CHANGED
|
@@ -4,7 +4,7 @@ const log = require('intel').getLogger('browsertime.firefox');
|
|
|
4
4
|
|
|
5
5
|
// Get the HAR from Firefox
|
|
6
6
|
// Using https://github.com/firefox-devtools/har-export-trigger
|
|
7
|
-
module.exports = async function(runner, includeResponseBodies) {
|
|
7
|
+
module.exports = async function (runner, includeResponseBodies) {
|
|
8
8
|
const script = `
|
|
9
9
|
const callback = arguments[arguments.length - 1];
|
|
10
10
|
async function triggerExport() {
|
|
@@ -13,7 +13,7 @@ const disableTrackingProtectionPreferences = require('../settings/disableTrackin
|
|
|
13
13
|
const util = require('../../support/util');
|
|
14
14
|
const { Android } = require('../../android');
|
|
15
15
|
|
|
16
|
-
module.exports.configureBuilder = function(builder, baseDir, options) {
|
|
16
|
+
module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
17
17
|
// Here we configure everything that we need to start Firefox
|
|
18
18
|
const firefoxConfig = options.firefox || {};
|
|
19
19
|
const moduleRootPath = path.resolve(__dirname, '..', '..', '..');
|
|
@@ -83,18 +83,22 @@ module.exports.configureBuilder = function(builder, baseDir, options) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
if (!firefoxConfig.noDefaultPrefs) {
|
|
87
|
+
Object.keys(defaultFirefoxPreferences).forEach(function (pref) {
|
|
88
|
+
ffOptions.setPreference(pref, defaultFirefoxPreferences[pref]);
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
log.info('Skip setting default preferences for Firefox');
|
|
92
|
+
}
|
|
89
93
|
|
|
90
94
|
if (firefoxConfig.disableSafeBrowsing) {
|
|
91
|
-
Object.keys(disableSafeBrowsingPreferences).forEach(function(pref) {
|
|
95
|
+
Object.keys(disableSafeBrowsingPreferences).forEach(function (pref) {
|
|
92
96
|
ffOptions.setPreference(pref, disableSafeBrowsingPreferences[pref]);
|
|
93
97
|
});
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
if (firefoxConfig.disableTrackingProtection) {
|
|
97
|
-
Object.keys(disableTrackingProtectionPreferences).forEach(function(pref) {
|
|
101
|
+
Object.keys(disableTrackingProtectionPreferences).forEach(function (pref) {
|
|
98
102
|
ffOptions.setPreference(pref, disableTrackingProtectionPreferences[pref]);
|
|
99
103
|
});
|
|
100
104
|
}
|
|
@@ -140,6 +144,7 @@ module.exports.configureBuilder = function(builder, baseDir, options) {
|
|
|
140
144
|
ffOptions.setPreference('devtools.chrome.enabled', true);
|
|
141
145
|
|
|
142
146
|
const userPrefs = util.toArray(firefoxConfig.preference);
|
|
147
|
+
log.debug('Set Firefox preference %j', userPrefs);
|
|
143
148
|
for (const pref of userPrefs) {
|
|
144
149
|
const name = pref.substr(0, pref.indexOf(':'));
|
|
145
150
|
let value = pref.substr(pref.indexOf(':') + 1);
|
|
@@ -163,7 +168,7 @@ module.exports.configureBuilder = function(builder, baseDir, options) {
|
|
|
163
168
|
get(firefoxConfig, 'developer') ? firefox.Channel.AURORA : undefined
|
|
164
169
|
];
|
|
165
170
|
|
|
166
|
-
firefoxTypes = firefoxTypes.filter(function(n) {
|
|
171
|
+
firefoxTypes = firefoxTypes.filter(function (n) {
|
|
167
172
|
return n !== undefined;
|
|
168
173
|
});
|
|
169
174
|
|
|
@@ -206,13 +206,12 @@ class Firefox {
|
|
|
206
206
|
]) {
|
|
207
207
|
// You can configure to not use content and perceptual.
|
|
208
208
|
if (results[i].visualMetrics[progress]) {
|
|
209
|
-
results[i].visualMetrics[
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
);
|
|
209
|
+
results[i].visualMetrics[progress] =
|
|
210
|
+
util.adjustVisualProgressTimestamps(
|
|
211
|
+
results[i].visualMetrics[progress],
|
|
212
|
+
geckoProfile.meta.startTime,
|
|
213
|
+
firstFrameStartTime
|
|
214
|
+
);
|
|
216
215
|
}
|
|
217
216
|
}
|
|
218
217
|
geckoProfile.meta.visualMetrics = results[i].visualMetrics;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
const s = require('selenium-webdriver/safari');
|
|
3
3
|
|
|
4
|
-
module.exports.configureBuilder = async function(builder, baseDir, options) {
|
|
4
|
+
module.exports.configureBuilder = async function (builder, baseDir, options) {
|
|
5
5
|
const safariOptions = options.safari || {};
|
|
6
6
|
builder
|
|
7
7
|
.getCapabilities()
|
|
@@ -80,7 +80,7 @@ function generateScriptObject(name, path, contents) {
|
|
|
80
80
|
content: null,
|
|
81
81
|
isAsync:
|
|
82
82
|
Object.getPrototypeOf(scriptAndMetadataObject.function) ===
|
|
83
|
-
Object.getPrototypeOf(async function() {})
|
|
83
|
+
Object.getPrototypeOf(async function () {})
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
} catch (error) {
|
package/lib/support/cli.js
CHANGED
|
@@ -282,6 +282,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
282
282
|
describe: 'Collect Chromes console log and save to disk.',
|
|
283
283
|
group: 'chrome'
|
|
284
284
|
})
|
|
285
|
+
.option('chrome.noDefaultOptions', {
|
|
286
|
+
type: 'boolean',
|
|
287
|
+
describe:
|
|
288
|
+
'Prevent Browsertime from setting its default options for Chrome',
|
|
289
|
+
group: 'chrome'
|
|
290
|
+
})
|
|
285
291
|
.option('cpu', {
|
|
286
292
|
type: 'boolean',
|
|
287
293
|
describe:
|
|
@@ -483,6 +489,12 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
483
489
|
type: 'boolean',
|
|
484
490
|
group: 'firefox'
|
|
485
491
|
})
|
|
492
|
+
.option('firefox.noDefaultPrefs', {
|
|
493
|
+
describe: 'Prevents browsertime from setting its default preferences.',
|
|
494
|
+
default: false,
|
|
495
|
+
type: 'boolean',
|
|
496
|
+
group: 'firefox'
|
|
497
|
+
})
|
|
486
498
|
.option('firefox.disableSafeBrowsing', {
|
|
487
499
|
describe: 'Disable safebrowsing.',
|
|
488
500
|
default: true,
|
|
@@ -4,7 +4,7 @@ const path = require('path');
|
|
|
4
4
|
const dayjs = require('dayjs');
|
|
5
5
|
const util = require('../support/util');
|
|
6
6
|
const log = require('intel').getLogger('browsertime');
|
|
7
|
-
const AsyncFunction = Object.getPrototypeOf(async function() {}).constructor;
|
|
7
|
+
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
8
8
|
|
|
9
9
|
module.exports = {
|
|
10
10
|
loadPrePostScripts(scripts) {
|
|
@@ -25,7 +25,7 @@ const sizeMap = {
|
|
|
25
25
|
'iPad Pro': '1024x1366'
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
module.exports = function(options) {
|
|
28
|
+
module.exports = function (options) {
|
|
29
29
|
// you cannot set the width/height for phone so just keep the viewport undefined
|
|
30
30
|
if (isAndroidConfigured(options)) {
|
|
31
31
|
return;
|
package/lib/support/har/index.js
CHANGED
|
@@ -97,20 +97,19 @@ function addMetaToHAR(index, harPage, url, browserScript, options) {
|
|
|
97
97
|
? options.resultURL
|
|
98
98
|
: options.resultURL + '/';
|
|
99
99
|
if (options.screenshot) {
|
|
100
|
-
_meta.screenshot = `${base}${pathToFolder(
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)}screenshots/${index + 1}/afterPageCompleteCheck.${
|
|
104
|
-
options.screenshotParams.type
|
|
105
|
-
}`;
|
|
100
|
+
_meta.screenshot = `${base}${pathToFolder(url, options)}screenshots/${
|
|
101
|
+
index + 1
|
|
102
|
+
}/afterPageCompleteCheck.${options.screenshotParams.type}`;
|
|
106
103
|
}
|
|
107
104
|
if (options.video) {
|
|
108
|
-
_meta.video = `${base}${pathToFolder(url, options)}video/${
|
|
109
|
-
1
|
|
105
|
+
_meta.video = `${base}${pathToFolder(url, options)}video/${
|
|
106
|
+
index + 1
|
|
107
|
+
}.mp4`;
|
|
110
108
|
}
|
|
111
109
|
if (options.chrome && options.chrome.timeline) {
|
|
112
|
-
_meta.timeline = `${base}${pathToFolder(url, options)}trace-${
|
|
113
|
-
1
|
|
110
|
+
_meta.timeline = `${base}${pathToFolder(url, options)}trace-${
|
|
111
|
+
index + 1
|
|
112
|
+
}.json.gz`;
|
|
114
113
|
}
|
|
115
114
|
}
|
|
116
115
|
if (browserScript && browserScript.pageinfo) {
|
|
@@ -129,7 +128,7 @@ function jsonifyVisualProgress(visualProgress) {
|
|
|
129
128
|
}
|
|
130
129
|
|
|
131
130
|
module.exports = {
|
|
132
|
-
addBrowser: function(har, name, version, comment) {
|
|
131
|
+
addBrowser: function (har, name, version, comment) {
|
|
133
132
|
merge(har.log, {
|
|
134
133
|
browser: {
|
|
135
134
|
name,
|
|
@@ -145,7 +144,7 @@ module.exports = {
|
|
|
145
144
|
return har;
|
|
146
145
|
},
|
|
147
146
|
|
|
148
|
-
addCreator: function(har, comment) {
|
|
147
|
+
addCreator: function (har, comment) {
|
|
149
148
|
merge(har.log, {
|
|
150
149
|
creator: {
|
|
151
150
|
name: 'Browsertime',
|
|
@@ -161,7 +160,7 @@ module.exports = {
|
|
|
161
160
|
return har;
|
|
162
161
|
},
|
|
163
162
|
|
|
164
|
-
getFullyLoaded: function(har) {
|
|
163
|
+
getFullyLoaded: function (har) {
|
|
165
164
|
const fullyLoaded = [];
|
|
166
165
|
const entries = Array.from(har.log.entries);
|
|
167
166
|
|
|
@@ -190,7 +189,7 @@ module.exports = {
|
|
|
190
189
|
return fullyLoaded;
|
|
191
190
|
},
|
|
192
191
|
|
|
193
|
-
mergeHars: function(hars) {
|
|
192
|
+
mergeHars: function (hars) {
|
|
194
193
|
if (isEmpty(hars)) {
|
|
195
194
|
return undefined;
|
|
196
195
|
}
|
|
@@ -10,7 +10,7 @@ function toSafeKey(key) {
|
|
|
10
10
|
return key.replace(/[.~ /+|,:?&%–)(]|%7C/g, '-');
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
module.exports = function(url, options) {
|
|
13
|
+
module.exports = function (url, options) {
|
|
14
14
|
if (options.useSameDir) {
|
|
15
15
|
return '';
|
|
16
16
|
} else {
|
|
@@ -31,19 +31,13 @@ module.exports = function(url, options) {
|
|
|
31
31
|
|
|
32
32
|
if (useHash && !isEmpty(parsedUrl.hash)) {
|
|
33
33
|
const md5 = crypto.createHash('md5'),
|
|
34
|
-
hash = md5
|
|
35
|
-
.update(parsedUrl.hash)
|
|
36
|
-
.digest('hex')
|
|
37
|
-
.substring(0, 8);
|
|
34
|
+
hash = md5.update(parsedUrl.hash).digest('hex').substring(0, 8);
|
|
38
35
|
urlSegments.push('hash-' + hash);
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
if (!isEmpty(parsedUrl.search)) {
|
|
42
39
|
const md5 = crypto.createHash('md5'),
|
|
43
|
-
hash = md5
|
|
44
|
-
.update(parsedUrl.search)
|
|
45
|
-
.digest('hex')
|
|
46
|
-
.substring(0, 8);
|
|
40
|
+
hash = md5.update(parsedUrl.search).digest('hex').substring(0, 8);
|
|
47
41
|
urlSegments.push('query-' + hash);
|
|
48
42
|
}
|
|
49
43
|
|
|
@@ -65,7 +59,7 @@ module.exports = function(url, options) {
|
|
|
65
59
|
|
|
66
60
|
pathSegments.push('data');
|
|
67
61
|
|
|
68
|
-
pathSegments.forEach(function(segment, index) {
|
|
62
|
+
pathSegments.forEach(function (segment, index) {
|
|
69
63
|
if (segment) {
|
|
70
64
|
pathSegments[index] = segment.replace(
|
|
71
65
|
/[^-a-z0-9_.\u0621-\u064A]/gi,
|
package/lib/support/preURL.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const log = require('intel').getLogger('browsertime');
|
|
4
4
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
5
5
|
|
|
6
|
-
module.exports = async function(browser, options) {
|
|
6
|
+
module.exports = async function (browser, options) {
|
|
7
7
|
log.info('Accessing preURL %s', options.preURL);
|
|
8
8
|
await browser.loadAndWait(options.preURL);
|
|
9
9
|
await delay(options.preURLDelay ? options.preURLDelay : 1500);
|
|
@@ -137,7 +137,7 @@ class Statistics {
|
|
|
137
137
|
stats.stddev() / Math.sqrt(stats.length).toFixed(decimals)
|
|
138
138
|
) // "standard deviation of the mean"
|
|
139
139
|
};
|
|
140
|
-
percentiles.forEach(function(p) {
|
|
140
|
+
percentiles.forEach(function (p) {
|
|
141
141
|
let name = percentileName(p);
|
|
142
142
|
node[name] = parseFloat(stats.percentile(p).toFixed(decimals));
|
|
143
143
|
});
|
package/lib/support/stop.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const execa = require('execa');
|
|
4
4
|
const log = require('intel').getLogger('browsertime');
|
|
5
5
|
|
|
6
|
-
module.exports = async function(processName) {
|
|
6
|
+
module.exports = async function (processName) {
|
|
7
7
|
const scriptArgs = ['-9', processName];
|
|
8
8
|
|
|
9
9
|
log.debug('Kill all processes ' + processName);
|
|
@@ -17,9 +17,7 @@ const unlink = promisify(fs.unlink);
|
|
|
17
17
|
const mkdir = promisify(fs.mkdir);
|
|
18
18
|
|
|
19
19
|
const defaultDir = 'browsertime-results';
|
|
20
|
-
let timestamp = dayjs()
|
|
21
|
-
.format()
|
|
22
|
-
.replace(/:/g, '');
|
|
20
|
+
let timestamp = dayjs().format().replace(/:/g, '');
|
|
23
21
|
|
|
24
22
|
function pathNameFromUrl(url) {
|
|
25
23
|
const parsedUrl = urlParser.parse(url),
|
|
@@ -29,10 +27,7 @@ function pathNameFromUrl(url) {
|
|
|
29
27
|
|
|
30
28
|
if (!isEmpty(parsedUrl.search)) {
|
|
31
29
|
const md5 = crypto.createHash('md5'),
|
|
32
|
-
hash = md5
|
|
33
|
-
.update(parsedUrl.search)
|
|
34
|
-
.digest('hex')
|
|
35
|
-
.substring(0, 8);
|
|
30
|
+
hash = md5.update(parsedUrl.search).digest('hex').substring(0, 8);
|
|
36
31
|
pathSegments.push('query-' + hash);
|
|
37
32
|
}
|
|
38
33
|
|
|
@@ -115,18 +110,18 @@ class StorageManager {
|
|
|
115
110
|
}
|
|
116
111
|
|
|
117
112
|
async gzip(inputFile, outputFile, removeInput) {
|
|
118
|
-
const promise = new Promise(function(resolve, reject) {
|
|
113
|
+
const promise = new Promise(function (resolve, reject) {
|
|
119
114
|
const gzip = zlib.createGzip();
|
|
120
115
|
const input = fs.createReadStream(inputFile);
|
|
121
116
|
const out = fs.createWriteStream(outputFile);
|
|
122
|
-
out.on('finish', function() {
|
|
117
|
+
out.on('finish', function () {
|
|
123
118
|
if (removeInput) {
|
|
124
119
|
unlink(inputFile).then(() => resolve());
|
|
125
120
|
} else {
|
|
126
121
|
resolve();
|
|
127
122
|
}
|
|
128
123
|
});
|
|
129
|
-
out.on('error', function(e) {
|
|
124
|
+
out.on('error', function (e) {
|
|
130
125
|
log.error('Could not gzip %s to %s', inputFile, outputFile, e);
|
|
131
126
|
reject();
|
|
132
127
|
});
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const execa = require('execa');
|
|
4
4
|
const log = require('intel').getLogger('browsertime.video');
|
|
5
5
|
|
|
6
|
-
module.exports = async function(src, dest, framerate) {
|
|
6
|
+
module.exports = async function (src, dest, framerate) {
|
|
7
7
|
const scriptArgs = ['-nostdin', '-i', src, '-r', framerate, dest];
|
|
8
8
|
log.info('Converting video to %s fps', framerate);
|
|
9
9
|
return execa('ffmpeg', scriptArgs);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
module.exports = function(options) {
|
|
4
|
+
module.exports = function (options) {
|
|
5
5
|
// If the font is not part of the params and we're on macOS
|
|
6
6
|
// we check that SFNSMono.ttf is available
|
|
7
7
|
if (!options.videoParams.fontPath && process.platform === 'darwin') {
|