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
package/lib/support/cli.js
CHANGED
|
@@ -1,23 +1,34 @@
|
|
|
1
|
-
|
|
1
|
+
import { format } from 'node:util';
|
|
2
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import yargs from 'yargs';
|
|
4
|
+
import { hideBin } from 'yargs/helpers';
|
|
5
|
+
import { findUpSync } from 'find-up';
|
|
6
|
+
import get from 'lodash.get';
|
|
7
|
+
import set from 'lodash.set';
|
|
8
|
+
import hasbin from 'hasbin';
|
|
9
|
+
import {
|
|
10
|
+
framerate,
|
|
11
|
+
crf,
|
|
12
|
+
addTimer,
|
|
13
|
+
threads,
|
|
14
|
+
xvfbDisplay
|
|
15
|
+
} from '../video/defaults.js';
|
|
16
|
+
import SCREENSHOT from '../screenshot/defaults.js';
|
|
17
|
+
import {
|
|
18
|
+
features,
|
|
19
|
+
threads as _threads,
|
|
20
|
+
desktop_sampling_interval,
|
|
21
|
+
android_sampling_interval,
|
|
22
|
+
bufferSize
|
|
23
|
+
} from '../firefox/settings/geckoProfilerDefaults.js';
|
|
2
24
|
|
|
3
|
-
const
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const findUp = require('find-up');
|
|
6
|
-
const get = require('lodash.get');
|
|
7
|
-
const set = require('lodash.set');
|
|
8
|
-
const util = require('util');
|
|
9
|
-
const hasbin = require('hasbin');
|
|
10
|
-
const videoDefaults = require('../video/defaults');
|
|
11
|
-
const screenshotDefaults = require('../screenshot/defaults');
|
|
12
|
-
const geckoProfilerDefaults = require('../firefox/settings/geckoProfilerDefaults');
|
|
25
|
+
const configPath = findUpSync(['.browsertime.json']);
|
|
13
26
|
|
|
14
|
-
const configPath = findUp.sync(['.browsertime.json']);
|
|
15
27
|
let config;
|
|
16
|
-
|
|
17
28
|
try {
|
|
18
|
-
config = configPath ? JSON.parse(
|
|
19
|
-
} catch (
|
|
20
|
-
if (
|
|
29
|
+
config = configPath ? JSON.parse(readFileSync(configPath)) : {};
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error instanceof SyntaxError) {
|
|
21
32
|
/* eslint no-console: off */
|
|
22
33
|
console.error(
|
|
23
34
|
'Could not parse the config JSON file ' +
|
|
@@ -25,13 +36,13 @@ try {
|
|
|
25
36
|
'. Is the file really valid JSON?'
|
|
26
37
|
);
|
|
27
38
|
}
|
|
28
|
-
throw
|
|
39
|
+
throw error;
|
|
29
40
|
}
|
|
30
41
|
|
|
31
42
|
function validateInput(argv) {
|
|
32
43
|
// Check NodeJS major version
|
|
33
44
|
const fullVersion = process.versions.node;
|
|
34
|
-
const minVersion =
|
|
45
|
+
const minVersion = 14;
|
|
35
46
|
const majorVersion = fullVersion.split('.')[0];
|
|
36
47
|
if (majorVersion < minVersion) {
|
|
37
48
|
return (
|
|
@@ -48,9 +59,9 @@ function validateInput(argv) {
|
|
|
48
59
|
if (!urlOrFile.startsWith('http')) {
|
|
49
60
|
// is existing file?
|
|
50
61
|
try {
|
|
51
|
-
|
|
52
|
-
} catch
|
|
53
|
-
return
|
|
62
|
+
statSync(urlOrFile);
|
|
63
|
+
} catch {
|
|
64
|
+
return format(
|
|
54
65
|
"'%s' does not exist, is the path to the file correct?",
|
|
55
66
|
urlOrFile
|
|
56
67
|
);
|
|
@@ -65,10 +76,8 @@ function validateInput(argv) {
|
|
|
65
76
|
}
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
if (argv.video || argv.visualMetrics) {
|
|
69
|
-
|
|
70
|
-
return 'You need to have ffmpeg in your path to be able to record a video.';
|
|
71
|
-
}
|
|
79
|
+
if ((argv.video || argv.visualMetrics) && !hasbin.sync(['ffmpeg'])) {
|
|
80
|
+
return 'You need to have ffmpeg in your path to be able to record a video.';
|
|
72
81
|
}
|
|
73
82
|
|
|
74
83
|
if (argv.safari && argv.safari.useSimulator && !argv.safari.deviceUDID) {
|
|
@@ -87,22 +96,20 @@ function validateInput(argv) {
|
|
|
87
96
|
return 'There is no benefit running debug mode inside a Docker container.';
|
|
88
97
|
}
|
|
89
98
|
|
|
90
|
-
if (argv.tcpdump) {
|
|
91
|
-
|
|
92
|
-
return 'You need to have tcpdump in your path to be able to record a tcpdump.';
|
|
93
|
-
}
|
|
99
|
+
if (argv.tcpdump && !hasbin.sync(['tcpdump'])) {
|
|
100
|
+
return 'You need to have tcpdump in your path to be able to record a tcpdump.';
|
|
94
101
|
}
|
|
95
102
|
|
|
96
|
-
if (argv.gnirehtet) {
|
|
97
|
-
|
|
98
|
-
return 'You need to have gnirehtet in your path to be able to use it. If you run on a Mac you can install it using Homebrew: brew install gnirehtet';
|
|
99
|
-
}
|
|
103
|
+
if (argv.gnirehtet && !hasbin.sync(['gnirehtet'])) {
|
|
104
|
+
return 'You need to have gnirehtet in your path to be able to use it. If you run on a Mac you can install it using Homebrew: brew install gnirehtet';
|
|
100
105
|
}
|
|
101
106
|
|
|
102
|
-
if (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
if (
|
|
108
|
+
argv.connectivity &&
|
|
109
|
+
argv.connectivity.engine === 'humble' &&
|
|
110
|
+
(!argv.connectivity.humble || !argv.connectivity.humble.url)
|
|
111
|
+
) {
|
|
112
|
+
return 'You need to specify the URL to Humble by using the --connectivity.humble.url option.';
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
if (
|
|
@@ -137,33 +144,34 @@ function validateInput(argv) {
|
|
|
137
144
|
return true;
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
|
|
141
|
-
let
|
|
147
|
+
export function parseCommandLine() {
|
|
148
|
+
let yargsInstance = yargs(hideBin(process.argv));
|
|
149
|
+
let validated = yargsInstance
|
|
142
150
|
.parserConfiguration({ 'deep-merge-config': true })
|
|
143
151
|
.env('BROWSERTIME')
|
|
144
152
|
.usage('$0 [options] <url>/<scriptFile>')
|
|
145
153
|
.require(1, 'One or more url or script files')
|
|
146
154
|
.option('timeouts.browserStart', {
|
|
147
|
-
default:
|
|
155
|
+
default: 60_000,
|
|
148
156
|
type: 'number',
|
|
149
157
|
describe: 'Timeout when waiting for browser to start, in milliseconds',
|
|
150
158
|
group: 'timeouts'
|
|
151
159
|
})
|
|
152
160
|
.option('timeouts.pageLoad', {
|
|
153
|
-
default:
|
|
161
|
+
default: 300_000,
|
|
154
162
|
type: 'number',
|
|
155
163
|
describe: 'Timeout when waiting for url to load, in milliseconds',
|
|
156
164
|
group: 'timeouts'
|
|
157
165
|
})
|
|
158
166
|
.option('timeouts.script', {
|
|
159
|
-
default:
|
|
167
|
+
default: 120_000,
|
|
160
168
|
type: 'number',
|
|
161
169
|
describe: 'Timeout when running browser scripts, in milliseconds',
|
|
162
170
|
group: 'timeouts'
|
|
163
171
|
})
|
|
164
172
|
.option('timeouts.pageCompleteCheck', {
|
|
165
173
|
alias: 'maxLoadTime',
|
|
166
|
-
default:
|
|
174
|
+
default: 120_000,
|
|
167
175
|
type: 'number',
|
|
168
176
|
describe:
|
|
169
177
|
'Timeout when waiting for page to complete loading, in milliseconds',
|
|
@@ -311,11 +319,13 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
311
319
|
describe:
|
|
312
320
|
'Easy way to enable both chrome.timeline for Chrome and geckoProfile for Firefox'
|
|
313
321
|
})
|
|
314
|
-
.option('
|
|
322
|
+
.option('android.powerTesting', {
|
|
323
|
+
alias: 'androidPower',
|
|
315
324
|
type: 'boolean',
|
|
316
325
|
describe:
|
|
317
326
|
'Enables android power testing - charging must be disabled for this.' +
|
|
318
|
-
'(You have to disable charging yourself for this - it depends on the phone model).'
|
|
327
|
+
'(You have to disable charging yourself for this - it depends on the phone model).',
|
|
328
|
+
group: 'android'
|
|
319
329
|
})
|
|
320
330
|
.option('chrome.CPUThrottlingRate', {
|
|
321
331
|
type: 'number',
|
|
@@ -458,24 +468,24 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
458
468
|
})
|
|
459
469
|
.option('firefox.geckoProfilerParams.features', {
|
|
460
470
|
describe: 'Enabled features during gecko profiling',
|
|
461
|
-
default:
|
|
471
|
+
default: features,
|
|
462
472
|
type: 'string',
|
|
463
473
|
group: 'firefox'
|
|
464
474
|
})
|
|
465
475
|
.option('firefox.geckoProfilerParams.threads', {
|
|
466
476
|
describe: 'Threads to profile.',
|
|
467
|
-
default:
|
|
477
|
+
default: _threads,
|
|
468
478
|
type: 'string',
|
|
469
479
|
group: 'firefox'
|
|
470
480
|
})
|
|
471
481
|
.option('firefox.geckoProfilerParams.interval', {
|
|
472
|
-
describe: `Sampling interval in ms. Defaults to ${
|
|
482
|
+
describe: `Sampling interval in ms. Defaults to ${desktop_sampling_interval} on desktop, and ${android_sampling_interval} on android.`,
|
|
473
483
|
type: 'number',
|
|
474
484
|
group: 'firefox'
|
|
475
485
|
})
|
|
476
486
|
.option('firefox.geckoProfilerParams.bufferSize', {
|
|
477
487
|
describe: 'Buffer size in elements. Default is ~90MB.',
|
|
478
|
-
default:
|
|
488
|
+
default: bufferSize,
|
|
479
489
|
type: 'number',
|
|
480
490
|
group: 'firefox'
|
|
481
491
|
})
|
|
@@ -488,7 +498,8 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
488
498
|
})
|
|
489
499
|
.option('firefox.perfStatsParams.mask', {
|
|
490
500
|
describe: 'Mask to decide which features to enable',
|
|
491
|
-
|
|
501
|
+
// eslint-disable-next-line prettier/prettier
|
|
502
|
+
default: 0xFF_FF_FF_FF,
|
|
492
503
|
type: 'number',
|
|
493
504
|
group: 'firefox'
|
|
494
505
|
})
|
|
@@ -567,19 +578,19 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
567
578
|
'Record a video and store the video. Set it to false to remove the video that is created by turning on visualMetrics. To remove fully turn off video recordings, make sure to set video and visualMetrics to false. Requires FFMpeg to be installed.'
|
|
568
579
|
})
|
|
569
580
|
.option('videoParams.framerate', {
|
|
570
|
-
default:
|
|
581
|
+
default: framerate,
|
|
571
582
|
describe: 'Frames per second',
|
|
572
583
|
group: 'video'
|
|
573
584
|
})
|
|
574
585
|
.option('videoParams.crf', {
|
|
575
|
-
default:
|
|
586
|
+
default: crf,
|
|
576
587
|
describe:
|
|
577
588
|
'Constant rate factor see https://trac.ffmpeg.org/wiki/Encode/H.264#crf',
|
|
578
589
|
group: 'video'
|
|
579
590
|
})
|
|
580
591
|
.option('videoParams.addTimer', {
|
|
581
592
|
type: 'boolean',
|
|
582
|
-
default:
|
|
593
|
+
default: addTimer,
|
|
583
594
|
describe: 'Add timer and metrics to the video.',
|
|
584
595
|
group: 'video'
|
|
585
596
|
})
|
|
@@ -635,7 +646,7 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
635
646
|
group: 'video'
|
|
636
647
|
})
|
|
637
648
|
.option('videoParams.threads', {
|
|
638
|
-
default:
|
|
649
|
+
default: threads,
|
|
639
650
|
describe:
|
|
640
651
|
'Number of threads to use for video recording. Default is determined by ffmpeg.',
|
|
641
652
|
group: 'video'
|
|
@@ -661,6 +672,7 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
661
672
|
})
|
|
662
673
|
.option('visualMetricsPortable', {
|
|
663
674
|
type: 'boolean',
|
|
675
|
+
default: true,
|
|
664
676
|
describe:
|
|
665
677
|
'Use the portable visual-metrics processing script (no ImageMagick dependencies).'
|
|
666
678
|
})
|
|
@@ -682,50 +694,71 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
682
694
|
describe:
|
|
683
695
|
'Specify browser. Safari only works on OS X/iOS. Edge only work on OS that supports Edge.'
|
|
684
696
|
})
|
|
697
|
+
.option('android.ignoreShutdownFailures', {
|
|
698
|
+
alias: 'ignoreShutdownFailures',
|
|
699
|
+
type: 'boolean',
|
|
700
|
+
default: false,
|
|
701
|
+
describe: 'If set, shutdown failures will be ignored on Android.',
|
|
702
|
+
group: 'android'
|
|
703
|
+
})
|
|
685
704
|
.option('android', {
|
|
686
705
|
type: 'boolean',
|
|
687
706
|
default: false,
|
|
688
707
|
describe:
|
|
689
708
|
'Short key to use Android. Defaults to use com.android.chrome unless --browser is specified.'
|
|
690
709
|
})
|
|
691
|
-
.option('
|
|
710
|
+
.option('android.rooted', {
|
|
692
711
|
type: 'boolean',
|
|
712
|
+
alias: 'androidRooted',
|
|
693
713
|
default: false,
|
|
694
714
|
describe:
|
|
695
|
-
'If your phone is rooted you can use this to set it up following Mozillas best practice for stable metrics.'
|
|
715
|
+
'If your phone is rooted you can use this to set it up following Mozillas best practice for stable metrics.',
|
|
716
|
+
group: 'android'
|
|
696
717
|
})
|
|
697
|
-
.option('
|
|
718
|
+
.option('android.batteryTemperatureLimit', {
|
|
719
|
+
alias: 'androidBatteryTemperatureLimit',
|
|
698
720
|
type: 'integer',
|
|
699
721
|
describe:
|
|
700
|
-
'Do the battery temperature need to be below a specific limit before we start the test?'
|
|
722
|
+
'Do the battery temperature need to be below a specific limit before we start the test?',
|
|
723
|
+
group: 'android'
|
|
701
724
|
})
|
|
702
|
-
.option('
|
|
725
|
+
.option('android.batteryTemperatureWaitTimeInSeconds', {
|
|
726
|
+
alias: 'androidBatteryTemperatureWaitTimeInSeconds',
|
|
703
727
|
type: 'integer',
|
|
704
728
|
default: 120,
|
|
705
729
|
describe:
|
|
706
|
-
'How long time to wait (in seconds) if the androidBatteryTemperatureWaitTimeInSeconds is not met before the next try'
|
|
730
|
+
'How long time to wait (in seconds) if the androidBatteryTemperatureWaitTimeInSeconds is not met before the next try',
|
|
731
|
+
group: 'android'
|
|
707
732
|
})
|
|
708
|
-
.option('
|
|
733
|
+
.option('android.batteryTemperatureReboot', {
|
|
734
|
+
alias: 'androidBatteryTemperatureReboot',
|
|
709
735
|
type: 'boolean',
|
|
710
736
|
default: false,
|
|
711
737
|
describe:
|
|
712
|
-
'If your phone does not get the minimum temperature aftet the wait time, reboot the phone.'
|
|
738
|
+
'If your phone does not get the minimum temperature aftet the wait time, reboot the phone.',
|
|
739
|
+
group: 'android'
|
|
713
740
|
})
|
|
714
|
-
.option('
|
|
741
|
+
.option('android.pretestPowerPress', {
|
|
742
|
+
alias: 'androidPretestPowerPress',
|
|
715
743
|
type: 'boolean',
|
|
716
744
|
default: false,
|
|
717
|
-
describe: 'Press the power button on the phone before a test starts.'
|
|
745
|
+
describe: 'Press the power button on the phone before a test starts.',
|
|
746
|
+
group: 'android'
|
|
718
747
|
})
|
|
719
|
-
.option('
|
|
748
|
+
.option('android.pretestPressHomeButton', {
|
|
749
|
+
alias: 'androidPretestPressHomeButton',
|
|
720
750
|
type: 'boolean',
|
|
721
751
|
default: false,
|
|
722
|
-
describe: 'Press the home button on the phone before a test starts.'
|
|
752
|
+
describe: 'Press the home button on the phone before a test starts.',
|
|
753
|
+
group: 'android'
|
|
723
754
|
})
|
|
724
|
-
.option('
|
|
755
|
+
.option('android.verifyNetwork', {
|
|
756
|
+
alias: 'androidVerifyNetwork',
|
|
725
757
|
type: 'boolean',
|
|
726
758
|
default: false,
|
|
727
759
|
describe:
|
|
728
|
-
'Before a test start, verify that the device has a Internet connection by pinging 8.8.8.8 (or a configurable domain with --androidPingAddress)'
|
|
760
|
+
'Before a test start, verify that the device has a Internet connection by pinging 8.8.8.8 (or a configurable domain with --androidPingAddress)',
|
|
761
|
+
group: 'android'
|
|
729
762
|
})
|
|
730
763
|
/** Process start time. Android-only for now. */
|
|
731
764
|
.option('processStartTime', {
|
|
@@ -807,22 +840,22 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
807
840
|
.option('screenshotParams.type', {
|
|
808
841
|
describe: 'Set the file type of the screenshot',
|
|
809
842
|
choices: ['png', 'jpg'],
|
|
810
|
-
default:
|
|
843
|
+
default: SCREENSHOT.type,
|
|
811
844
|
group: 'Screenshot'
|
|
812
845
|
})
|
|
813
846
|
.option('screenshotParams.png.compressionLevel', {
|
|
814
847
|
describe: 'zlib compression level',
|
|
815
|
-
default:
|
|
848
|
+
default: SCREENSHOT.png.compressionLevel,
|
|
816
849
|
group: 'Screenshot'
|
|
817
850
|
})
|
|
818
851
|
.option('screenshotParams.jpg.quality', {
|
|
819
852
|
describe: 'Quality of the JPEG screenshot. 1-100',
|
|
820
|
-
default:
|
|
853
|
+
default: SCREENSHOT.jpg.quality,
|
|
821
854
|
group: 'Screenshot'
|
|
822
855
|
})
|
|
823
856
|
.option('screenshotParams.maxSize', {
|
|
824
857
|
describe: 'The max size of the screenshot (width and height).',
|
|
825
|
-
default:
|
|
858
|
+
default: SCREENSHOT.maxSize,
|
|
826
859
|
group: 'Screenshot'
|
|
827
860
|
})
|
|
828
861
|
.option('pageCompleteCheck', {
|
|
@@ -1096,7 +1129,7 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1096
1129
|
describe: 'Start xvfb before the browser is started'
|
|
1097
1130
|
})
|
|
1098
1131
|
.option('xvfbParams.display', {
|
|
1099
|
-
default:
|
|
1132
|
+
default: xvfbDisplay,
|
|
1100
1133
|
describe: 'The display used for xvfb'
|
|
1101
1134
|
})
|
|
1102
1135
|
.option('tcpdump', {
|
|
@@ -1137,11 +1170,13 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1137
1170
|
describe:
|
|
1138
1171
|
'Run the browser in headless mode. Works for Firefox and Chrome.'
|
|
1139
1172
|
})
|
|
1140
|
-
.option('gnirehtet', {
|
|
1173
|
+
.option('android.gnirehtet', {
|
|
1174
|
+
alias: 'gnirehtet',
|
|
1141
1175
|
type: 'boolean',
|
|
1142
1176
|
default: false,
|
|
1143
1177
|
describe:
|
|
1144
|
-
'Start gnirehtet and reverse tethering the traffic from your Android phone.'
|
|
1178
|
+
'Start gnirehtet and reverse tethering the traffic from your Android phone.',
|
|
1179
|
+
group: 'android'
|
|
1145
1180
|
})
|
|
1146
1181
|
.option('flushDNS', {
|
|
1147
1182
|
type: 'boolean',
|
|
@@ -1191,18 +1226,21 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1191
1226
|
.alias('h', 'help')
|
|
1192
1227
|
.alias('V', 'version')
|
|
1193
1228
|
.alias('v', 'verbose')
|
|
1229
|
+
.wrap(yargsInstance.terminalWidth())
|
|
1194
1230
|
.check(validateInput);
|
|
1195
1231
|
|
|
1196
|
-
validated.wrap(yargs.terminalWidth());
|
|
1197
|
-
|
|
1198
1232
|
let argv = validated.argv;
|
|
1199
1233
|
|
|
1234
|
+
// hack to keep backward compability to --android
|
|
1235
|
+
if (argv.android[0] === true) {
|
|
1236
|
+
set(argv, 'android.enabled', true);
|
|
1237
|
+
}
|
|
1200
1238
|
if (
|
|
1201
1239
|
argv.firefox &&
|
|
1202
1240
|
(argv.firefox.nightly || argv.firefox.beta || argv.firefox.developer)
|
|
1203
1241
|
) {
|
|
1204
1242
|
argv.browser = 'firefox';
|
|
1205
|
-
if (argv.android) {
|
|
1243
|
+
if (argv.android.enabled) {
|
|
1206
1244
|
// TODO add support for Firefox dev
|
|
1207
1245
|
set(
|
|
1208
1246
|
argv,
|
|
@@ -1220,7 +1258,7 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1220
1258
|
|
|
1221
1259
|
if (argv.ios) {
|
|
1222
1260
|
set(argv, 'safari.ios', true);
|
|
1223
|
-
} else if (argv.android) {
|
|
1261
|
+
} else if (argv.android.enabled) {
|
|
1224
1262
|
if (argv.browser === 'chrome') {
|
|
1225
1263
|
// Default to Chrome Android.
|
|
1226
1264
|
set(
|
|
@@ -1257,8 +1295,8 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1257
1295
|
|
|
1258
1296
|
if (!Array.isArray(argv.urlAlias)) argv.urlAlias = [argv.urlAlias];
|
|
1259
1297
|
|
|
1260
|
-
for (
|
|
1261
|
-
urlMetaData[
|
|
1298
|
+
for (const [index, url] of urls.entries()) {
|
|
1299
|
+
urlMetaData[url] = argv.urlAlias[index];
|
|
1262
1300
|
}
|
|
1263
1301
|
set(argv, 'urlMetaData', urlMetaData);
|
|
1264
1302
|
}
|
|
@@ -1279,13 +1317,13 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|
|
1279
1317
|
|
|
1280
1318
|
// Set the timeouts to a maximum while debugging
|
|
1281
1319
|
if (argv.debug) {
|
|
1282
|
-
set(argv, 'timeouts.pageload',
|
|
1283
|
-
set(argv, 'timeouts.script',
|
|
1284
|
-
set(argv, 'timeouts.pageCompleteCheck',
|
|
1320
|
+
set(argv, 'timeouts.pageload', 2_147_483_647);
|
|
1321
|
+
set(argv, 'timeouts.script', 2_147_483_647);
|
|
1322
|
+
set(argv, 'timeouts.pageCompleteCheck', 2_147_483_647);
|
|
1285
1323
|
}
|
|
1286
1324
|
|
|
1287
1325
|
return {
|
|
1288
1326
|
urls: argv._,
|
|
1289
1327
|
options: argv
|
|
1290
1328
|
};
|
|
1291
|
-
}
|
|
1329
|
+
}
|
package/lib/support/dns.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import intel from 'intel';
|
|
3
|
+
import { isAndroidConfigured } from '../android/index.js';
|
|
4
|
+
const log = intel.getLogger('browsertime.dns');
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
const log = require('intel').getLogger('browsertime.dns');
|
|
5
|
-
const { isAndroidConfigured } = require('../android');
|
|
6
|
-
|
|
7
|
-
module.exports = async function (options) {
|
|
6
|
+
export default async function (options) {
|
|
8
7
|
if (isAndroidConfigured(options)) {
|
|
9
8
|
return;
|
|
10
9
|
}
|
|
@@ -36,4 +35,4 @@ module.exports = async function (options) {
|
|
|
36
35
|
reject: false
|
|
37
36
|
});
|
|
38
37
|
}
|
|
39
|
-
}
|
|
38
|
+
}
|
|
@@ -1,46 +1,93 @@
|
|
|
1
|
-
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
import intel from 'intel';
|
|
5
|
+
import { toArray } from '../support/util.js';
|
|
6
|
+
import {
|
|
7
|
+
removeFile,
|
|
8
|
+
copyFile,
|
|
9
|
+
removeFileSync,
|
|
10
|
+
copyFileSync
|
|
11
|
+
} from './fileUtil.js';
|
|
12
|
+
const require = createRequire(import.meta.url);
|
|
13
|
+
const log = intel.getLogger('browsertime');
|
|
2
14
|
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const dayjs = require('dayjs');
|
|
5
|
-
const util = require('../support/util');
|
|
6
|
-
const log = require('intel').getLogger('browsertime');
|
|
7
15
|
const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
|
|
8
16
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
export function loadPrePostScriptsSync(scripts) {
|
|
18
|
+
return toArray(scripts).map(script => {
|
|
19
|
+
// if the script is an AsyncFunction, return it.
|
|
20
|
+
if (script instanceof AsyncFunction) {
|
|
21
|
+
return script;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
if (script.endsWith('.js')) {
|
|
25
|
+
const name = script + '.cjs';
|
|
26
|
+
copyFileSync(script, name);
|
|
27
|
+
const data = require(resolve(name));
|
|
28
|
+
removeFileSync(name);
|
|
29
|
+
return data;
|
|
30
|
+
} else {
|
|
31
|
+
return require(resolve(script));
|
|
22
32
|
}
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"Couldn't run pre/post script file: " + resolve(script) + ' ' + error
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function loadScriptSync(script) {
|
|
42
|
+
if (script instanceof AsyncFunction) {
|
|
43
|
+
return script;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
if (script.endsWith('.js')) {
|
|
47
|
+
const name = script + '.cjs';
|
|
48
|
+
copyFileSync(script, name);
|
|
49
|
+
const data = require(resolve(name));
|
|
50
|
+
removeFileSync(name);
|
|
51
|
+
return data;
|
|
52
|
+
} else {
|
|
53
|
+
return require(resolve(script));
|
|
54
|
+
}
|
|
55
|
+
} catch {
|
|
56
|
+
// assume the script is a valid inline script by default
|
|
57
|
+
return script;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function loadScript(script, throwError) {
|
|
62
|
+
if (script) {
|
|
63
|
+
// if the script is an AsyncFunction, return it.
|
|
64
|
+
if (script instanceof AsyncFunction) {
|
|
65
|
+
return script;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
if (script.endsWith('.js')) {
|
|
69
|
+
const name = script + '.cjs';
|
|
70
|
+
await copyFile(script, name);
|
|
71
|
+
const data = require(resolve(name));
|
|
72
|
+
await removeFile(name);
|
|
73
|
+
return data;
|
|
74
|
+
} else {
|
|
75
|
+
return require(resolve(script));
|
|
30
76
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
77
|
+
} catch (error) {
|
|
78
|
+
// assume the script is a valid inline script by default
|
|
79
|
+
if (throwError) {
|
|
80
|
+
log.error(
|
|
81
|
+
'Could not parse user script %s with error %s',
|
|
82
|
+
script,
|
|
83
|
+
error
|
|
84
|
+
);
|
|
85
|
+
throw error;
|
|
39
86
|
}
|
|
40
87
|
}
|
|
41
|
-
return script;
|
|
42
|
-
},
|
|
43
|
-
timestamp() {
|
|
44
|
-
return dayjs().format();
|
|
45
88
|
}
|
|
46
|
-
|
|
89
|
+
return script;
|
|
90
|
+
}
|
|
91
|
+
export function timestamp() {
|
|
92
|
+
return dayjs().format();
|
|
93
|
+
}
|
package/lib/support/errors.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class BrowsertimeError extends Error {
|
|
1
|
+
export class BrowsertimeError extends Error {
|
|
4
2
|
constructor(message, extra) {
|
|
5
3
|
super(message);
|
|
6
4
|
this.extra = extra || {};
|
|
@@ -8,29 +6,22 @@ class BrowsertimeError extends Error {
|
|
|
8
6
|
}
|
|
9
7
|
}
|
|
10
8
|
|
|
11
|
-
class BrowserError extends BrowsertimeError {
|
|
9
|
+
export class BrowserError extends BrowsertimeError {
|
|
12
10
|
constructor(message, extra) {
|
|
13
11
|
super(message, extra);
|
|
14
12
|
}
|
|
15
13
|
}
|
|
16
14
|
|
|
17
|
-
class UrlLoadError extends BrowsertimeError {
|
|
15
|
+
export class UrlLoadError extends BrowsertimeError {
|
|
18
16
|
constructor(message, url, extra) {
|
|
19
17
|
super(message, extra);
|
|
20
18
|
this.url = url;
|
|
21
19
|
}
|
|
22
20
|
}
|
|
23
21
|
|
|
24
|
-
class TimeoutError extends BrowsertimeError {
|
|
22
|
+
export class TimeoutError extends BrowsertimeError {
|
|
25
23
|
constructor(message, url, extra) {
|
|
26
24
|
super(message, extra);
|
|
27
25
|
this.url = url;
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
|
-
|
|
31
|
-
module.exports = {
|
|
32
|
-
BrowsertimeError,
|
|
33
|
-
BrowserError,
|
|
34
|
-
UrlLoadError,
|
|
35
|
-
TimeoutError
|
|
36
|
-
};
|