browsertime 16.16.0 → 17.0.0-beta.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 +52 -0
- package/bin/browsertime.js +43 -43
- package/bin/browsertimeWebPageReplay.js +10 -9
- package/browserscripts/pageinfo/generator.js +1 -1
- package/index.js +14 -13
- package/lib/android/gnirehtet.js +14 -15
- package/lib/android/index.js +92 -89
- package/lib/android/root.js +6 -9
- package/lib/chrome/chromeDevtoolsProtocol.js +46 -45
- package/lib/chrome/har.js +12 -13
- package/lib/chrome/longTaskMetrics.js +3 -5
- package/lib/chrome/parseCpuTrace.js +13 -10
- package/lib/chrome/settings/chromeAndroidOptions.js +1 -3
- package/lib/chrome/settings/chromeDesktopOptions.js +1 -3
- package/lib/chrome/settings/traceCategories.js +1 -3
- package/lib/chrome/traceCategoriesParser.js +35 -36
- package/lib/chrome/webdriver/builder.js +18 -26
- package/lib/chrome/webdriver/chromium.js +56 -46
- package/lib/chrome/webdriver/setupChromiumOptions.js +32 -27
- package/lib/connectivity/humble.js +13 -14
- package/lib/connectivity/index.js +74 -77
- package/lib/connectivity/trafficShapeParser.js +31 -35
- package/lib/core/engine/collector.js +25 -22
- package/lib/core/engine/command/addText.js +24 -27
- package/lib/core/engine/command/android.js +7 -11
- package/lib/core/engine/command/cache.js +3 -4
- package/lib/core/engine/command/chromeDevToolsProtocol.js +20 -20
- package/lib/core/engine/command/click.js +48 -49
- package/lib/core/engine/command/debug.js +3 -4
- package/lib/core/engine/command/javaScript.js +18 -19
- package/lib/core/engine/command/measure.js +31 -37
- package/lib/core/engine/command/meta.js +1 -4
- package/lib/core/engine/command/mouse/clickAndHold.js +36 -39
- package/lib/core/engine/command/mouse/contextClick.js +17 -18
- package/lib/core/engine/command/mouse/doubleClick.js +17 -19
- package/lib/core/engine/command/mouse/index.js +5 -9
- package/lib/core/engine/command/mouse/mouseMove.js +19 -23
- package/lib/core/engine/command/mouse/singleClick.js +15 -19
- package/lib/core/engine/command/navigation.js +12 -14
- package/lib/core/engine/command/screenshot.js +1 -4
- package/lib/core/engine/command/scroll.js +4 -7
- package/lib/core/engine/command/select.js +26 -26
- package/lib/core/engine/command/set.js +25 -23
- package/lib/core/engine/command/stopWatch.js +5 -8
- package/lib/core/engine/command/switch.js +18 -20
- package/lib/core/engine/command/util/lcpHighlightScript.js +1 -2
- package/lib/core/engine/command/util/lsHighlightScript.js +1 -2
- package/lib/core/engine/command/wait.js +18 -18
- package/lib/core/engine/index.js +81 -71
- package/lib/core/engine/iteration.js +93 -79
- package/lib/core/engine/run.js +5 -9
- package/lib/core/pageCompleteChecks/defaultPageCompleteCheck.js +1 -2
- package/lib/core/pageCompleteChecks/pageCompleteCheckByInactivity.js +1 -3
- package/lib/core/pageCompleteChecks/spaInactivity.js +1 -3
- package/lib/core/seleniumRunner.js +92 -100
- package/lib/core/webdriver/index.js +24 -21
- package/lib/edge/webdriver/builder.js +21 -26
- package/lib/extensionserver/httpServer.js +17 -21
- package/lib/extensionserver/index.js +8 -12
- package/lib/extensionserver/setup.js +12 -12
- package/lib/firefox/geckoProfiler.js +27 -21
- package/lib/firefox/getHAR.js +7 -8
- package/lib/firefox/memoryReport.js +9 -11
- package/lib/firefox/perfStats.js +5 -7
- package/lib/firefox/settings/disableSafeBrowsingPreferences.js +1 -3
- package/lib/firefox/settings/disableTrackingProtectionPreferences.js +1 -3
- package/lib/firefox/settings/firefoxPreferences.js +2 -4
- package/lib/firefox/settings/geckoProfilerDefaults.js +5 -9
- package/lib/firefox/webdriver/builder.js +66 -63
- package/lib/firefox/webdriver/firefox.js +43 -48
- package/lib/safari/webdriver/builder.js +4 -5
- package/lib/safari/webdriver/safari.js +4 -8
- package/lib/screenshot/defaults.js +1 -3
- package/lib/screenshot/index.js +24 -21
- package/lib/support/browserScript.js +65 -56
- package/lib/support/cli.js +123 -85
- package/lib/support/dns.js +6 -7
- package/lib/support/engineUtils.js +85 -38
- package/lib/support/errors.js +4 -13
- package/lib/support/fileUtil.js +81 -68
- package/lib/support/filters.js +15 -20
- package/lib/support/getViewPort.js +6 -7
- package/lib/support/har/index.js +208 -216
- package/lib/support/images/index.js +54 -26
- package/lib/support/logging.js +20 -17
- package/lib/support/pathToFolder.js +18 -23
- package/lib/support/preURL.js +5 -6
- package/lib/support/processes.js +4 -6
- package/lib/support/setResourceTimingBufferSize.js +2 -4
- package/lib/support/statistics.js +58 -56
- package/lib/support/stop.js +7 -8
- package/lib/support/storageManager.js +44 -44
- package/lib/support/tcpdump.js +22 -16
- package/lib/support/userTiming.js +7 -13
- package/lib/support/util.js +204 -224
- package/lib/support/xvfb.js +11 -13
- package/lib/video/defaults.js +6 -10
- package/lib/video/postprocessing/finetune/addTextToVideo.js +15 -15
- package/lib/video/postprocessing/finetune/convertFps.js +14 -8
- package/lib/video/postprocessing/finetune/getFont.js +7 -9
- package/lib/video/postprocessing/finetune/getTimingMetrics.js +19 -18
- package/lib/video/postprocessing/finetune/index.js +40 -36
- package/lib/video/postprocessing/finetune/removeOrange.js +10 -11
- package/lib/video/postprocessing/visualmetrics/extraMetrics.js +17 -13
- package/lib/video/postprocessing/visualmetrics/getVideoMetrics.js +12 -13
- package/lib/video/postprocessing/visualmetrics/visualMetrics.js +117 -128
- package/lib/video/screenRecording/android/recorder.js +12 -17
- package/lib/video/screenRecording/desktop/convert.js +13 -11
- package/lib/video/screenRecording/desktop/desktopRecorder.js +29 -24
- package/lib/video/screenRecording/desktop/ffmpegRecorder.js +60 -63
- package/lib/video/screenRecording/desktop/osx/getSPDisplaysDataType.js +4 -6
- package/lib/video/screenRecording/desktop/osx/getScreen.js +9 -10
- package/lib/video/screenRecording/firefox/firefoxWindowRecorder.js +54 -54
- package/lib/video/screenRecording/ios/convertToMp4.js +10 -11
- package/lib/video/screenRecording/ios/iosRecorder.js +23 -21
- package/lib/video/screenRecording/iosSimulator/convertToMp4.js +10 -11
- package/lib/video/screenRecording/iosSimulator/recorder.js +10 -9
- package/lib/video/screenRecording/recorder.js +8 -9
- package/lib/video/screenRecording/setOrangeBackground.js +5 -6
- package/lib/video/video.js +28 -34
- package/package.json +19 -17
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const httpServer = require('./httpServer');
|
|
4
|
-
const setup = require('./setup');
|
|
1
|
+
import { startServer, stopServer } from './httpServer.js';
|
|
2
|
+
import setup from './setup.js';
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* Create a ExtensionServer. The extension server helps us with
|
|
@@ -16,8 +14,7 @@ class ExtensionServer {
|
|
|
16
14
|
|
|
17
15
|
_useServer(newOptions) {
|
|
18
16
|
const options = newOptions || this.options;
|
|
19
|
-
|
|
20
|
-
options.browser === 'firefox' &&
|
|
17
|
+
return options.browser === 'firefox' &&
|
|
21
18
|
(options.cacheClearRaw ||
|
|
22
19
|
options.requestheader ||
|
|
23
20
|
options.block ||
|
|
@@ -25,20 +22,19 @@ class ExtensionServer {
|
|
|
25
22
|
options.cookie ||
|
|
26
23
|
options.injectJs ||
|
|
27
24
|
options.clearCacheKeepCookies)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} else return false;
|
|
25
|
+
? true
|
|
26
|
+
: false;
|
|
31
27
|
}
|
|
32
28
|
|
|
33
29
|
async _start() {
|
|
34
30
|
if (!this.extensionServer) {
|
|
35
|
-
this.extensionServer = await
|
|
31
|
+
this.extensionServer = await startServer();
|
|
36
32
|
}
|
|
37
33
|
}
|
|
38
34
|
|
|
39
35
|
async _stop() {
|
|
40
36
|
if (this.extensionServer) {
|
|
41
|
-
await
|
|
37
|
+
await stopServer(this.extensionServer);
|
|
42
38
|
this.extensionServer = undefined;
|
|
43
39
|
}
|
|
44
40
|
}
|
|
@@ -53,4 +49,4 @@ class ExtensionServer {
|
|
|
53
49
|
}
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
|
|
52
|
+
export default ExtensionServer;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const log =
|
|
1
|
+
import { format } from 'node:url';
|
|
2
|
+
import intel from 'intel';
|
|
3
|
+
import { toArray } from '../support/util.js';
|
|
4
|
+
const log = intel.getLogger('browsertime');
|
|
5
5
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
6
6
|
|
|
7
7
|
function generateURL(port, testUrl, options) {
|
|
8
8
|
const query = {};
|
|
9
9
|
if (options.block) {
|
|
10
|
-
query.bl =
|
|
10
|
+
query.bl = toArray(options.block);
|
|
11
11
|
}
|
|
12
12
|
if (options.requestheader) {
|
|
13
|
-
query.rh =
|
|
13
|
+
query.rh = toArray(options.requestheader);
|
|
14
14
|
}
|
|
15
15
|
if (options.cacheClearRaw) {
|
|
16
16
|
query.clear = 'true';
|
|
@@ -29,16 +29,16 @@ function generateURL(port, testUrl, options) {
|
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
if (options.cookie) {
|
|
32
|
-
const cookies =
|
|
32
|
+
const cookies = toArray(options.cookie);
|
|
33
33
|
query.cookie = [];
|
|
34
34
|
for (const cookie of cookies) {
|
|
35
|
-
const name = cookie.
|
|
36
|
-
const value = cookie.
|
|
35
|
+
const name = cookie.slice(0, Math.max(0, cookie.indexOf('=')));
|
|
36
|
+
const value = cookie.slice(Math.max(0, cookie.indexOf('=') + 1));
|
|
37
37
|
query.cookie.push(name + '@' + value + '@' + testUrl);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
return
|
|
41
|
+
return format({
|
|
42
42
|
protocol: 'http',
|
|
43
43
|
hostname: '127.0.0.1',
|
|
44
44
|
port,
|
|
@@ -46,10 +46,10 @@ function generateURL(port, testUrl, options) {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
export default 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);
|
|
53
53
|
// Add some time to make sure the cache is cleared etc
|
|
54
54
|
await delay(500);
|
|
55
|
-
}
|
|
55
|
+
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
import get from 'lodash.get';
|
|
3
|
+
import intel from 'intel';
|
|
4
|
+
import {
|
|
5
|
+
android_sampling_interval,
|
|
6
|
+
desktop_sampling_interval
|
|
7
|
+
} from './settings/geckoProfilerDefaults.js';
|
|
8
|
+
import { isAndroidConfigured, Android } from '../android/index.js';
|
|
9
|
+
import pathToFolder from '../support/pathToFolder.js';
|
|
10
|
+
import { BrowserError } from '../support/errors.js';
|
|
9
11
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
12
|
+
const log = intel.getLogger('browsertime.firefox');
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* Timeout a promise after ms. Use promise.race to compete
|
|
@@ -16,7 +19,7 @@ const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
|
16
19
|
* @param {string} errorMessage - the error message in the Error if we timeouts
|
|
17
20
|
*/
|
|
18
21
|
async function timeout(promise, ms, errorMessage) {
|
|
19
|
-
let timer
|
|
22
|
+
let timer;
|
|
20
23
|
|
|
21
24
|
return Promise.race([
|
|
22
25
|
new Promise((resolve, reject) => {
|
|
@@ -56,8 +59,8 @@ class GeckoProfiler {
|
|
|
56
59
|
!firefoxConfig.geckoProfilerParams.interval
|
|
57
60
|
) {
|
|
58
61
|
interval = isAndroidConfigured(options)
|
|
59
|
-
?
|
|
60
|
-
:
|
|
62
|
+
? android_sampling_interval
|
|
63
|
+
: desktop_sampling_interval;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
const bufferSize = firefoxConfig.geckoProfilerParams.bufferSize;
|
|
@@ -95,12 +98,9 @@ class GeckoProfiler {
|
|
|
95
98
|
const storageManager = this.storageManager;
|
|
96
99
|
const options = this.options;
|
|
97
100
|
let profileDir = await storageManager.createSubDataDir(
|
|
98
|
-
|
|
99
|
-
);
|
|
100
|
-
let destinationFilename = path.join(
|
|
101
|
-
profileDir,
|
|
102
|
-
`geckoProfile-${index}.json`
|
|
101
|
+
join(pathToFolder(url, options))
|
|
103
102
|
);
|
|
103
|
+
let destinationFilename = join(profileDir, `geckoProfile-${index}.json`);
|
|
104
104
|
|
|
105
105
|
let deviceProfileFilename = destinationFilename;
|
|
106
106
|
if (isAndroidConfigured(options)) {
|
|
@@ -115,6 +115,12 @@ class GeckoProfiler {
|
|
|
115
115
|
log.info(
|
|
116
116
|
`Collecting Gecko profile from ${deviceProfileFilename} to ${destinationFilename}`
|
|
117
117
|
);
|
|
118
|
+
// Pause profiler before we collect the profile, so that we don't capture
|
|
119
|
+
// more samples while the parent process waits for subprocess profiles.
|
|
120
|
+
await runner.runPrivilegedScript(
|
|
121
|
+
'Services.profiler.Pause();',
|
|
122
|
+
'Pause GeckoProfiler.'
|
|
123
|
+
);
|
|
118
124
|
const script = `
|
|
119
125
|
var callback = arguments[arguments.length - 1];
|
|
120
126
|
Services.profiler.dumpProfileToFileAsync(String.raw\`${deviceProfileFilename}\`)
|
|
@@ -124,7 +130,7 @@ class GeckoProfiler {
|
|
|
124
130
|
try {
|
|
125
131
|
await timeout(
|
|
126
132
|
runner.runPrivilegedAsyncScript(script, 'Collect GeckoProfiler'),
|
|
127
|
-
|
|
133
|
+
1_200_000,
|
|
128
134
|
'Could not get the Geckoprofiler log'
|
|
129
135
|
);
|
|
130
136
|
log.info('Stop GeckoProfiler.');
|
|
@@ -141,15 +147,15 @@ class GeckoProfiler {
|
|
|
141
147
|
// GZIP the profile and remove the old file
|
|
142
148
|
return storageManager.gzip(
|
|
143
149
|
destinationFilename,
|
|
144
|
-
|
|
150
|
+
join(profileDir, `geckoProfile-${index}.json.gz`),
|
|
145
151
|
true
|
|
146
152
|
);
|
|
147
|
-
} catch (
|
|
148
|
-
log.error(
|
|
153
|
+
} catch (error) {
|
|
154
|
+
log.error(error.message);
|
|
149
155
|
}
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
addMetaData() {}
|
|
153
159
|
}
|
|
154
160
|
|
|
155
|
-
|
|
161
|
+
export default GeckoProfiler;
|
package/lib/firefox/getHAR.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const log = require('intel').getLogger('browsertime.firefox');
|
|
1
|
+
import intel from 'intel';
|
|
2
|
+
const log = intel.getLogger('browsertime.firefox');
|
|
4
3
|
|
|
5
4
|
// Get the HAR from Firefox
|
|
6
5
|
// Using https://github.com/firefox-devtools/har-export-trigger
|
|
7
|
-
|
|
6
|
+
export default async function (runner, includeResponseBodies) {
|
|
8
7
|
const script = `
|
|
9
8
|
const callback = arguments[arguments.length - 1];
|
|
10
9
|
async function triggerExport() {
|
|
@@ -49,7 +48,7 @@ module.exports = async function (runner, includeResponseBodies) {
|
|
|
49
48
|
delete entry.response.content.text;
|
|
50
49
|
} else if (
|
|
51
50
|
entry.response.content.mimeType &&
|
|
52
|
-
entry.response.content.mimeType.
|
|
51
|
+
!entry.response.content.mimeType.includes('text/html')
|
|
53
52
|
) {
|
|
54
53
|
delete entry.response.content.text;
|
|
55
54
|
}
|
|
@@ -61,7 +60,7 @@ module.exports = async function (runner, includeResponseBodies) {
|
|
|
61
60
|
'Got an error from HAR Export Trigger ' + JSON.stringify(harResult)
|
|
62
61
|
);
|
|
63
62
|
}
|
|
64
|
-
} catch (
|
|
65
|
-
log.error('Could not get the HAR from Firefox',
|
|
63
|
+
} catch (error) {
|
|
64
|
+
log.error('Could not get the HAR from Firefox', error);
|
|
66
65
|
}
|
|
67
|
-
}
|
|
66
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const { isAndroidConfigured, Android } = require('../android');
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import intel from 'intel';
|
|
3
|
+
import pathToFolder from '../support/pathToFolder.js';
|
|
4
|
+
import { BrowserError } from '../support/errors.js';
|
|
5
|
+
import { isAndroidConfigured, Android } from '../android/index.js';
|
|
7
6
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
7
|
+
const log = intel.getLogger('browsertime.firefox');
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Timeout a promise after ms. Use promise.race to compete
|
|
@@ -14,7 +14,7 @@ const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
|
14
14
|
* @param {string} errorMessage - the error message in the Error if we timeouts
|
|
15
15
|
*/
|
|
16
16
|
async function timeout(promise, ms, errorMessage) {
|
|
17
|
-
let timer
|
|
17
|
+
let timer;
|
|
18
18
|
|
|
19
19
|
return Promise.race([
|
|
20
20
|
new Promise((resolve, reject) => {
|
|
@@ -28,7 +28,7 @@ async function timeout(promise, ms, errorMessage) {
|
|
|
28
28
|
]);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
class MemoryReport {
|
|
31
|
+
export class MemoryReport {
|
|
32
32
|
constructor(runner, storageManager, firefoxConfig, options) {
|
|
33
33
|
this.runner = runner;
|
|
34
34
|
this.storageManager = storageManager;
|
|
@@ -91,7 +91,7 @@ class MemoryReport {
|
|
|
91
91
|
let script = `Cc['@mozilla.org/memory-info-dumper;1'].getService(Ci.nsIMemoryInfoDumper).dumpMemoryReportsToNamedFile(String.raw\`${deviceReportFilename}\`, null, null, false, ${minimizeFirst});`;
|
|
92
92
|
await timeout(
|
|
93
93
|
runner.runPrivilegedScript(script, 'Collecting memory report'),
|
|
94
|
-
|
|
94
|
+
1_200_000,
|
|
95
95
|
'Could not get memory report'
|
|
96
96
|
);
|
|
97
97
|
|
|
@@ -106,5 +106,3 @@ class MemoryReport {
|
|
|
106
106
|
return this.parse(reportFilename, subDir);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
|
|
110
|
-
module.exports = MemoryReport;
|
package/lib/firefox/perfStats.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
const log =
|
|
1
|
+
import intel from 'intel';
|
|
2
|
+
const log = intel.getLogger('browsertime.firefox');
|
|
3
3
|
|
|
4
|
-
class PerfStats {
|
|
4
|
+
export class PerfStats {
|
|
5
5
|
constructor(runner, firefoxConfig) {
|
|
6
6
|
this.runner = runner;
|
|
7
7
|
this.firefoxConfig = firefoxConfig;
|
|
@@ -56,10 +56,8 @@ class PerfStats {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
return combinedPerfStats;
|
|
59
|
-
} catch (
|
|
60
|
-
log.error('Could not collect perf stats',
|
|
59
|
+
} catch (error) {
|
|
60
|
+
log.error('Could not collect perf stats', error);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
module.exports = PerfStats;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
module.exports = {
|
|
1
|
+
export default {
|
|
4
2
|
// Common preferences file used by both unittest and perf harnesses.
|
|
5
3
|
'app.update.checkInstallTime': false,
|
|
6
4
|
'app.update.disabledForTesting': true,
|
|
@@ -139,7 +137,7 @@ module.exports = {
|
|
|
139
137
|
// int32_t) to avoid it kicking in during tests. The maintenance can take a
|
|
140
138
|
// relatively long time which may cause unnecessary intermittents and slow down
|
|
141
139
|
// tests. This, like many things, will stop working correctly in 2038.
|
|
142
|
-
'places.database.lastMaintenance':
|
|
140
|
+
'places.database.lastMaintenance': 2_147_483_647,
|
|
143
141
|
'plugin.state.flash': 0,
|
|
144
142
|
'plugins.flashBlock.enabled': false,
|
|
145
143
|
'privacy.reduceTimerPrecision': false, // Bug 1445243 - reduces precision of tests
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
desktop_sampling_interval: 1,
|
|
7
|
-
android_sampling_interval: 4,
|
|
8
|
-
bufferSize: 13107200 // 100MB
|
|
9
|
-
};
|
|
1
|
+
export const features = 'js,stackwalk,leaf';
|
|
2
|
+
export const threads = 'GeckoMain,Compositor,Renderer';
|
|
3
|
+
export const desktop_sampling_interval = 1;
|
|
4
|
+
export const android_sampling_interval = 4;
|
|
5
|
+
export const bufferSize = 13_107_200; // 100MB;
|
|
@@ -1,30 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import {
|
|
5
|
+
ServiceBuilder,
|
|
6
|
+
Options,
|
|
7
|
+
Channel
|
|
8
|
+
} from 'selenium-webdriver/firefox.js';
|
|
9
|
+
import intel from 'intel';
|
|
10
|
+
import { pac, manual } from 'selenium-webdriver/proxy.js';
|
|
11
|
+
import pick from 'lodash.pick';
|
|
12
|
+
import isEmpty from 'lodash.isempty';
|
|
13
|
+
import get from 'lodash.get';
|
|
14
|
+
import defaultFirefoxPreferences from '../settings/firefoxPreferences.js';
|
|
15
|
+
import disableSafeBrowsingPreferences from '../settings/disableSafeBrowsingPreferences.js';
|
|
16
|
+
import disableTrackingProtectionPreferences from '../settings/disableTrackingProtectionPreferences.js';
|
|
17
|
+
import { toArray } from '../../support/util.js';
|
|
18
|
+
import { Android, isAndroidConfigured } from '../../android/index.js';
|
|
19
|
+
const log = intel.getLogger('browsertime.firefox');
|
|
20
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
|
|
22
|
+
export async function configureBuilder(builder, baseDir, options) {
|
|
17
23
|
// Here we configure everything that we need to start Firefox
|
|
18
24
|
const firefoxConfig = options.firefox || {};
|
|
19
|
-
const moduleRootPath =
|
|
25
|
+
const moduleRootPath = resolve(__dirname, '..', '..', '..');
|
|
20
26
|
|
|
21
27
|
let geckodriverPath = get(firefoxConfig, 'geckodriverPath');
|
|
22
28
|
if (!geckodriverPath) {
|
|
23
|
-
const geckodriver =
|
|
24
|
-
geckodriverPath = geckodriver.binPath();
|
|
29
|
+
const geckodriver = await import('@sitespeed.io/geckodriver');
|
|
30
|
+
geckodriverPath = geckodriver.default.binPath();
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
const serviceBuilder = new
|
|
33
|
+
const serviceBuilder = new ServiceBuilder(geckodriverPath);
|
|
28
34
|
if (options.verbose >= 2) {
|
|
29
35
|
// This echoes the output from geckodriver to the console.
|
|
30
36
|
serviceBuilder.setStdio('inherit');
|
|
@@ -35,19 +41,20 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
// https://firefox-source-docs.mozilla.org/testing/geckodriver/Flags.html
|
|
38
|
-
let
|
|
39
|
-
if (
|
|
40
|
-
if (!Array.isArray(
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
let geckodriverArguments = get(firefoxConfig, 'geckodriverArgs');
|
|
45
|
+
if (geckodriverArguments) {
|
|
46
|
+
if (!Array.isArray(geckodriverArguments))
|
|
47
|
+
geckodriverArguments = [geckodriverArguments];
|
|
48
|
+
for (let argument of geckodriverArguments) {
|
|
49
|
+
serviceBuilder.addArguments(argument);
|
|
43
50
|
}
|
|
44
51
|
}
|
|
45
52
|
|
|
46
53
|
builder.setFirefoxService(serviceBuilder);
|
|
47
54
|
|
|
48
|
-
const ffOptions = new
|
|
55
|
+
const ffOptions = new Options();
|
|
49
56
|
|
|
50
|
-
const profileTemplatePath =
|
|
57
|
+
const profileTemplatePath = resolve(
|
|
51
58
|
moduleRootPath,
|
|
52
59
|
'browsersupport',
|
|
53
60
|
'firefox-profile'
|
|
@@ -69,7 +76,7 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
69
76
|
// Output the window recorder image frames to a base directory.
|
|
70
77
|
// This pref expects a trailing slash.
|
|
71
78
|
if (firefoxConfig.windowRecorder) {
|
|
72
|
-
if (options
|
|
79
|
+
if (isAndroidConfigured(options)) {
|
|
73
80
|
const android = new Android(options);
|
|
74
81
|
const pathToRecording = android.getFullPathOnSdCard(
|
|
75
82
|
'browsertime-firefox-windowrecording'
|
|
@@ -84,23 +91,23 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
if (!firefoxConfig.noDefaultPrefs) {
|
|
87
|
-
Object.keys(defaultFirefoxPreferences)
|
|
94
|
+
for (const pref of Object.keys(defaultFirefoxPreferences)) {
|
|
88
95
|
ffOptions.setPreference(pref, defaultFirefoxPreferences[pref]);
|
|
89
|
-
}
|
|
96
|
+
}
|
|
90
97
|
} else {
|
|
91
98
|
log.info('Skip setting default preferences for Firefox');
|
|
92
99
|
}
|
|
93
100
|
|
|
94
101
|
if (firefoxConfig.disableSafeBrowsing) {
|
|
95
|
-
Object.keys(disableSafeBrowsingPreferences)
|
|
102
|
+
for (const pref of Object.keys(disableSafeBrowsingPreferences)) {
|
|
96
103
|
ffOptions.setPreference(pref, disableSafeBrowsingPreferences[pref]);
|
|
97
|
-
}
|
|
104
|
+
}
|
|
98
105
|
}
|
|
99
106
|
|
|
100
107
|
if (firefoxConfig.disableTrackingProtection) {
|
|
101
|
-
Object.keys(disableTrackingProtectionPreferences)
|
|
108
|
+
for (const pref of Object.keys(disableTrackingProtectionPreferences)) {
|
|
102
109
|
ffOptions.setPreference(pref, disableTrackingProtectionPreferences[pref]);
|
|
103
|
-
}
|
|
110
|
+
}
|
|
104
111
|
}
|
|
105
112
|
|
|
106
113
|
if (options.debug) {
|
|
@@ -110,7 +117,7 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
110
117
|
}
|
|
111
118
|
|
|
112
119
|
if (!options.skipHar) {
|
|
113
|
-
if (options
|
|
120
|
+
if (isAndroidConfigured(options)) {
|
|
114
121
|
log.info('Skip install HAR trigger on Android');
|
|
115
122
|
} else {
|
|
116
123
|
// Hack for opening the toolbar
|
|
@@ -122,11 +129,7 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
ffOptions.addExtensions(
|
|
125
|
-
|
|
126
|
-
moduleRootPath,
|
|
127
|
-
'vendor',
|
|
128
|
-
'har_export_trigger-0.6.1-an+fx.xpi'
|
|
129
|
-
)
|
|
132
|
+
resolve(moduleRootPath, 'vendor', 'har_export_trigger-0.6.1-an+fx.xpi')
|
|
130
133
|
);
|
|
131
134
|
}
|
|
132
135
|
}
|
|
@@ -136,7 +139,7 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
136
139
|
|
|
137
140
|
if (!firefoxConfig.disableBrowsertimeExtension) {
|
|
138
141
|
ffOptions.addExtensions(
|
|
139
|
-
|
|
142
|
+
resolve(moduleRootPath, 'vendor', 'browsertime-0.18.0-an+fx.xpi')
|
|
140
143
|
);
|
|
141
144
|
}
|
|
142
145
|
|
|
@@ -151,16 +154,16 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
151
154
|
|
|
152
155
|
ffOptions.setPreference('devtools.chrome.enabled', true);
|
|
153
156
|
|
|
154
|
-
const userPrefs =
|
|
157
|
+
const userPrefs = toArray(firefoxConfig.preference);
|
|
155
158
|
log.debug('Set Firefox preference %j', userPrefs);
|
|
156
159
|
for (const pref of userPrefs) {
|
|
157
|
-
const name = pref.
|
|
158
|
-
let value = pref.
|
|
160
|
+
const name = pref.slice(0, Math.max(0, pref.indexOf(':')));
|
|
161
|
+
let value = pref.slice(pref.indexOf(':') + 1);
|
|
159
162
|
if (value === 'false') {
|
|
160
163
|
ffOptions.setPreference(name, false);
|
|
161
164
|
} else if (value === 'true') {
|
|
162
165
|
ffOptions.setPreference(name, true);
|
|
163
|
-
} else if (isNaN(value)) {
|
|
166
|
+
} else if (Number.isNaN(value)) {
|
|
164
167
|
ffOptions.setPreference(name, value);
|
|
165
168
|
} else {
|
|
166
169
|
ffOptions.setPreference(name, Number(value));
|
|
@@ -168,12 +171,10 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
168
171
|
}
|
|
169
172
|
|
|
170
173
|
let firefoxTypes = [
|
|
171
|
-
get(firefoxConfig, 'binaryPath')
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
get(firefoxConfig, '
|
|
175
|
-
get(firefoxConfig, 'beta') ? firefox.Channel.BETA : undefined,
|
|
176
|
-
get(firefoxConfig, 'developer') ? firefox.Channel.AURORA : undefined
|
|
174
|
+
get(firefoxConfig, 'binaryPath') ?? undefined,
|
|
175
|
+
get(firefoxConfig, 'nightly') ? Channel.NIGHTLY : undefined,
|
|
176
|
+
get(firefoxConfig, 'beta') ? Channel.BETA : undefined,
|
|
177
|
+
get(firefoxConfig, 'developer') ? Channel.AURORA : undefined
|
|
177
178
|
];
|
|
178
179
|
|
|
179
180
|
firefoxTypes = firefoxTypes.filter(function (n) {
|
|
@@ -183,9 +184,9 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
183
184
|
// Do not set binary when using Android
|
|
184
185
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1751196
|
|
185
186
|
|
|
186
|
-
if (!options
|
|
187
|
+
if (!isAndroidConfigured(options)) {
|
|
187
188
|
ffOptions.setBinary(
|
|
188
|
-
firefoxTypes.length > 0 ? firefoxTypes[0] :
|
|
189
|
+
firefoxTypes.length > 0 ? firefoxTypes[0] : Channel.RELEASE
|
|
189
190
|
);
|
|
190
191
|
}
|
|
191
192
|
|
|
@@ -195,12 +196,12 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
195
196
|
ffOptions.addArguments(firefoxConfig.args);
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
const
|
|
199
|
+
const environments = toArray(firefoxConfig.env);
|
|
199
200
|
ffOptions.firefoxOptions_().env = ffOptions.firefoxOptions_().env || {};
|
|
200
|
-
for (const
|
|
201
|
-
const name =
|
|
202
|
-
const value =
|
|
203
|
-
if (options
|
|
201
|
+
for (const environment of environments) {
|
|
202
|
+
const name = environment.slice(0, Math.max(0, environment.indexOf('=')));
|
|
203
|
+
const value = environment.slice(environment.indexOf('=') + 1);
|
|
204
|
+
if (isAndroidConfigured(options)) {
|
|
204
205
|
ffOptions.firefoxOptions_().env[name] = value;
|
|
205
206
|
} else {
|
|
206
207
|
process.env[name] = value;
|
|
@@ -219,7 +220,7 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
219
220
|
.getCapabilities()
|
|
220
221
|
.set('pageLoadStrategy', get(options, 'pageLoadStrategy', 'normal'));
|
|
221
222
|
|
|
222
|
-
if (options
|
|
223
|
+
if (isAndroidConfigured(options)) {
|
|
223
224
|
// Monkey patch to avoid changing `selenium-webdriver` before the
|
|
224
225
|
// corresponding `geckodriver` functionality has been replaced:
|
|
225
226
|
// see this [Firefox bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1525126)
|
|
@@ -249,21 +250,23 @@ module.exports.configureBuilder = function (builder, baseDir, options) {
|
|
|
249
250
|
if (android && android.intentArgument) {
|
|
250
251
|
ffOptions.firefoxOptions_().androidIntentArguments = (
|
|
251
252
|
ffOptions.firefoxOptions_().androidIntentArguments || []
|
|
252
|
-
)
|
|
253
|
+
)
|
|
254
|
+
// eslint-disable-next-line unicorn/prefer-spread
|
|
255
|
+
.concat(...toArray(android.intentArgument));
|
|
253
256
|
}
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
const proxyPacSettings = pick(options.proxy, ['pac']);
|
|
257
260
|
|
|
258
261
|
if (!isEmpty(proxyPacSettings)) {
|
|
259
|
-
builder.setProxy(
|
|
262
|
+
builder.setProxy(pac(proxyPacSettings));
|
|
260
263
|
}
|
|
261
264
|
|
|
262
265
|
const proxySettings = pick(options.proxy, ['ftp', 'http', 'https', 'bypass']);
|
|
263
266
|
|
|
264
267
|
if (!isEmpty(proxySettings)) {
|
|
265
|
-
builder.setProxy(
|
|
268
|
+
builder.setProxy(manual(proxySettings));
|
|
266
269
|
}
|
|
267
270
|
|
|
268
271
|
builder.setFirefoxOptions(ffOptions);
|
|
269
|
-
}
|
|
272
|
+
}
|