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.
Files changed (42) hide show
  1. package/CHANGELOG.md +14 -2
  2. package/bin/browsertime.js +12 -13
  3. package/lib/android/index.js +16 -6
  4. package/lib/chrome/longTaskMetrics.js +8 -5
  5. package/lib/chrome/networkManager.js +7 -3
  6. package/lib/chrome/webdriver/builder.js +3 -4
  7. package/lib/chrome/webdriver/chromium.js +13 -4
  8. package/lib/connectivity/humble.js +2 -2
  9. package/lib/connectivity/index.js +11 -3
  10. package/lib/core/engine/collector.js +31 -20
  11. package/lib/core/engine/command/measure.js +18 -6
  12. package/lib/core/engine/index.js +6 -3
  13. package/lib/core/seleniumRunner.js +2 -2
  14. package/lib/edge/webdriver/builder.js +4 -5
  15. package/lib/firefox/geckoProfiler.js +7 -7
  16. package/lib/firefox/networkManager.js +7 -3
  17. package/lib/firefox/webdriver/builder.js +14 -12
  18. package/lib/firefox/webdriver/firefox.js +18 -7
  19. package/lib/support/cli.js +24 -21
  20. package/lib/support/getViewPort.js +8 -4
  21. package/lib/support/har/index.js +7 -4
  22. package/lib/support/statistics.js +8 -7
  23. package/lib/support/usbPower.js +11 -0
  24. package/lib/support/util.js +53 -0
  25. package/lib/support/xvfb.js +4 -4
  26. package/lib/video/postprocessing/finetune/index.js +3 -3
  27. package/lib/video/postprocessing/visualmetrics/visualMetrics.js +14 -5
  28. package/lib/video/screenRecording/android/recorder.js +8 -3
  29. package/lib/video/screenRecording/desktop/desktopRecorder.js +9 -8
  30. package/lib/video/video.js +2 -3
  31. package/package.json +4 -6
  32. package/types/android/index.d.ts.map +1 -1
  33. package/types/core/engine/command/measure.d.ts.map +1 -1
  34. package/types/support/getViewPort.d.ts.map +1 -1
  35. package/types/support/usbPower.d.ts +2 -0
  36. package/types/support/usbPower.d.ts.map +1 -0
  37. package/types/support/util.d.ts +6 -0
  38. package/types/support/util.d.ts.map +1 -1
  39. package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts.map +1 -1
  40. package/types/video/screenRecording/android/recorder.d.ts.map +1 -1
  41. package/types/video/screenRecording/desktop/desktopRecorder.d.ts.map +1 -1
  42. 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.1 - 2025-01-07
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
@@ -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 = get(options, 'chrome.android.deviceSerial');
44
- const firefoxDevice = get(options, 'firefox.android.deviceSerial');
45
- const safariIos = get(options, 'safari.ios');
46
- const safariDeviceName = get(options, 'safari.deviceName');
47
- const safariDeviceUDID = get(options, 'safari.deviceUDID ');
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
- set(preWarmOptions, 'chrome.android.package', 'com.android.chrome');
49
+ setProperty(preWarmOptions, 'chrome.android.package', 'com.android.chrome');
51
50
  }
52
51
  if (chromeDevice) {
53
- set(preWarmOptions, 'chrome.android.deviceSerial', chromeDevice);
52
+ setProperty(preWarmOptions, 'chrome.android.deviceSerial', chromeDevice);
54
53
  } else if (firefoxDevice) {
55
- set(preWarmOptions, 'firefox.android.deviceSerial', firefoxDevice);
54
+ setProperty(preWarmOptions, 'firefox.android.deviceSerial', firefoxDevice);
56
55
  }
57
56
 
58
57
  if (safariIos) {
59
- set(preWarmOptions, 'safari.ios', true);
58
+ setProperty(preWarmOptions, 'safari.ios', true);
60
59
  if (safariDeviceName) {
61
- set(preWarmOptions, 'safari.deviceName', safariDeviceName);
60
+ setProperty(preWarmOptions, 'safari.deviceName', safariDeviceName);
62
61
  }
63
62
  if (safariDeviceUDID) {
64
- set(preWarmOptions, 'safari.deviceUDID', safariDeviceUDID);
63
+ setProperty(preWarmOptions, 'safari.deviceUDID', safariDeviceUDID);
65
64
  }
66
65
  }
67
66
 
