browsertime 19.3.0 → 20.0.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +9 -6
  3. package/lib/core/engine/command/measure.js +4 -4
  4. package/lib/core/engine/index.js +6 -2
  5. package/lib/firefox/webdriver/builder.js +31 -3
  6. package/lib/support/cli.js +28 -15
  7. package/lib/support/engineUtils.js +13 -1
  8. package/lib/support/userTiming.js +2 -2
  9. package/package.json +2 -3
  10. package/visualmetrics/__init__.py +1 -0
  11. package/visualmetrics/test_data/ms_000000.png +0 -0
  12. package/visualmetrics/test_data/ms_000920.png +0 -0
  13. package/visualmetrics/test_data/ms_001000.png +0 -0
  14. package/visualmetrics/test_data/ms_001080.png +0 -0
  15. package/visualmetrics/test_data/ms_001200.png +0 -0
  16. package/visualmetrics/test_data/ms_001240.png +0 -0
  17. package/visualmetrics/test_data/ms_001280.png +0 -0
  18. package/visualmetrics/test_data/ms_001360.png +0 -0
  19. package/visualmetrics/test_data/ms_001400.png +0 -0
  20. package/visualmetrics/test_data/ms_001520.png +0 -0
  21. package/visualmetrics/test_data/ms_002040.png +0 -0
  22. package/visualmetrics/test_data/ms_002600.png +0 -0
  23. package/visualmetrics/test_data/ms_003160.png +0 -0
  24. package/visualmetrics/test_data/ms_003720.png +0 -0
  25. package/visualmetrics/test_data/ms_004280.png +0 -0
  26. package/visualmetrics/test_data/ms_004880.png +0 -0
  27. package/visualmetrics/test_data/ms_005440.png +0 -0
  28. package/visualmetrics/test_data/ms_006000.png +0 -0
  29. package/visualmetrics/test_visualmetrics.py +34 -0
  30. package/visualmetrics/visualmetrics-portable.py +1969 -0
  31. package/visualmetrics/visualmetrics.py +2518 -0
  32. package/CONTRIBUTING.md +0 -24
  33. package/docs/examples/README.md +0 -9
  34. package/docs/examples/advance.md +0 -12
  35. package/docs/examples/android.md +0 -54
  36. package/docs/examples/basic.md +0 -36
  37. package/docs/examples/chrome.md +0 -28
  38. package/docs/examples/firefox.md +0 -10
  39. package/docs/issues.md +0 -18
  40. package/docs/new-style-script-objects.md +0 -38
  41. package/docs/sequence-diagrams/loadAndWait.wsd +0 -24
  42. package/docs/sequence-diagrams/run.wsd +0 -24
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Browsertime changelog (we do [semantic versioning](https://semver.org))
2
2
 
3
+ ## 20.0.0 - 2023-12-22
4
+
5
+ ### Breaking
6
+ * Changed `--userTimingWhitelist` to `--userTimingAllowList` in [#2023](https://github.com/sitespeedio/browsertime/pull/2023).
7
+ * Reading pageCompleteCheck JavaScript from file now works as intended. It should be a plain JavaScript file named .js [#2034](https://github.com/sitespeedio/browsertime/pull/2034) see [#912](https://github.com/sitespeedio/browsertime/issues/912)
8
+
9
+ ### Fixed
10
+ * Group page load parameters as PageLoad to make them easier to find using `--help` [#2035](https://github.com/sitespeedio/browsertime/pull/2035).
11
+ * Fix starting Firefox 121 on Mac [#2043](https://github.com/sitespeedio/browsertime/pull/2043).
12
+
13
+ ### Added
14
+ * Firefox 121 in the Docker container.g
15
+
16
+ ## 19.3.1 - 2023-12-18
17
+ ### Fixed
18
+ * Ensure that visual metrics python script is included in the release.
19
+
3
20
  ## 19.3.0 - 2023-12-18
4
21
 
5
22
  ### Added
package/README.md CHANGED
@@ -168,13 +168,14 @@ To get the HAR from Firefox we use the [HAR Export Trigger](https://github.com/f
168
168
 
169
169
  We welcome contributions from the community! Whether you're fixing a bug, adding a feature, or improving documentation, your help is valuable. Here’s how you can contribute:
170
170
 
171
- 1. **Fork and Clone**: Fork the repository and clone it locally.
172
- 2. **Create a Branch**: Create a new branch for your feature or bug fix.
173
- 3. **Develop**: Make your changes. Ensure you adhere to the coding standards and write tests if applicable.
174
- 4. **Test**: Run tests to ensure everything works as expected.
175
- 5. **Submit a Pull Request**: Push your changes to your fork and submit a pull request to the main repository.
171
+ 1. **Create an Issue**: Create an issue and discuss with us how to implement the issue.
172
+ 2. **Fork and Clone**: Fork the repository and clone it locally.
173
+ 3. **Create a Branch**: Create a new branch for your feature or bug fix.
174
+ 4. **Develop**: Make your changes. Ensure you adhere to the coding standards and write tests if applicable.
175
+ 5. **Test**: Run tests to ensure everything works as expected.
176
+ 6. **Submit a Pull Request**: Push your changes to your fork and submit a pull request to the main repository.
176
177
 
177
- Before contributing, please read our [CONTRIBUTING.md](CONTRIBUTING.md) for more detailed information on how to contribute.
178
+ Before contributing, please read our [CONTRIBUTING.md](.github/CONTRIBUTING.md) for more detailed information on how to contribute.
178
179
 
179
180
  ### Reporting Issues
180
181
  Found a bug or have a feature request? Please use the [GitHub Issues](https://github.com/sitespeedio/browsertime/issues) to report them. Be sure to check existing issues to avoid duplicates.
@@ -185,6 +186,8 @@ Join our community! Whether you need help, want to share your experience, or dis
185
186
 
186
187
  - **Slack**: Connect with fellow users and the development team on [Slack](https://join.slack.com/t/sitespeedio/shared_invite/zt-296jzr7qs-d6DId2KpEnMPJSQ8_R~WFw).
187
188
  - **GitHub Issues**: For technical questions, feature requests, and bug reports, use our [GitHub issues](https://github.com/sitespeedio/browsertime/issues).
189
+ - **RSS/Changelog**: Latest releases and information can always be found in our [RSS feed](https://github.com/sitespeedio/browsertime/releases.atom) and in our [changelog](https://github.com/sitespeedio/browsertime/blob/main/CHANGELOG.md).
190
+ - **Mastodon**: Follow us on Mastodon [https://fosstodon.org/@sitespeedio](https://fosstodon.org/@sitespeedio).
188
191
 
189
192
  We're excited to have you in our community and look forward to your contributions and interactions!
190
193
 
@@ -6,7 +6,7 @@ import { timestamp as _timestamp } from '../../../support/engineUtils.js';
6
6
  import { Video } from '../../../video/video.js';
7
7
  import { pathToFolder } from '../../../support/pathToFolder.js';
8
8
  import { setOrangeBackground } from '../../../video/screenRecording/setOrangeBackground.js';
9
- import { filterWhitelisted } from '../../../support/userTiming.js';
9
+ import { filterAllowlisted } from '../../../support/userTiming.js';
10
10
  import { isAndroidConfigured, Android } from '../../../android/index.js';
11
11
  import { TCPDump } from '../../../support/tcpdump.js';
12
12
  import { lcpHighlightScript as highlightLargestContentfulPaint } from './util/lcpHighlightScript.js';
@@ -487,11 +487,11 @@ export class Measure {
487
487
 
488
488
  // Some sites has crazy amount of user timings:
489
489
  // strip them if you want
490
- if (this.options.userTimingWhitelist) {
491
- filterWhitelisted(
490
+ if (this.options.userTimingAllowList) {
491
+ filterAllowlisted(
492
492
  this.result[this.numberOfMeasuredPages].browserScripts.timings
493
493
  .userTimings,
494
- this.options.userTimingWhitelist
494
+ this.options.userTimingAllowList
495
495
  );
496
496
  }
497
497
 
@@ -26,7 +26,11 @@ import { Android, isAndroidConfigured } from '../../android/index.js';
26
26
  import { RootedDevice } from '../../android/root.js';
27
27
  import { run } from './run.js';
28
28
  import { IOSRecorder } from '../../video/screenRecording/ios/iosRecorder.js';
29
- import { loadPrePostScripts, loadScript } from '../../support/engineUtils.js';
29
+ import {
30
+ loadPrePostScripts,
31
+ loadScript,
32
+ loadPageCompleteScript
33
+ } from '../../support/engineUtils.js';
30
34
  const log = intel.getLogger('browsertime');
31
35
  const defaults = {
32
36
  scripts: [],
@@ -260,7 +264,7 @@ export class Engine {
260
264
  postScripts = await loadPrePostScripts(options.postScript, options);
261
265
  postURLScripts = await loadPrePostScripts(options.postURLScript, options);
262
266
  pageCompleteCheck = options.pageCompleteCheck
263
- ? await loadScript(options.pageCompleteCheck, options)
267
+ ? await loadPageCompleteScript(options.pageCompleteCheck)
264
268
  : undefined;
265
269
  } catch (error) {
266
270
  log.error(error.message);
@@ -1,6 +1,7 @@
1
1
  import { resolve } from 'node:path';
2
2
  import { fileURLToPath } from 'node:url';
3
3
  import path from 'node:path';
4
+ import { platform } from 'node:os';
4
5
  import {
5
6
  ServiceBuilder,
6
7
  Options,
@@ -168,9 +169,36 @@ export async function configureBuilder(builder, baseDir, options) {
168
169
  // https://bugzilla.mozilla.org/show_bug.cgi?id=1751196
169
170
 
170
171
  if (!isAndroidConfigured(options)) {
171
- ffOptions.setBinary(
172
- firefoxTypes.length > 0 ? firefoxTypes[0] : Channel.RELEASE
173
- );
172
+ // Fix for https://github.com/sitespeedio/browsertime/issues/2041
173
+ if (platform() === 'darwin') {
174
+ if (
175
+ !firefoxConfig.binaryPath &&
176
+ !firefoxConfig.nightly &&
177
+ !firefoxConfig.beta &&
178
+ !firefoxConfig.developer
179
+ ) {
180
+ ffOptions.setBinary('/Applications/Firefox.app/Contents/MacOS/firefox');
181
+ } else if (firefoxConfig.nightly) {
182
+ ffOptions.setBinary(
183
+ '/Applications/Firefox Nightly.app/Contents/MacOS/firefox'
184
+ );
185
+ } else if (firefoxConfig.beta) {
186
+ ffOptions.setBinary(
187
+ '/Applications/Firefox Nightly.app/Contents/MacOS/firefox'
188
+ );
189
+ } else if (firefoxConfig.developer) {
190
+ ffOptions.setBinary(
191
+ '/Applications/FirefoxDeveloperEdition.app/Contents/MacOS/firefox'
192
+ );
193
+ } else if (firefoxConfig.binaryPath) {
194
+ ffOptions.setBinary(firefoxConfig.binaryPath);
195
+ }
196
+ } else {
197
+ // See https://github.com/sitespeedio/browsertime/issues/2041
198
+ ffOptions.setBinary(
199
+ firefoxTypes.length > 0 ? firefoxTypes[0] : Channel.RELEASE
200
+ );
201
+ }
174
202
  }
175
203
 
176
204
  ffOptions.addArguments('-no-remote');
@@ -905,43 +905,50 @@ export function parseCommandLine() {
905
905
  })
906
906
  .option('pageCompleteCheck', {
907
907
  describe:
908
- 'Supply a JavaScript (inline or JavaScript file) that decides when the browser is finished loading the page and can start to collect metrics. The JavaScript snippet is repeatedly queried to see if page has completed loading (indicated by the script returning true). Use it to fetch timings happening after the loadEventEnd. By default the tests ends 2 seconds after loadEventEnd. Also checkout --pageCompleteCheckInactivity and --pageCompleteCheckPollTimeout'
908
+ 'Supply a JavaScript (inline or JavaScript file) that decides when the browser is finished loading the page and can start to collect metrics. The JavaScript snippet is repeatedly queried to see if page has completed loading (indicated by the script returning true). Use it to fetch timings happening after the loadEventEnd. By default the tests ends 2 seconds after loadEventEnd. Also checkout --pageCompleteCheckInactivity and --pageCompleteCheckPollTimeout',
909
+ group: 'PageLoad'
909
910
  })
910
911
  .option('pageCompleteWaitTime', {
911
912
  describe:
912
913
  'How long time you want to wait for your pageComplteteCheck to finish, after it is signaled to closed. Extra parameter passed on to your pageCompleteCheck.',
913
- default: 8000
914
+ default: 8000,
915
+ group: 'PageLoad'
914
916
  })
915
917
  .option('pageCompleteCheckInactivity', {
916
918
  describe:
917
919
  'Alternative way to choose when to end your test. This will wait for 2 seconds of inactivity that happens after loadEventEnd.',
918
920
  type: 'boolean',
919
- default: false
921
+ default: false,
922
+ group: 'PageLoad'
920
923
  })
921
924
  .option('pageCompleteCheckNetworkIdle', {
922
925
  describe:
923
926
  'Alternative way to choose when to end your test that works in Chrome and Firefox. Uses CDP or WebDriver Bidi to look at network traffic instead of running JavaScript in the browser to know when to end the test. By default this will wait 5 seconds of inactivity in the network log (no requets/responses in 5 seconds). Use --timeouts.networkIdle to change the 5 seconds. The test will end after 2 minutes if there is still activity on the network. You can change that timout using --timeouts.pageCompleteCheck ',
924
927
  type: 'boolean',
925
- default: false
928
+ default: false,
929
+ group: 'PageLoad'
926
930
  })
927
931
  .option('pageCompleteCheckPollTimeout', {
928
932
  type: 'number',
929
933
  default: 1500,
930
934
  describe:
931
- 'The time in ms to wait for running the page complete check the next time.'
935
+ 'The time in ms to wait for running the page complete check the next time.',
936
+ group: 'PageLoad'
932
937
  })
933
938
  .option('pageCompleteCheckStartWait', {
934
939
  type: 'number',
935
940
  default: 5000,
936
941
  describe:
937
- 'The time in ms to wait for running the page complete check for the first time. Use this when you have a pageLoadStrategy set to none'
942
+ 'The time in ms to wait for running the page complete check for the first time. Use this when you have a pageLoadStrategy set to none',
943
+ group: 'PageLoad'
938
944
  })
939
945
  .option('pageLoadStrategy', {
940
946
  type: 'string',
941
947
  default: 'none',
942
948
  choices: ['eager', 'none', 'normal'],
943
949
  describe:
944
- 'Set the strategy to waiting for document readiness after a navigation event. After the strategy is ready, your pageCompleteCheck will start runninhg.'
950
+ 'Set the strategy to waiting for document readiness after a navigation event. After the strategy is ready, your pageCompleteCheck will start running.',
951
+ group: 'PageLoad'
945
952
  })
946
953
  .option('iterations', {
947
954
  alias: 'n',
@@ -965,13 +972,15 @@ export function parseCommandLine() {
965
972
  type: 'number',
966
973
  default: 0,
967
974
  describe:
968
- 'Extra time added for the browser to settle before starting to test a URL. This delay happens after the browser was opened and before the navigation to the URL'
975
+ 'Extra time added for the browser to settle before starting to test a URL. This delay happens after the browser was opened and before the navigation to the URL',
976
+ group: 'PageLoad'
969
977
  })
970
978
  .option('webdriverPageload', {
971
979
  type: 'boolean',
972
980
  describe:
973
981
  'Use webdriver.get to initialize the page load instead of window.location.',
974
- default: false
982
+ default: false,
983
+ group: 'PageLoad'
975
984
  })
976
985
  .option('proxy.pac', {
977
986
  type: 'string',
@@ -1106,7 +1115,8 @@ export function parseCommandLine() {
1106
1115
  describe:
1107
1116
  'Use internal browser functionality to clear browser cache between runs instead of only using Selenium.',
1108
1117
  type: 'boolean',
1109
- default: false
1118
+ default: false,
1119
+ group: 'PageLoad'
1110
1120
  })
1111
1121
  .option('basicAuth', {
1112
1122
  describe:
@@ -1211,9 +1221,9 @@ export function parseCommandLine() {
1211
1221
  type: 'integer',
1212
1222
  default: 1500
1213
1223
  })
1214
- .option('userTimingWhitelist', {
1224
+ .option('userTimingAllowList', {
1215
1225
  describe:
1216
- 'All userTimings are captured by default this option takes a regex that will whitelist which userTimings to capture in the results.'
1226
+ 'All userTimings are captured by default this option takes a regex that will allow which userTimings to capture in the results.'
1217
1227
  })
1218
1228
  .option('headless', {
1219
1229
  type: 'boolean',
@@ -1233,7 +1243,8 @@ export function parseCommandLine() {
1233
1243
  type: 'boolean',
1234
1244
  default: false,
1235
1245
  describe:
1236
- 'Flush DNS between runs, works on Mac OS and Linux. Your user needs sudo rights to be able to flush the DNS.'
1246
+ 'Flush DNS between runs, works on Mac OS and Linux. Your user needs sudo rights to be able to flush the DNS.',
1247
+ group: 'PageLoad'
1237
1248
  })
1238
1249
  .option('extension', {
1239
1250
  describe:
@@ -1243,7 +1254,8 @@ export function parseCommandLine() {
1243
1254
  describe:
1244
1255
  'Convenient parameter to use if you test a SPA application: will automatically wait for X seconds after last network activity and use hash in file names. Read more: https://www.sitespeed.io/documentation/sitespeed.io/spa/',
1245
1256
  type: 'boolean',
1246
- default: false
1257
+ default: false,
1258
+ group: 'PageLoad'
1247
1259
  })
1248
1260
  .option('cjs', {
1249
1261
  describe:
@@ -1255,7 +1267,8 @@ export function parseCommandLine() {
1255
1267
  type: 'number',
1256
1268
  default: 3,
1257
1269
  describe:
1258
- 'If the browser fails to start, you can retry to start it this amount of times.'
1270
+ 'If the browser fails to start, you can retry to start it this amount of times.',
1271
+ group: 'PageLoad'
1259
1272
  })
1260
1273
  .option('preWarmServer', {
1261
1274
  type: 'boolean',
@@ -1,12 +1,17 @@
1
1
  import { resolve, dirname, join } from 'node:path';
2
2
  import { promisify } from 'node:util';
3
- import { writeFile as _writeFile, unlink as _unlink } from 'node:fs';
3
+ import {
4
+ writeFile as _writeFile,
5
+ unlink as _unlink,
6
+ readFile as _readFile
7
+ } from 'node:fs';
4
8
  import { pathToFileURL } from 'node:url';
5
9
  import dayjs from 'dayjs';
6
10
  import intel from 'intel';
7
11
  import { toArray } from '../support/util.js';
8
12
  const log = intel.getLogger('browsertime');
9
13
  const writeFile = promisify(_writeFile);
14
+ const readFile = promisify(_readFile);
10
15
  const unlink = promisify(_unlink);
11
16
 
12
17
  const AsyncFunction = Object.getPrototypeOf(async function () {}).constructor;
@@ -82,6 +87,13 @@ export async function loadPrePostScripts(scripts, options) {
82
87
  return readScripts;
83
88
  }
84
89
 
90
+ export async function loadPageCompleteScript(script) {
91
+ if (script && script.endsWith('js')) {
92
+ return readFile(resolve(script), 'utf8');
93
+ }
94
+ return script;
95
+ }
96
+
85
97
  export async function loadScript(script, options, throwError) {
86
98
  if (script) {
87
99
  return loadFile(script, options, throwError);
@@ -1,5 +1,5 @@
1
- export function filterWhitelisted(userTimings, whitelistRegex) {
2
- const allowed = new RegExp(whitelistRegex);
1
+ export function filterAllowlisted(userTimings, allowlistRegex) {
2
+ const allowed = new RegExp(allowlistRegex);
3
3
  userTimings.marks = userTimings.marks.filter(mark => allowed.test(mark.name));
4
4
  userTimings.measures = userTimings.measures.filter(measure =>
5
5
  allowed.test(measure.name)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "browsertime",
3
3
  "description": "Get performance metrics from your web page using Browsertime.",
4
- "version": "19.3.0",
4
+ "version": "20.0.0",
5
5
  "bin": "./bin/browsertime.js",
6
6
  "type": "module",
7
7
  "dependencies": {
@@ -56,9 +56,8 @@
56
56
  "bin",
57
57
  "browserscripts",
58
58
  "browsersupport",
59
- "browsertime",
59
+ "visualmetrics",
60
60
  "browsertime.png",
61
- "docs",
62
61
  "index.js",
63
62
  "lib",
64
63
  "package.json",
@@ -0,0 +1 @@
1
+ #
@@ -0,0 +1,34 @@
1
+ import unittest
2
+ import os
3
+
4
+ from browsertime.visualmetrics import (
5
+ calculate_contentful_speed_index,
6
+ calculate_perceptual_speed_index,
7
+ )
8
+
9
+ HERE = os.path.dirname(__file__)
10
+
11
+
12
+ class TestVisualMetrics(unittest.TestCase):
13
+ def setUp(self):
14
+ self.directory = "test_data"
15
+ images = os.listdir(os.path.join(HERE, self.directory))
16
+
17
+ def _p(image):
18
+ p = {}
19
+ p["time"] = int(image.split(".")[0].split("ms_")[-1])
20
+ return p
21
+
22
+ progress = [_p(image) for image in images if image.startswith("ms_")]
23
+ self.sorted_progress = sorted(progress,
24
+ key = lambda image: image['time'])
25
+
26
+ def test_calculate_contentful_speed_index(self):
27
+ res = calculate_contentful_speed_index(self.sorted_progress,
28
+ self.directory)
29
+ self.assertEqual(res[0], 1188)
30
+
31
+ def test_calculate_perceptual_speed_index(self):
32
+ res = calculate_perceptual_speed_index(self.sorted_progress,
33
+ self.directory)
34
+ self.assertEqual(res[0], 946)