browsertime 24.0.0-alpha.2 → 24.0.0-alpha.4
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 +14 -2
- package/bin/browsertime.js +12 -13
- package/lib/android/index.js +16 -6
- package/lib/chrome/longTaskMetrics.js +8 -5
- package/lib/chrome/networkManager.js +7 -3
- package/lib/chrome/webdriver/builder.js +3 -4
- package/lib/chrome/webdriver/chromium.js +13 -4
- package/lib/connectivity/humble.js +2 -2
- package/lib/connectivity/index.js +11 -3
- package/lib/core/engine/collector.js +31 -20
- package/lib/core/engine/command/measure.js +18 -6
- package/lib/core/engine/index.js +6 -3
- package/lib/core/seleniumRunner.js +2 -2
- package/lib/edge/webdriver/builder.js +4 -5
- package/lib/firefox/geckoProfiler.js +7 -7
- package/lib/firefox/networkManager.js +7 -3
- package/lib/firefox/webdriver/builder.js +14 -12
- package/lib/firefox/webdriver/firefox.js +18 -7
- package/lib/support/cli.js +24 -21
- package/lib/support/getViewPort.js +8 -4
- package/lib/support/har/index.js +7 -4
- package/lib/support/statistics.js +8 -7
- package/lib/support/usbPower.js +11 -0
- package/lib/support/util.js +53 -0
- package/lib/support/xvfb.js +4 -4
- package/lib/video/postprocessing/finetune/index.js +3 -3
- package/lib/video/postprocessing/visualmetrics/visualMetrics.js +14 -5
- package/lib/video/screenRecording/android/recorder.js +8 -3
- package/lib/video/screenRecording/desktop/desktopRecorder.js +9 -8
- package/lib/video/video.js +2 -3
- package/package.json +4 -6
- package/types/android/index.d.ts.map +1 -1
- package/types/core/engine/command/measure.d.ts.map +1 -1
- package/types/support/getViewPort.d.ts.map +1 -1
- package/types/support/usbPower.d.ts +2 -0
- package/types/support/usbPower.d.ts.map +1 -0
- package/types/support/util.d.ts +6 -0
- package/types/support/util.d.ts.map +1 -1
- package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts.map +1 -1
- package/types/video/screenRecording/android/recorder.d.ts.map +1 -1
- package/types/video/screenRecording/desktop/desktopRecorder.d.ts.map +1 -1
- package/types/video/video.d.ts.map +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
# Browsertime changelog (we do [semantic versioning](https://semver.org))
|
|
2
2
|
|
|
3
|
-
## 24.0.0-alpha.
|
|
3
|
+
## 24.0.0-alpha.3 - 2025-01-10
|
|
4
|
+
|
|
5
|
+
The 24.0.0 release remove a lot of dependencies. Since we implemented Browsertime the first time, there are many things that are easy to do in modern NodeJS. Those things have now been implemented in Browsertime.
|
|
6
|
+
|
|
7
|
+
This release would work exactly as before, the only thing that changed is that usb-power-profiling is a optional dependency. That means that if you install using `--omit=optional` that dependency is not installed.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
* Moved usb-power-profiling to be an optional package [#2249](https://github.com/sitespeedio/browsertime/pull/2249).
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
* Edgedriver 131 [#2236](https://github.com/sitespeedio/browsertime/pull/2236).
|
|
14
|
+
|
|
4
15
|
### Fixed
|
|
5
16
|
* Replace dependencies with local implementation:
|
|
6
17
|
* Replace btoa [#2233](https://github.com/sitespeedio/browsertime/pull/2233).
|
|
@@ -14,8 +25,9 @@
|
|
|
14
25
|
* Replace jimp with jimp custom [#2243](https://github.com/sitespeedio/browsertime/pull/2243).
|
|
15
26
|
* Replace @cypress/xvfb [#2245](https://github.com/sitespeedio/browsertime/pull/2245).
|
|
16
27
|
* Replace intel (log) with sitespeed.io/log [#2246](https://github.com/sitespeedio/browsertime/pull/2246).
|
|
28
|
+
* Replace lodash.set [#2250](https://github.com/sitespeedio/browsertime/pull/2250).
|
|
29
|
+
* Replace lodash.get [#2251](https://github.com/sitespeedio/browsertime/pull/2251).
|
|
17
30
|
* Fix Docker file ENV to follow the new standard [#2239](https://github.com/sitespeedio/browsertime/pull/2239).
|
|
18
|
-
* Edgedriver 131 [#2236](https://github.com/sitespeedio/browsertime/pull/2236).
|
|
19
31
|
|
|
20
32
|
|
|
21
33
|
## 23.5.0 - 2024-12-23
|
package/bin/browsertime.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import merge from 'lodash.merge';
|
|
3
|
-
import get from 'lodash.get';
|
|
4
|
-
import set from 'lodash.set';
|
|
5
3
|
import { getLogger } from '@sitespeed.io/log';
|
|
6
4
|
import { existsSync, mkdirSync } from 'node:fs';
|
|
7
5
|
import path from 'node:path';
|
|
@@ -15,6 +13,7 @@ import { configure } from '../lib/support/logging.js';
|
|
|
15
13
|
import { parseCommandLine } from '../lib/support/cli.js';
|
|
16
14
|
import { StorageManager } from '../lib/support/storageManager.js';
|
|
17
15
|
import { loadScript } from '../lib/support/engineUtils.js';
|
|
16
|
+
import { setProperty, getProperty } from '../lib/support/util.js';
|
|
18
17
|
import { isAndroidConfigured } from '../lib/android/index.js';
|
|
19
18
|
|
|
20
19
|
const log = getLogger('browsertime');
|
|
@@ -40,28 +39,28 @@ async function preWarmServer(urls, options) {
|
|
|
40
39
|
docker: options.docker,
|
|
41
40
|
headless: options.headless
|
|
42
41
|
};
|
|
43
|
-
const chromeDevice =
|
|
44
|
-
const firefoxDevice =
|
|
45
|
-
const safariIos =
|
|
46
|
-
const safariDeviceName =
|
|
47
|
-
const safariDeviceUDID =
|
|
42
|
+
const chromeDevice = getProperty(options, 'chrome.android.deviceSerial');
|
|
43
|
+
const firefoxDevice = getProperty(options, 'firefox.android.deviceSerial');
|
|
44
|
+
const safariIos = getProperty(options, 'safari.ios');
|
|
45
|
+
const safariDeviceName = getProperty(options, 'safari.deviceName');
|
|
46
|
+
const safariDeviceUDID = getProperty(options, 'safari.deviceUDID ');
|
|
48
47
|
|
|
49
48
|
if (isAndroidConfigured(options) && options.browser === 'chrome') {
|
|
50
|
-
|
|
49
|
+
setProperty(preWarmOptions, 'chrome.android.package', 'com.android.chrome');
|
|
51
50
|
}
|
|
52
51
|
if (chromeDevice) {
|
|
53
|
-
|
|
52
|
+
setProperty(preWarmOptions, 'chrome.android.deviceSerial', chromeDevice);
|
|
54
53
|
} else if (firefoxDevice) {
|
|
55
|
-
|
|
54
|
+
setProperty(preWarmOptions, 'firefox.android.deviceSerial', firefoxDevice);
|
|
56
55
|
}
|
|
57
56
|
|
|
58
57
|
if (safariIos) {
|
|
59
|
-
|
|
58
|
+
setProperty(preWarmOptions, 'safari.ios', true);
|
|
60
59
|
if (safariDeviceName) {
|
|
61
|
-
|
|
60
|
+
setProperty(preWarmOptions, 'safari.deviceName', safariDeviceName);
|
|
62
61
|
}
|
|
63
62
|
if (safariDeviceUDID) {
|
|
64
|
-
|
|
63
|
+
setProperty(preWarmOptions, 'safari.deviceUDID', safariDeviceUDID);
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
|
package/lib/android/index.js
CHANGED
|
@@ -5,10 +5,10 @@ import { EOL as endOfLine } from 'node:os';
|
|
|
5
5
|
import { execa } from 'execa';
|
|
6
6
|
import { getLogger } from '@sitespeed.io/log';
|
|
7
7
|
import pkg from '@devicefarmer/adbkit';
|
|
8
|
-
import usbPowerProfiler from 'usb-power-profiling/usb-power-profiling.js';
|
|
9
8
|
const { Adb } = pkg;
|
|
10
|
-
import get from 'lodash.get';
|
|
11
9
|
import { pathToFolder } from '../support/pathToFolder.js';
|
|
10
|
+
import { loadUsbPowerProfiler } from '../support/usbPower.js';
|
|
11
|
+
import { getProperty } from '../support/util.js';
|
|
12
12
|
const log = getLogger('browsertime.android');
|
|
13
13
|
const mkdir = promisify(_mkdir);
|
|
14
14
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
@@ -25,10 +25,10 @@ export class Android {
|
|
|
25
25
|
Android.instance = this;
|
|
26
26
|
this.client = Adb.createClient();
|
|
27
27
|
|
|
28
|
-
this.id =
|
|
28
|
+
this.id = getProperty(
|
|
29
29
|
options,
|
|
30
30
|
'chrome.android.deviceSerial',
|
|
31
|
-
|
|
31
|
+
getProperty(options, 'firefox.android.deviceSerial')
|
|
32
32
|
);
|
|
33
33
|
this.port = options.devToolsPort;
|
|
34
34
|
|
|
@@ -474,6 +474,11 @@ export class Android {
|
|
|
474
474
|
}
|
|
475
475
|
|
|
476
476
|
async getUsbPowerUsageProfile(index, url, result, options, storageManager) {
|
|
477
|
+
const usbPowerProfiler = await loadUsbPowerProfiler();
|
|
478
|
+
if (!usbPowerProfiler) {
|
|
479
|
+
log.info('USB profiler is not installed');
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
477
482
|
let profileData = await usbPowerProfiler.profileFromData();
|
|
478
483
|
let destinationFilename = path.join(
|
|
479
484
|
await pathToFolder(url, options),
|
|
@@ -485,6 +490,11 @@ export class Android {
|
|
|
485
490
|
}
|
|
486
491
|
|
|
487
492
|
async function getUsbPowerUsage(startTime, endTime) {
|
|
493
|
+
const usbPowerProfiler = await loadUsbPowerProfiler();
|
|
494
|
+
if (!usbPowerProfiler) {
|
|
495
|
+
log.info('USB profiler is not installed');
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
488
498
|
let baselineUsageData = await usbPowerProfiler.getPowerData(
|
|
489
499
|
startTime - 2,
|
|
490
500
|
endTime - 1
|
|
@@ -584,10 +594,10 @@ export function isAndroidConfigured(options) {
|
|
|
584
594
|
if (options.android && options.android.enabled === true) {
|
|
585
595
|
return true;
|
|
586
596
|
}
|
|
587
|
-
return
|
|
597
|
+
return getProperty(
|
|
588
598
|
options,
|
|
589
599
|
'chrome.android.package',
|
|
590
|
-
|
|
600
|
+
getProperty(options, 'firefox.android.package', false)
|
|
591
601
|
)
|
|
592
602
|
? true
|
|
593
603
|
: false;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { getProperty } from '../support/util.js';
|
|
2
2
|
|
|
3
3
|
export function longTaskMetrics(result, options) {
|
|
4
4
|
let totalDurationFirstPaint = 0;
|
|
@@ -12,21 +12,24 @@ export function longTaskMetrics(result, options) {
|
|
|
12
12
|
// https://web.dev/tbt/ - total blocking time
|
|
13
13
|
let totalBlockingTime = 0;
|
|
14
14
|
|
|
15
|
-
const firstPaint =
|
|
15
|
+
const firstPaint = getProperty(
|
|
16
16
|
result,
|
|
17
17
|
'browserScripts.timings.paintTiming.first-paint'
|
|
18
18
|
);
|
|
19
|
-
const firstContentfulPaint =
|
|
19
|
+
const firstContentfulPaint = getProperty(
|
|
20
20
|
result,
|
|
21
21
|
'browserScripts.timings.paintTiming.first-contentful-paint'
|
|
22
22
|
);
|
|
23
23
|
|
|
24
|
-
const largestContentfulPaint =
|
|
24
|
+
const largestContentfulPaint = getProperty(
|
|
25
25
|
result,
|
|
26
26
|
'browserScripts.timings.largestContentfulPaint.renderTime'
|
|
27
27
|
); // result.browserScripts.timings.largestContentfulPaint.loadTime;
|
|
28
28
|
|
|
29
|
-
const loadEventEnd =
|
|
29
|
+
const loadEventEnd = getProperty(
|
|
30
|
+
result,
|
|
31
|
+
'browserScripts.timings.loadEventEnd'
|
|
32
|
+
);
|
|
30
33
|
|
|
31
34
|
let longTasksBeforeFirstPaint = 0;
|
|
32
35
|
let longTasksBeforeFirstContentfulPaint = 0;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { getLogger } from '@sitespeed.io/log';
|
|
2
|
-
import
|
|
2
|
+
import { getProperty } from '../support/util.js';
|
|
3
3
|
|
|
4
4
|
const log = getLogger('browsertime.chrome.network');
|
|
5
5
|
|
|
6
6
|
export class NetworkManager {
|
|
7
7
|
constructor(cdpClient, options) {
|
|
8
|
-
this.maxTimeout =
|
|
9
|
-
|
|
8
|
+
this.maxTimeout = getProperty(
|
|
9
|
+
options,
|
|
10
|
+
'timeouts.pageCompleteCheck',
|
|
11
|
+
30_000
|
|
12
|
+
);
|
|
13
|
+
this.idleTime = getProperty(options, 'timeouts.networkIdle', 5000);
|
|
10
14
|
|
|
11
15
|
this.cdp = cdpClient.getRawClient();
|
|
12
16
|
this.inflight = 0;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import get from 'lodash.get';
|
|
2
1
|
import { logging } from 'selenium-webdriver';
|
|
3
2
|
import { ServiceBuilder, Options } from 'selenium-webdriver/chrome.js';
|
|
4
3
|
import { pac, manual } from 'selenium-webdriver/proxy.js';
|
|
5
4
|
import { setupChromiumOptions } from './setupChromiumOptions.js';
|
|
6
|
-
import { pick, isEmpty } from '../../support/util.js';
|
|
5
|
+
import { pick, isEmpty, getProperty } from '../../support/util.js';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Configure a WebDriver builder based on the specified options.
|
|
@@ -13,7 +12,7 @@ import { pick, isEmpty } from '../../support/util.js';
|
|
|
13
12
|
export async function configureBuilder(builder, baseDir, options) {
|
|
14
13
|
const chromeConfig = options.chrome || {};
|
|
15
14
|
|
|
16
|
-
let chromedriverPath =
|
|
15
|
+
let chromedriverPath = getProperty(chromeConfig, 'chromedriverPath');
|
|
17
16
|
if (!chromedriverPath) {
|
|
18
17
|
let chromedriver = await import('@sitespeed.io/chromedriver');
|
|
19
18
|
chromedriverPath = chromedriver.default.binPath();
|
|
@@ -62,7 +61,7 @@ export async function configureBuilder(builder, baseDir, options) {
|
|
|
62
61
|
|
|
63
62
|
builder
|
|
64
63
|
.getCapabilities()
|
|
65
|
-
.set('pageLoadStrategy',
|
|
64
|
+
.set('pageLoadStrategy', getProperty(options, 'pageLoadStrategy', 'normal'))
|
|
66
65
|
.set('goog:loggingPrefs', logPrefs); // Fix for Chrome/Chromedriver 75
|
|
67
66
|
|
|
68
67
|
setupChromiumOptions(chromeOptions, chromeConfig, options, baseDir);
|
|
@@ -3,7 +3,6 @@ import { unlink as _unlink, rm as _rm } from 'node:fs';
|
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { logging } from 'selenium-webdriver';
|
|
5
5
|
import { getLogger } from '@sitespeed.io/log';
|
|
6
|
-
import usbPowerProfiler from 'usb-power-profiling/usb-power-profiling.js';
|
|
7
6
|
const log = getLogger('browsertime.chrome');
|
|
8
7
|
const { Type } = logging;
|
|
9
8
|
import { longTaskMetrics } from '../longTaskMetrics.js';
|
|
@@ -14,6 +13,7 @@ import { toArray } from '../../support/util.js';
|
|
|
14
13
|
import { logging as _logging } from 'selenium-webdriver';
|
|
15
14
|
import { parse } from '../traceCategoriesParser.js';
|
|
16
15
|
import { pathToFolder } from '../../support/pathToFolder.js';
|
|
16
|
+
import { loadUsbPowerProfiler } from '../../support/usbPower.js';
|
|
17
17
|
import { ChromeDevtoolsProtocol } from '../chromeDevtoolsProtocol.js';
|
|
18
18
|
import { NetworkManager } from '../networkManager.js';
|
|
19
19
|
import { Android, isAndroidConfigured } from '../../android/index.js';
|
|
@@ -80,7 +80,10 @@ export class Chromium {
|
|
|
80
80
|
await this.android.addDevtoolsFw();
|
|
81
81
|
|
|
82
82
|
if (this.options.androidUsbPower) {
|
|
83
|
-
usbPowerProfiler
|
|
83
|
+
const usbPowerProfiler = await loadUsbPowerProfiler();
|
|
84
|
+
if (usbPowerProfiler) {
|
|
85
|
+
usbPowerProfiler.startSampling();
|
|
86
|
+
}
|
|
84
87
|
}
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -171,7 +174,10 @@ export class Chromium {
|
|
|
171
174
|
if (this.options.androidPower) {
|
|
172
175
|
await this.android.resetPowerUsage();
|
|
173
176
|
} else if (this.options.androidUsbPower) {
|
|
174
|
-
await
|
|
177
|
+
const usbPowerProfiler = await loadUsbPowerProfiler();
|
|
178
|
+
if (usbPowerProfiler) {
|
|
179
|
+
await usbPowerProfiler.resetPowerData();
|
|
180
|
+
}
|
|
175
181
|
}
|
|
176
182
|
}
|
|
177
183
|
|
|
@@ -511,7 +517,10 @@ export class Chromium {
|
|
|
511
517
|
if (this.options.androidPower) {
|
|
512
518
|
await this.android.stopPowerTesting();
|
|
513
519
|
} else if (this.options.androidUsbPower) {
|
|
514
|
-
await
|
|
520
|
+
const usbPowerProfiler = await loadUsbPowerProfiler();
|
|
521
|
+
if (usbPowerProfiler) {
|
|
522
|
+
await usbPowerProfiler.stopSampling();
|
|
523
|
+
}
|
|
515
524
|
}
|
|
516
525
|
}
|
|
517
526
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import http from 'node:http';
|
|
2
2
|
import https from 'node:https';
|
|
3
|
-
import get from 'lodash.get';
|
|
4
3
|
import { getLogger } from '@sitespeed.io/log';
|
|
4
|
+
import { getProperty } from '../support/util.js';
|
|
5
5
|
const log = getLogger('browsertime.connectivity.humble');
|
|
6
6
|
|
|
7
7
|
export class Humble {
|
|
8
8
|
constructor(options) {
|
|
9
|
-
this.url =
|
|
9
|
+
this.url = getProperty(options.connectivity, 'humble.url');
|
|
10
10
|
this.profile = options.connectivity.profile;
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import get from 'lodash.get';
|
|
2
1
|
import { getLogger } from '@sitespeed.io/log';
|
|
3
2
|
import {
|
|
4
3
|
start as throttleStart,
|
|
@@ -7,6 +6,7 @@ import {
|
|
|
7
6
|
const log = getLogger('browsertime.connectivity');
|
|
8
7
|
import { Humble } from './humble.js';
|
|
9
8
|
import { parseTrafficShapeConfig } from './trafficShapeParser.js';
|
|
9
|
+
import { getProperty } from '../support/util.js';
|
|
10
10
|
|
|
11
11
|
let humble;
|
|
12
12
|
|
|
@@ -49,7 +49,11 @@ export async function addConnectivity(options) {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const setOnLocalHost =
|
|
52
|
+
const setOnLocalHost = getProperty(
|
|
53
|
+
connectivity,
|
|
54
|
+
'throttle.localhost',
|
|
55
|
+
false
|
|
56
|
+
);
|
|
53
57
|
const rtt = profile.variance
|
|
54
58
|
? getRandomIntInclusive(
|
|
55
59
|
profile.rtt,
|
|
@@ -96,7 +100,11 @@ export async function removeConnectivity(options) {
|
|
|
96
100
|
return;
|
|
97
101
|
}
|
|
98
102
|
case 'throttle': {
|
|
99
|
-
const setOnLocalHost =
|
|
103
|
+
const setOnLocalHost = getProperty(
|
|
104
|
+
connectivity,
|
|
105
|
+
'throttle.localhost',
|
|
106
|
+
false
|
|
107
|
+
);
|
|
100
108
|
return throttleStop({ localhost: setOnLocalHost });
|
|
101
109
|
}
|
|
102
110
|
case 'humble': {
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
|
-
import get from 'lodash.get';
|
|
4
3
|
import { getLogger } from '@sitespeed.io/log';
|
|
5
4
|
import { timestamp as _timestamp } from '../../support/engineUtils.js';
|
|
6
5
|
import { Statistics } from '../../support/statistics.js';
|
|
7
6
|
import { pathToFolder } from '../../support/pathToFolder.js';
|
|
8
7
|
import { getConnectivitySettings } from '../../connectivity/index.js';
|
|
9
|
-
import { formatMetric } from '../../support/util.js';
|
|
8
|
+
import { formatMetric, getProperty } from '../../support/util.js';
|
|
10
9
|
const require = createRequire(import.meta.url);
|
|
11
10
|
const version = require('../../../package.json').version;
|
|
12
11
|
const log = getLogger('browsertime');
|
|
@@ -20,11 +19,11 @@ function getNewResult(url, options) {
|
|
|
20
19
|
url,
|
|
21
20
|
timestamp: _timestamp(),
|
|
22
21
|
connectivity: {
|
|
23
|
-
engine:
|
|
24
|
-
profile:
|
|
22
|
+
engine: getProperty(options, 'connectivity.engine'),
|
|
23
|
+
profile: getProperty(options, 'connectivity.profile'),
|
|
25
24
|
settings: getConnectivitySettings(options) || undefined
|
|
26
25
|
},
|
|
27
|
-
extra: JSON.parse(
|
|
26
|
+
extra: JSON.parse(getProperty(options, 'info.extra', '{}')),
|
|
28
27
|
browser: { name: options.browser }
|
|
29
28
|
},
|
|
30
29
|
files: {
|
|
@@ -163,7 +162,7 @@ export class Collector {
|
|
|
163
162
|
const results = this.allResults[url] ?? getNewResult(url, this.options);
|
|
164
163
|
results.info.description = allData.description;
|
|
165
164
|
results.info.title = allData.title;
|
|
166
|
-
results.info.browser.userAgent =
|
|
165
|
+
results.info.browser.userAgent = getProperty(
|
|
167
166
|
allData[0],
|
|
168
167
|
'browserScripts.browser.userAgent',
|
|
169
168
|
''
|
|
@@ -238,30 +237,36 @@ export class Collector {
|
|
|
238
237
|
}
|
|
239
238
|
|
|
240
239
|
if (this.options.iterations > 1) {
|
|
241
|
-
const ttfb =
|
|
240
|
+
const ttfb = getProperty(
|
|
242
241
|
data,
|
|
243
242
|
'browserScripts.timings.pageTimings.backEndTime'
|
|
244
243
|
);
|
|
245
|
-
const domContentLoaded =
|
|
244
|
+
const domContentLoaded = getProperty(
|
|
246
245
|
data,
|
|
247
246
|
'browserScripts.timings.pageTimings.domContentLoadedTime'
|
|
248
247
|
);
|
|
249
|
-
const firstPaint =
|
|
250
|
-
|
|
248
|
+
const firstPaint = getProperty(
|
|
249
|
+
data,
|
|
250
|
+
'browserScripts.timings.firstPaint'
|
|
251
|
+
);
|
|
252
|
+
const fcp = getProperty(
|
|
251
253
|
data,
|
|
252
254
|
"browserScripts.timings.paintTiming['first-contentful-paint']"
|
|
253
255
|
);
|
|
254
|
-
const pageLoadTime =
|
|
256
|
+
const pageLoadTime = getProperty(
|
|
255
257
|
data,
|
|
256
258
|
'browserScripts.timings.pageTimings.pageLoadTime'
|
|
257
259
|
);
|
|
258
|
-
const lcp =
|
|
260
|
+
const lcp = getProperty(
|
|
259
261
|
data,
|
|
260
262
|
'browserScripts.timings.largestContentfulPaint.renderTime'
|
|
261
263
|
);
|
|
262
|
-
const cls =
|
|
263
|
-
|
|
264
|
-
|
|
264
|
+
const cls = getProperty(
|
|
265
|
+
data,
|
|
266
|
+
'browserScripts.pageinfo.cumulativeLayoutShift'
|
|
267
|
+
);
|
|
268
|
+
const tbt = getProperty(data, 'cpu.longTasks.totalBlockingTime');
|
|
269
|
+
const mem = getProperty(data, 'memory');
|
|
265
270
|
|
|
266
271
|
log.info(
|
|
267
272
|
`${url} ${ttfb ? formatMetric('TTFB', ttfb, false, true) + ' ' : ''}${
|
|
@@ -451,17 +456,23 @@ export class Collector {
|
|
|
451
456
|
|
|
452
457
|
// Add delta to TTFB
|
|
453
458
|
const deltaToTTFB = {};
|
|
454
|
-
const fcp =
|
|
459
|
+
const fcp = getProperty(
|
|
455
460
|
data,
|
|
456
461
|
"browserScripts.timings.paintTiming['first-contentful-paint']"
|
|
457
462
|
);
|
|
458
|
-
const ttfb =
|
|
459
|
-
const lcp =
|
|
463
|
+
const ttfb = getProperty(data, 'browserScripts.timings.ttfb');
|
|
464
|
+
const lcp = getProperty(
|
|
460
465
|
data,
|
|
461
466
|
'browserScripts.timings.largestContentfulPaint.renderTime'
|
|
462
467
|
);
|
|
463
|
-
const firstVisualChange =
|
|
464
|
-
|
|
468
|
+
const firstVisualChange = getProperty(
|
|
469
|
+
data,
|
|
470
|
+
'visualMetrics.FirstVisualChange'
|
|
471
|
+
);
|
|
472
|
+
const lastVisualChange = getProperty(
|
|
473
|
+
data,
|
|
474
|
+
'visualMetrics.LastVisualChange'
|
|
475
|
+
);
|
|
465
476
|
|
|
466
477
|
if (fcp) {
|
|
467
478
|
deltaToTTFB['firstContentfulPaint'] = fcp - ttfb;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { getLogger } from '@sitespeed.io/log';
|
|
3
|
-
import get from 'lodash.get';
|
|
4
3
|
import merge from 'lodash.merge';
|
|
5
4
|
import { timestamp as _timestamp } from '../../../support/engineUtils.js';
|
|
6
5
|
import { Video } from '../../../video/video.js';
|
|
@@ -12,6 +11,7 @@ import {
|
|
|
12
11
|
} from '../../../support/userTiming.js';
|
|
13
12
|
import { isAndroidConfigured, Android } from '../../../android/index.js';
|
|
14
13
|
import { TCPDump } from '../../../support/tcpdump.js';
|
|
14
|
+
import { getProperty } from '../../../support/util.js';
|
|
15
15
|
import { lcpHighlightScript as highlightLargestContentfulPaint } from './util/lcpHighlightScript.js';
|
|
16
16
|
import { clsHighlightScript as highlightLS } from './util/lsHighlightScript.js';
|
|
17
17
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
@@ -132,15 +132,23 @@ export class Measure {
|
|
|
132
132
|
/**
|
|
133
133
|
* @private
|
|
134
134
|
*/
|
|
135
|
-
this.ANDROID_DELAY_TIME =
|
|
135
|
+
this.ANDROID_DELAY_TIME = getProperty(
|
|
136
|
+
options,
|
|
137
|
+
'orangeAndroidDelayTime',
|
|
138
|
+
2000
|
|
139
|
+
);
|
|
136
140
|
/**
|
|
137
141
|
* @private
|
|
138
142
|
*/
|
|
139
|
-
this.IOS_DELAY_TIME =
|
|
143
|
+
this.IOS_DELAY_TIME = getProperty(options, 'orangeIosDelayTime', 1000);
|
|
140
144
|
/**
|
|
141
145
|
* @private
|
|
142
146
|
*/
|
|
143
|
-
this.DESKTOP_DELAY_TIME =
|
|
147
|
+
this.DESKTOP_DELAY_TIME = getProperty(
|
|
148
|
+
options,
|
|
149
|
+
'orangeDesktopDelayTime',
|
|
150
|
+
800
|
|
151
|
+
);
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
/**
|
|
@@ -657,8 +665,12 @@ export class Measure {
|
|
|
657
665
|
if (isAndroidConfigured(this.options) && this.options.processStartTime) {
|
|
658
666
|
const packageName =
|
|
659
667
|
this.options.browser === 'firefox'
|
|
660
|
-
?
|
|
661
|
-
|
|
668
|
+
? getProperty(
|
|
669
|
+
this.options,
|
|
670
|
+
'firefox.android.package',
|
|
671
|
+
'org.mozilla.firefox'
|
|
672
|
+
)
|
|
673
|
+
: getProperty(this.options, 'chrome.android.package');
|
|
662
674
|
|
|
663
675
|
const android = new Android(this.options);
|
|
664
676
|
const pid = await android.pidof(packageName);
|
package/lib/core/engine/index.js
CHANGED
|
@@ -2,7 +2,6 @@ import { arch as _arch } from 'node:os';
|
|
|
2
2
|
import { getLogger } from '@sitespeed.io/log';
|
|
3
3
|
import merge from 'lodash.merge';
|
|
4
4
|
import { execaCommand as command } from 'execa';
|
|
5
|
-
import get from 'lodash.get';
|
|
6
5
|
import { StorageManager } from '../../support/storageManager.js';
|
|
7
6
|
import { Firefox } from '../../firefox/webdriver/firefox.js';
|
|
8
7
|
import { Chromium } from '../../chrome/webdriver/chromium.js';
|
|
@@ -11,7 +10,7 @@ import {
|
|
|
11
10
|
addConnectivity,
|
|
12
11
|
removeConnectivity
|
|
13
12
|
} from '../../connectivity/index.js';
|
|
14
|
-
import { logResultLogLine } from '../../support/util.js';
|
|
13
|
+
import { logResultLogLine, getProperty } from '../../support/util.js';
|
|
15
14
|
import {
|
|
16
15
|
getFullyLoaded,
|
|
17
16
|
getMainDocumentTimings,
|
|
@@ -108,7 +107,11 @@ export class Engine {
|
|
|
108
107
|
}
|
|
109
108
|
|
|
110
109
|
if (options.androidVerifyNetwork) {
|
|
111
|
-
const pingAddress =
|
|
110
|
+
const pingAddress = getProperty(
|
|
111
|
+
options,
|
|
112
|
+
'androidPingAddress',
|
|
113
|
+
'8.8.8.8'
|
|
114
|
+
);
|
|
112
115
|
const connection = await android.ping(pingAddress);
|
|
113
116
|
if (!connection) {
|
|
114
117
|
const message = `No internet connection for ${android.id}. Could not ping ${pingAddress}`;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getLogger } from '@sitespeed.io/log';
|
|
2
2
|
import merge from 'lodash.merge';
|
|
3
|
-
import get from 'lodash.get';
|
|
4
3
|
import { Condition } from 'selenium-webdriver';
|
|
5
4
|
import { isAndroidConfigured } from '../android/index.js';
|
|
6
5
|
import { UrlLoadError, BrowserError, TimeoutError } from '../support/errors.js';
|
|
@@ -9,6 +8,7 @@ import { getViewPort } from '../support/getViewPort.js';
|
|
|
9
8
|
import { defaultPageCompleteCheck } from './pageCompleteChecks/defaultPageCompleteCheck.js';
|
|
10
9
|
import { pageCompleteCheckByInactivity } from './pageCompleteChecks/pageCompleteCheckByInactivity.js';
|
|
11
10
|
import { spaInactivity as spaCheck } from './pageCompleteChecks/spaInactivity.js';
|
|
11
|
+
import { getProperty } from '../support/util.js';
|
|
12
12
|
const log = getLogger('browsertime');
|
|
13
13
|
|
|
14
14
|
const defaults = {
|
|
@@ -292,7 +292,7 @@ export class SeleniumRunner {
|
|
|
292
292
|
// We give it a couple of times to finish loading, this makes it
|
|
293
293
|
// more stable in real case scenarios on slow servers.
|
|
294
294
|
let totalWaitTime = 0;
|
|
295
|
-
const tries =
|
|
295
|
+
const tries = getProperty(this.options, 'retries', 5) + 1;
|
|
296
296
|
for (let index = 0; index < tries; ++index) {
|
|
297
297
|
try {
|
|
298
298
|
await this._waitOnPageCompleteCheck(pageCompleteCheck, normalizedURI);
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { Options, ServiceBuilder } from 'selenium-webdriver/edge.js';
|
|
2
2
|
import { getLogger } from '@sitespeed.io/log';
|
|
3
|
-
import get from 'lodash.get';
|
|
4
3
|
import { logging } from 'selenium-webdriver';
|
|
5
4
|
import { setupChromiumOptions } from '../../chrome/webdriver/setupChromiumOptions.js';
|
|
6
5
|
const log = getLogger('browsertime.edge');
|
|
7
6
|
const { pac, manual } = 'selenium-webdriver/proxy.js';
|
|
8
|
-
import { pick, isEmpty } from '../../support/util.js';
|
|
7
|
+
import { pick, isEmpty, getProperty } from '../../support/util.js';
|
|
9
8
|
|
|
10
9
|
export async function configureBuilder(builder, baseDir, options) {
|
|
11
10
|
const edgeConfig = options.edge || {};
|
|
12
11
|
const chromeConfig = options.chrome || {};
|
|
13
12
|
|
|
14
|
-
let edgedriverPath =
|
|
15
|
-
const edgePath =
|
|
13
|
+
let edgedriverPath = getProperty(edgeConfig, 'edgedriverPath');
|
|
14
|
+
const edgePath = getProperty(edgeConfig, 'binaryPath');
|
|
16
15
|
|
|
17
16
|
if (!edgedriverPath) {
|
|
18
17
|
const edgedriver = await import('@sitespeed.io/edgedriver');
|
|
@@ -67,7 +66,7 @@ export async function configureBuilder(builder, baseDir, options) {
|
|
|
67
66
|
|
|
68
67
|
builder
|
|
69
68
|
.getCapabilities()
|
|
70
|
-
.set('pageLoadStrategy',
|
|
69
|
+
.set('pageLoadStrategy', getProperty(options, 'pageLoadStrategy', 'normal'))
|
|
71
70
|
.set('ms:loggingPrefs', logPrefs);
|
|
72
71
|
|
|
73
72
|
setupChromiumOptions(edgeOptions, chromeConfig, options, baseDir);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import get from 'lodash.get';
|
|
3
2
|
import { getLogger } from '@sitespeed.io/log';
|
|
4
3
|
import { geckoProfilerDefaults } from './settings/geckoProfilerDefaults.js';
|
|
5
4
|
import { isAndroidConfigured, Android } from '../android/index.js';
|
|
6
5
|
import { pathToFolder } from '../support/pathToFolder.js';
|
|
7
6
|
import { BrowserError } from '../support/errors.js';
|
|
7
|
+
import { getProperty } from '../support/util.js';
|
|
8
8
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
9
9
|
const log = getLogger('browsertime.firefox');
|
|
10
10
|
|
|
@@ -104,7 +104,7 @@ export class GeckoProfiler {
|
|
|
104
104
|
const runner = this.runner;
|
|
105
105
|
const firefoxConfig = this.firefoxConfig;
|
|
106
106
|
const options = this.options;
|
|
107
|
-
const chosenFeatures =
|
|
107
|
+
const chosenFeatures = getProperty(
|
|
108
108
|
firefoxConfig,
|
|
109
109
|
'geckoProfilerParams.features',
|
|
110
110
|
geckoProfilerDefaults.features
|
|
@@ -112,14 +112,14 @@ export class GeckoProfiler {
|
|
|
112
112
|
|
|
113
113
|
const featureString = '["' + chosenFeatures.join('","') + '"]';
|
|
114
114
|
|
|
115
|
-
const chosenThreads =
|
|
115
|
+
const chosenThreads = getProperty(
|
|
116
116
|
firefoxConfig,
|
|
117
117
|
'geckoProfilerParams.threads',
|
|
118
118
|
geckoProfilerDefaults.threads
|
|
119
119
|
).split(',');
|
|
120
120
|
const threadString = '["' + chosenThreads.join('","') + '"]';
|
|
121
121
|
|
|
122
|
-
let interval =
|
|
122
|
+
let interval = getProperty(
|
|
123
123
|
firefoxConfig,
|
|
124
124
|
'geckoProfilerParams.interval',
|
|
125
125
|
geckoProfilerDefaults.interval
|
|
@@ -135,7 +135,7 @@ export class GeckoProfiler {
|
|
|
135
135
|
: geckoProfilerDefaults.desktopSamplingInterval;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
const bufferSize =
|
|
138
|
+
const bufferSize = getProperty(
|
|
139
139
|
firefoxConfig,
|
|
140
140
|
'geckoProfilerParams.bufferSize',
|
|
141
141
|
geckoProfilerDefaults.bufferSize
|
|
@@ -208,7 +208,7 @@ export class GeckoProfiler {
|
|
|
208
208
|
|
|
209
209
|
let deviceProfileFilename = destinationFilename;
|
|
210
210
|
if (isAndroidConfigured(options)) {
|
|
211
|
-
deviceProfileFilename = `/sdcard/Android/data/${
|
|
211
|
+
deviceProfileFilename = `/sdcard/Android/data/${getProperty(
|
|
212
212
|
this.firefoxConfig,
|
|
213
213
|
'android.package',
|
|
214
214
|
'org.mozilla.firefox'
|
|
@@ -250,7 +250,7 @@ export class GeckoProfiler {
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
if (this.firefoxConfig.powerConsumption === true) {
|
|
253
|
-
const chosenFeatures =
|
|
253
|
+
const chosenFeatures = getProperty(
|
|
254
254
|
this.firefoxConfig,
|
|
255
255
|
'geckoProfilerParams.features',
|
|
256
256
|
geckoProfilerDefaults.features
|