@@ -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 = get(
28
+ this.id = getProperty(
29
29
  options,
30
30
  'chrome.android.deviceSerial',
31
- get(options, 'firefox.android.deviceSerial')
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 get(
597
+ return getProperty(
588
598
  options,
589
599
  'chrome.android.package',
590
- get(options, 'firefox.android.package', false)
600
+ getProperty(options, 'firefox.android.package', false)
591
601
  )
592
602
  ? true
593
603
  : false;
@@ -1,4 +1,4 @@
1
- import get from 'lodash.get';
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 = get(
15
+ const firstPaint = getProperty(
16
16
  result,
17
17
  'browserScripts.timings.paintTiming.first-paint'
18
18
  );
19
- const firstContentfulPaint = get(
19
+ const firstContentfulPaint = getProperty(
20
20
  result,
21
21
  'browserScripts.timings.paintTiming.first-contentful-paint'
22
22
  );
23
23
 
24
- const largestContentfulPaint = get(
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 = get(result, 'browserScripts.timings.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 get from 'lodash.get';
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 = get(options, 'timeouts.pageCompleteCheck', 30_000);
9
- this.idleTime = get(options, 'timeouts.networkIdle', 5000);
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 = get(chromeConfig, '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', get(options, 'pageLoadStrategy', 'normal'))
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.startSampling();
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 usbPowerProfiler.resetPowerData();
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 usbPowerProfiler.stopSampling();
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 = get(options.connectivity, 'humble.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 = get(connectivity, 'throttle.localhost', false);
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 = get(connectivity, 'throttle.localhost', false);
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: get(options, 'connectivity.engine'),
24
- profile: get(options, 'connectivity.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(get(options, 'info.extra', '{}')),
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 = get(
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 = get(
240
+ const ttfb = getProperty(
242
241
  data,
243
242
  'browserScripts.timings.pageTimings.backEndTime'
244
243
  );
245
- const domContentLoaded = get(
244
+ const domContentLoaded = getProperty(
246
245
  data,
247
246
  'browserScripts.timings.pageTimings.domContentLoadedTime'
248
247
  );
249
- const firstPaint = get(data, 'browserScripts.timings.firstPaint');
250
- const fcp = get(
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 = get(
256
+ const pageLoadTime = getProperty(
255
257
  data,
256
258
  'browserScripts.timings.pageTimings.pageLoadTime'
257
259
  );
258
- const lcp = get(
260
+ const lcp = getProperty(
259
261
  data,
260
262
  'browserScripts.timings.largestContentfulPaint.renderTime'
261
263
  );
262
- const cls = get(data, 'browserScripts.pageinfo.cumulativeLayoutShift');
263
- const tbt = get(data, 'cpu.longTasks.totalBlockingTime');
264
- const mem = get(data, 'memory');
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 = get(
459
+ const fcp = getProperty(
455
460
  data,
456
461
  "browserScripts.timings.paintTiming['first-contentful-paint']"
457
462
  );
458
- const ttfb = get(data, 'browserScripts.timings.ttfb');
459
- const lcp = get(
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 = get(data, 'visualMetrics.FirstVisualChange');
464
- const lastVisualChange = get(data, 'visualMetrics.LastVisualChange');
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 = get(options, 'orangeAndroidDelayTime', 2000);
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 = get(options, 'orangeIosDelayTime', 1000);
143
+ this.IOS_DELAY_TIME = getProperty(options, 'orangeIosDelayTime', 1000);
140
144
  /**
141
145
  * @private
142
146
  */
143
- this.DESKTOP_DELAY_TIME = get(options, 'orangeDesktopDelayTime', 800);
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
- ? get(this.options, 'firefox.android.package', 'org.mozilla.firefox')
661
- : get(this.options, 'chrome.android.package');
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);
@@ -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 = get(options, 'androidPingAddress', '8.8.8.8');
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 = get(this.options, 'retries', 5) + 1;
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 = get(edgeConfig, 'edgedriverPath');
15
- const edgePath = get(edgeConfig, 'binaryPath');
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', get(options, 'pageLoadStrategy', 'normal'))
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 = get(
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 = get(
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 = get(
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 = get(
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/${get(
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 = get(
253
+ const chosenFeatures = getProperty(
254
254
  this.firefoxConfig,
255
255
  'geckoProfilerParams.features',
256
256
  geckoProfilerDefaults.features