browsertime 20.0.0 → 21.1.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 (212) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -2
  3. package/bin/browsertime.js +9 -3
  4. package/browserscripts/pageinfo/interactionToNextPaintInfo.js +170 -143
  5. package/browserscripts/timings/interactionToNextPaint.js +49 -137
  6. package/lib/chrome/webdriver/setupChromiumOptions.js +0 -9
  7. package/lib/core/engine/collector.js +11 -0
  8. package/lib/core/engine/command/actions.js +52 -0
  9. package/lib/core/engine/command/addText.js +48 -30
  10. package/lib/core/engine/command/android.js +43 -4
  11. package/lib/core/engine/command/cache.js +39 -2
  12. package/lib/core/engine/command/chromeDevToolsProtocol.js +51 -1
  13. package/lib/core/engine/command/chromeTrace.js +34 -0
  14. package/lib/core/engine/command/click.js +102 -52
  15. package/lib/core/engine/command/debug.js +19 -2
  16. package/lib/core/engine/command/element.js +66 -0
  17. package/lib/core/engine/command/geckoProfiler.js +41 -1
  18. package/lib/core/engine/command/javaScript.js +43 -20
  19. package/lib/core/engine/command/measure.js +147 -15
  20. package/lib/core/engine/command/meta.js +17 -0
  21. package/lib/core/engine/command/mouse/clickAndHold.js +56 -29
  22. package/lib/core/engine/command/mouse/contextClick.js +30 -11
  23. package/lib/core/engine/command/mouse/doubleClick.js +35 -11
  24. package/lib/core/engine/command/mouse/mouseMove.js +38 -16
  25. package/lib/core/engine/command/mouse/singleClick.js +187 -12
  26. package/lib/core/engine/command/navigation.js +31 -3
  27. package/lib/core/engine/command/screenshot.js +33 -0
  28. package/lib/core/engine/command/scroll.js +35 -13
  29. package/lib/core/engine/command/select.js +55 -36
  30. package/lib/core/engine/command/set.js +51 -36
  31. package/lib/core/engine/command/stopWatch.js +30 -9
  32. package/lib/core/engine/command/switch.js +49 -11
  33. package/lib/core/engine/command/wait.js +50 -25
  34. package/lib/core/engine/commands.js +267 -0
  35. package/lib/core/engine/context.js +81 -0
  36. package/lib/core/engine/iteration.js +20 -102
  37. package/lib/firefox/geckoProfiler.js +49 -1
  38. package/lib/firefox/webdriver/builder.js +4 -9
  39. package/lib/firefox/webdriver/firefox.js +1 -1
  40. package/lib/support/cli.js +7 -0
  41. package/lib/support/getViewPort.js +6 -1
  42. package/lib/support/statistics.js +11 -1
  43. package/package.json +22 -12
  44. package/types/android/index.d.ts +70 -0
  45. package/types/android/index.d.ts.map +1 -0
  46. package/types/chrome/parseCpuTrace.d.ts +21 -0
  47. package/types/chrome/parseCpuTrace.d.ts.map +1 -0
  48. package/types/chrome/traceCategoriesParser.d.ts +2 -0
  49. package/types/chrome/traceCategoriesParser.d.ts.map +1 -0
  50. package/types/chrome/webdriver/traceUtilities.d.ts +8 -0
  51. package/types/chrome/webdriver/traceUtilities.d.ts.map +1 -0
  52. package/types/core/engine/command/action.d.ts +73 -0
  53. package/types/core/engine/command/action.d.ts.map +1 -0
  54. package/types/core/engine/command/actions.d.ts +38 -0
  55. package/types/core/engine/command/actions.d.ts.map +1 -0
  56. package/types/core/engine/command/addText.d.ts +68 -0
  57. package/types/core/engine/command/addText.d.ts.map +1 -0
  58. package/types/core/engine/command/android.d.ts +39 -0
  59. package/types/core/engine/command/android.d.ts.map +1 -0
  60. package/types/core/engine/command/cache.d.ts +53 -0
  61. package/types/core/engine/command/cache.d.ts.map +1 -0
  62. package/types/core/engine/command/chromeDevToolsProtocol.d.ts +61 -0
  63. package/types/core/engine/command/chromeDevToolsProtocol.d.ts.map +1 -0
  64. package/types/core/engine/command/chromeTrace.d.ts +45 -0
  65. package/types/core/engine/command/chromeTrace.d.ts.map +1 -0
  66. package/types/core/engine/command/click.d.ts +151 -0
  67. package/types/core/engine/command/click.d.ts.map +1 -0
  68. package/types/core/engine/command/debug.d.ts +28 -0
  69. package/types/core/engine/command/debug.d.ts.map +1 -0
  70. package/types/core/engine/command/element.d.ts +49 -0
  71. package/types/core/engine/command/element.d.ts.map +1 -0
  72. package/types/core/engine/command/geckoProfiler.d.ts +46 -0
  73. package/types/core/engine/command/geckoProfiler.d.ts.map +1 -0
  74. package/types/core/engine/command/javaScript.d.ts +63 -0
  75. package/types/core/engine/command/javaScript.d.ts.map +1 -0
  76. package/types/core/engine/command/measure.d.ts +194 -0
  77. package/types/core/engine/command/measure.d.ts.map +1 -0
  78. package/types/core/engine/command/meta.d.ts +23 -0
  79. package/types/core/engine/command/meta.d.ts.map +1 -0
  80. package/types/core/engine/command/mouse/clickAndHold.d.ts +82 -0
  81. package/types/core/engine/command/mouse/clickAndHold.d.ts.map +1 -0
  82. package/types/core/engine/command/mouse/contextClick.d.ts +44 -0
  83. package/types/core/engine/command/mouse/contextClick.d.ts.map +1 -0
  84. package/types/core/engine/command/mouse/doubleClick.d.ts +51 -0
  85. package/types/core/engine/command/mouse/doubleClick.d.ts.map +1 -0
  86. package/types/core/engine/command/mouse/index.d.ts +6 -0
  87. package/types/core/engine/command/mouse/index.d.ts.map +1 -0
  88. package/types/core/engine/command/mouse/mouseMove.d.ts +56 -0
  89. package/types/core/engine/command/mouse/mouseMove.d.ts.map +1 -0
  90. package/types/core/engine/command/mouse/singleClick.d.ts +115 -0
  91. package/types/core/engine/command/mouse/singleClick.d.ts.map +1 -0
  92. package/types/core/engine/command/navigation.d.ts +45 -0
  93. package/types/core/engine/command/navigation.d.ts.map +1 -0
  94. package/types/core/engine/command/screenshot.d.ts +33 -0
  95. package/types/core/engine/command/screenshot.d.ts.map +1 -0
  96. package/types/core/engine/command/scroll.d.ts +52 -0
  97. package/types/core/engine/command/scroll.d.ts.map +1 -0
  98. package/types/core/engine/command/select.d.ts +81 -0
  99. package/types/core/engine/command/select.d.ts.map +1 -0
  100. package/types/core/engine/command/set.d.ts +74 -0
  101. package/types/core/engine/command/set.d.ts.map +1 -0
  102. package/types/core/engine/command/stopWatch.d.ts +49 -0
  103. package/types/core/engine/command/stopWatch.d.ts.map +1 -0
  104. package/types/core/engine/command/switch.d.ts +77 -0
  105. package/types/core/engine/command/switch.d.ts.map +1 -0
  106. package/types/core/engine/command/util/lcpHighlightScript.d.ts +2 -0
  107. package/types/core/engine/command/util/lcpHighlightScript.d.ts.map +1 -0
  108. package/types/core/engine/command/util/lsHighlightScript.d.ts +2 -0
  109. package/types/core/engine/command/util/lsHighlightScript.d.ts.map +1 -0
  110. package/types/core/engine/command/wait.d.ts +74 -0
  111. package/types/core/engine/command/wait.d.ts.map +1 -0
  112. package/types/core/engine/commands.d.ts +161 -0
  113. package/types/core/engine/commands.d.ts.map +1 -0
  114. package/types/core/engine/context.d.ts +87 -0
  115. package/types/core/engine/context.d.ts.map +1 -0
  116. package/types/firefox/geckoProfiler.d.ts +11 -0
  117. package/types/firefox/geckoProfiler.d.ts.map +1 -0
  118. package/types/firefox/settings/geckoProfilerDefaults.d.ts +8 -0
  119. package/types/firefox/settings/geckoProfilerDefaults.d.ts.map +1 -0
  120. package/types/scripting.d.ts +2 -0
  121. package/types/support/engineUtils.d.ts +5 -0
  122. package/types/support/engineUtils.d.ts.map +1 -0
  123. package/types/support/errors.d.ts +15 -0
  124. package/types/support/errors.d.ts.map +1 -0
  125. package/types/support/fileUtil.d.ts +10 -0
  126. package/types/support/fileUtil.d.ts.map +1 -0
  127. package/types/support/filters.d.ts +7 -0
  128. package/types/support/filters.d.ts.map +1 -0
  129. package/types/support/getViewPort.d.ts +2 -0
  130. package/types/support/getViewPort.d.ts.map +1 -0
  131. package/types/support/pathToFolder.d.ts +2 -0
  132. package/types/support/pathToFolder.d.ts.map +1 -0
  133. package/types/support/storageManager.d.ts +17 -0
  134. package/types/support/storageManager.d.ts.map +1 -0
  135. package/types/support/tcpdump.d.ts +10 -0
  136. package/types/support/tcpdump.d.ts.map +1 -0
  137. package/types/support/userTiming.d.ts +2 -0
  138. package/types/support/userTiming.d.ts.map +1 -0
  139. package/types/support/util.d.ts +6 -0
  140. package/types/support/util.d.ts.map +1 -0
  141. package/types/video/defaults.d.ts +7 -0
  142. package/types/video/defaults.d.ts.map +1 -0
  143. package/types/video/postprocessing/finetune/addTextToVideo.d.ts +2 -0
  144. package/types/video/postprocessing/finetune/addTextToVideo.d.ts.map +1 -0
  145. package/types/video/postprocessing/finetune/convertFps.d.ts +2 -0
  146. package/types/video/postprocessing/finetune/convertFps.d.ts.map +1 -0
  147. package/types/video/postprocessing/finetune/getFont.d.ts +2 -0
  148. package/types/video/postprocessing/finetune/getFont.d.ts.map +1 -0
  149. package/types/video/postprocessing/finetune/getTimingMetrics.d.ts +2 -0
  150. package/types/video/postprocessing/finetune/getTimingMetrics.d.ts.map +1 -0
  151. package/types/video/postprocessing/finetune/index.d.ts +2 -0
  152. package/types/video/postprocessing/finetune/index.d.ts.map +1 -0
  153. package/types/video/postprocessing/finetune/removeOrange.d.ts +2 -0
  154. package/types/video/postprocessing/finetune/removeOrange.d.ts.map +1 -0
  155. package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts +5 -0
  156. package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts.map +1 -0
  157. package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts +5 -0
  158. package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts.map +1 -0
  159. package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts +3 -0
  160. package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts.map +1 -0
  161. package/types/video/screenRecording/android/recorder.d.ts +11 -0
  162. package/types/video/screenRecording/android/recorder.d.ts.map +1 -0
  163. package/types/video/screenRecording/desktop/convert.d.ts +2 -0
  164. package/types/video/screenRecording/desktop/convert.d.ts.map +1 -0
  165. package/types/video/screenRecording/desktop/desktopRecorder.d.ts +28 -0
  166. package/types/video/screenRecording/desktop/desktopRecorder.d.ts.map +1 -0
  167. package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts +17 -0
  168. package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts.map +1 -0
  169. package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts +2 -0
  170. package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts.map +1 -0
  171. package/types/video/screenRecording/desktop/osx/getScreen.d.ts +2 -0
  172. package/types/video/screenRecording/desktop/osx/getScreen.d.ts.map +1 -0
  173. package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts +13 -0
  174. package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts.map +1 -0
  175. package/types/video/screenRecording/ios/convertToMp4.d.ts +2 -0
  176. package/types/video/screenRecording/ios/convertToMp4.d.ts.map +1 -0
  177. package/types/video/screenRecording/ios/iosRecorder.d.ts +14 -0
  178. package/types/video/screenRecording/ios/iosRecorder.d.ts.map +1 -0
  179. package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts +2 -0
  180. package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts.map +1 -0
  181. package/types/video/screenRecording/iosSimulator/recorder.d.ts +9 -0
  182. package/types/video/screenRecording/iosSimulator/recorder.d.ts.map +1 -0
  183. package/types/video/screenRecording/recorder.d.ts +7 -0
  184. package/types/video/screenRecording/recorder.d.ts.map +1 -0
  185. package/types/video/screenRecording/setOrangeBackground.d.ts +2 -0
  186. package/types/video/screenRecording/setOrangeBackground.d.ts.map +1 -0
  187. package/types/video/video.d.ts +41 -0
  188. package/types/video/video.d.ts.map +1 -0
  189. package/browsersupport/firefox-profile/cert9.db +0 -0
  190. package/browsersupport/firefox-profile/chrome/userChrome.css +0 -4
  191. package/browsersupport/firefox-profile/key4.db +0 -0
  192. package/vendor/mac/x86/qvh +0 -0
  193. package/visualmetrics/__init__.py +0 -1
  194. package/visualmetrics/test_data/ms_000000.png +0 -0
  195. package/visualmetrics/test_data/ms_000920.png +0 -0
  196. package/visualmetrics/test_data/ms_001000.png +0 -0
  197. package/visualmetrics/test_data/ms_001080.png +0 -0
  198. package/visualmetrics/test_data/ms_001200.png +0 -0
  199. package/visualmetrics/test_data/ms_001240.png +0 -0
  200. package/visualmetrics/test_data/ms_001280.png +0 -0
  201. package/visualmetrics/test_data/ms_001360.png +0 -0
  202. package/visualmetrics/test_data/ms_001400.png +0 -0
  203. package/visualmetrics/test_data/ms_001520.png +0 -0
  204. package/visualmetrics/test_data/ms_002040.png +0 -0
  205. package/visualmetrics/test_data/ms_002600.png +0 -0
  206. package/visualmetrics/test_data/ms_003160.png +0 -0
  207. package/visualmetrics/test_data/ms_003720.png +0 -0
  208. package/visualmetrics/test_data/ms_004280.png +0 -0
  209. package/visualmetrics/test_data/ms_004880.png +0 -0
  210. package/visualmetrics/test_data/ms_005440.png +0 -0
  211. package/visualmetrics/test_data/ms_006000.png +0 -0
  212. package/visualmetrics/test_visualmetrics.py +0 -34
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Browsertime changelog (we do [semantic versioning](https://semver.org))
2
2
 
3
+ ## 21.1.0 - 2024-01-24
4
+ ### Added
5
+ * Firefox 122, Chrome 121 and Chromedriver 121 [#2067](https://github.com/sitespeedio/browsertime/pull/2067).
6
+
7
+ ### Fixed
8
+ * Set correct viewports for the following emulated mobiles for Chrome: iPad Mini iPad Air, iPhone 14 Pro, Pixel 7 and Samsung Galaxy A51/71 [#2065](https://github.com/sitespeedio/browsertime/pull/2065).
9
+
10
+ ## 21.0.0 - 2024-01-07
11
+
12
+ The new version uses JSDoc to generate documentation for scripting and make it possible to use code completion/Intellisense! You can read the [new documentation here](https://www.sitespeed.io/documentation/sitespeed.io/scripting/tutorial-08-Setting-Up-IntelliSense.html).
13
+
14
+ ### Added
15
+ * Upgraded to [Geckodriver 0.34.0](https://github.com/mozilla/geckodriver/releases/tag/v0.34.0) [#2049](https://github.com/sitespeedio/browsertime/pull/2049).
16
+ * Collect CPU consumption for Firefox. Turn that on with `--firefox.powerConsumption true` and including `power` as a geckoProfilerParams.features [#2046](https://github.com/sitespeedio/browsertime/pull/2046).
17
+ * Added more commands for mouse click on text [#2054](https://github.com/sitespeedio/browsertime/pull/2054).
18
+ * Updated AndroidCommand so you can run shell on your Android device as root [#2055](https://github.com/sitespeedio/browsertime/pull/2055).
19
+ * If you mark a test as failure, the exit code from Browsertime will be 1. If the exitCode is set in scripting, we use that and will not change that [#2057](https://github.com/sitespeedio/browsertime/pull/2057).
20
+ * Generate documentation for scripting using JSDoc [#2059](https://github.com/sitespeedio/browsertime/pull/2059).
21
+ * Make it easy to use Seleniums action API. Get access to the new command using commands.action.getActions() and chain the action. [#2061](https://github.com/sitespeedio/browsertime/pull/2061)
22
+
23
+
24
+ ### Fixed
25
+ * Make sure the visual metrics files are inlcuded in the Docker file [#2053](https://github.com/sitespeedio/browsertime/pull/2053).
26
+ * Removing QVH from the npm package (used for iPhone video recording but not working) [#2051](https://github.com/sitespeedio/browsertime/pull/2051)
27
+ * Removing visual metrics test images from the npm package [#2050](https://github.com/sitespeedio/browsertime/pull/2050).
28
+ * Removed the Chromedriver fix that was needed when Chrome for testing broke testing on Chrome :D [#2045](https://github.com/sitespeedio/browsertime/pull/2045).
29
+ * Refactor of commands/context object to prepare for supporting JSDoc and a little TypeScript to add code completion/IntelliSense in editors [#2047](https://github.com/sitespeedio/browsertime/pull/2047).
30
+ * Updated documentation for scripting with better JSDoc [#204](https://github.com/sitespeedio/browsertime/pull/2048).
31
+ * The code for getting Interaction to next paint was broken. This PR fixes it, make the code cleaner and gives more attribution [#2060](https://github.com/sitespeedio/browsertime/pull/2060).
32
+
3
33
  ## 20.0.0 - 2023-12-22
4
34
 
5
35
  ### Breaking
package/README.md CHANGED
@@ -133,13 +133,13 @@ You can change latency by setting a Docker environment variable. Use REPLAY to t
133
133
  Default browser is Chrome:
134
134
 
135
135
  ```
136
- docker run --cap-add=NET_ADMIN --rm -v "$(pwd)":/browsertime -e REPLAY=true -e LATENCY=100 sitespeedio/browsertime:12.0.0 https://en.wikipedia.org/wiki/Barack_Obama
136
+ docker run --cap-add=NET_ADMIN --rm -v "$(pwd)":/browsertime -e REPLAY=true -e LATENCY=100 sitespeedio/browsertime:20.0.0 https://en.wikipedia.org/wiki/Barack_Obama
137
137
  ```
138
138
 
139
139
  Use Firefox:
140
140
 
141
141
  ```shell
142
- docker run --cap-add=NET_ADMIN --rm -v "$(pwd)":/browsertime -e REPLAY=true -e LATENCY=100 sitespeedio/browsertime:19.2.0 -b firefox -n 11 --firefox.acceptInsecureCerts https://en.wikipedia.org/wiki/Barack_Obama
142
+ docker run --cap-add=NET_ADMIN --rm -v "$(pwd)":/browsertime -e REPLAY=true -e LATENCY=100 sitespeedio/browsertime:20.0.0 -b firefox -n 11 --firefox.acceptInsecureCerts true https://en.wikipedia.org/wiki/Barack_Obama
143
143
  ```
144
144
 
145
145
  And Chrome on your Android phone. This will only work on Linux because you need to be able to mount the usb port in Docker:
@@ -149,11 +149,17 @@ async function run(urls, options) {
149
149
  const resultDirectory = relative(process.cwd(), storageManager.directory);
150
150
 
151
151
  // check for errors
152
- for (let eachResult of result) {
153
- for (let errors of eachResult.errors) {
154
- if (errors.length > 0) {
152
+ // If we have set the exit code in scripts, respect that
153
+ if (process.exitCode === undefined) {
154
+ for (let eachResult of result) {
155
+ if (eachResult.markedAsFailure === 1) {
155
156
  process.exitCode = 1;
156
157
  }
158
+ for (let errors of eachResult.errors) {
159
+ if (errors.length > 0) {
160
+ process.exitCode = 1;
161
+ }
162
+ }
157
163
  }
158
164
  }
159
165
  log.info(`Wrote data to ${resultDirectory}`);
@@ -1,152 +1,179 @@
1
1
  (function () {
2
+ // https://github.com/GoogleChrome/web-vitals/blob/main/src/lib/getLoadState.ts#L20
2
3
 
3
- // This is an updated version of
4
- // https://github.com/GoogleChrome/web-vitals/blob/64f133590fcac72c1bc042bf7b4ab729d7e03316/src/onINP.ts
5
- // It was reworked the 19/5-2023
4
+ function getLoadState(timestamp) {
5
+ if (document.readyState === 'loading') {
6
+ // If the `readyState` is 'loading' there's no need to look at timestamps
7
+ // since the timestamp has to be the current time or earlier.
8
+ return 'loading';
9
+ } else {
10
+ const navigationEntry = performance.getEntriesByType('navigation')[0];
11
+ if (navigationEntry) {
12
+ if (timestamp < navigationEntry.domInteractive) {
13
+ return 'loading';
14
+ } else if (
15
+ navigationEntry.domContentLoadedEventStart === 0 ||
16
+ timestamp < navigationEntry.domContentLoadedEventStart
17
+ ) {
18
+ // If the `domContentLoadedEventStart` timestamp has not yet been
19
+ // set, or if the given timestamp is less than that value.
20
+ return 'dom-interactive';
21
+ } else if (
22
+ navigationEntry.domComplete === 0 ||
23
+ timestamp < navigationEntry.domComplete
24
+ ) {
25
+ // If the `domComplete` timestamp has not yet been
26
+ // set, or if the given timestamp is less than that value.
27
+ return 'dom-content-loaded';
28
+ }
29
+ }
30
+ }
31
+ // If any of the above fail, default to loaded. This could really only
32
+ // happy if the browser doesn't support the performance timeline, which
33
+ // most likely means this code would never run anyway.
34
+ return 'complete';
35
+ }
6
36
 
7
- const supported = PerformanceObserver.supportedEntryTypes;
8
- if (!supported || supported.indexOf('event') === -1 ||  supported.indexOf('first-input') === -1) {
9
- return;
37
+ // https://github.com/GoogleChrome/web-vitals/blob/main/src/lib/getSelector.ts#L24
38
+ function getName(node) {
39
+ const name = node.nodeName;
40
+ return node.nodeType === 1
41
+ ? name.toLowerCase()
42
+ : name.toUpperCase().replace(/^#/, '');
10
43
  }
11
- var observe = function observe(type, callback, opts) {
12
- try {
13
- if (PerformanceObserver.supportedEntryTypes.includes(type)) {
14
- var po = new PerformanceObserver(function (list) {
15
- Promise.resolve().then(function () {
16
- callback(list.getEntries());
17
- });
18
- });
19
- po.observe(Object.assign({type: type, buffered: true}, opts || {}));
20
- return po;
21
- }
22
- } catch (e) {}
23
- return;
24
- };
25
- var interactionCountEstimate = 0;
26
- var minKnownInteractionId = Infinity;
27
- var maxKnownInteractionId = 0;
28
- var updateEstimate = function updateEstimate(entries) {
29
- entries.forEach(function (e) {
30
- if (e.interactionId) {
31
- minKnownInteractionId = Math.min(
32
- minKnownInteractionId,
33
- e.interactionId
34
- );
35
- maxKnownInteractionId = Math.max(
36
- maxKnownInteractionId,
37
- e.interactionId
38
- );
39
- interactionCountEstimate = maxKnownInteractionId
40
- ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1
41
- : 0;
42
- }
43
- });
44
- };
45
- var po;
46
- var getInteractionCount = function getInteractionCount() {
47
- return po ? interactionCountEstimate : performance.interactionCount || 0;
48
- };
49
- var initInteractionCountPolyfill = function initInteractionCountPolyfill() {
50
- if ('interactionCount' in performance || po) return;
51
- po = observe('event', updateEstimate, {
52
- type: 'event',
53
- buffered: true,
54
- durationThreshold: 0,
55
- });
56
- };
57
- var prevInteractionCount = 0;
58
- var getInteractionCountForNavigation =
59
- function getInteractionCountForNavigation() {
60
- return getInteractionCount() - prevInteractionCount;
61
- };
62
- var MAX_INTERACTIONS_TO_CONSIDER = 10;
63
- var longestInteractionList = [];
64
- var longestInteractionMap = {};
65
- var processEntry = function processEntry(entry) {
66
- var minLongestInteraction =
67
- longestInteractionList[longestInteractionList.length - 1];
68
- var existingInteraction = longestInteractionMap[entry.interactionId];
69
- if (
70
- existingInteraction ||
71
- longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||
72
- entry.duration > minLongestInteraction.latency
73
- ) {
74
- if (existingInteraction) {
75
- existingInteraction.entries.push(entry);
76
- existingInteraction.latency = Math.max(
77
- existingInteraction.latency,
78
- entry.duration
79
- );
80
- } else {
81
- var interaction = {
82
- id: entry.interactionId,
83
- latency: entry.duration,
84
- entries: [entry],
85
- };
86
- longestInteractionMap[interaction.id] = interaction;
87
- longestInteractionList.push(interaction);
88
- }
89
- longestInteractionList.sort(function (a, b) {
90
- return b.latency - a.latency;
91
- });
92
- longestInteractionList
93
- .splice(MAX_INTERACTIONS_TO_CONSIDER)
94
- .forEach(function (i) {
95
- delete longestInteractionMap[i.id];
96
- });
44
+
45
+ function getSelector(node) {
46
+ let sel = '';
47
+
48
+ try {
49
+ while (node && node.nodeType !== 9) {
50
+ const el = node;
51
+ const part = el.id
52
+ ? '#' + el.id
53
+ : getName(el) +
54
+ (el.classList &&
55
+ el.classList.value &&
56
+ el.classList.value.trim() &&
57
+ el.classList.value.trim().length
58
+ ? '.' + el.classList.value.trim().replace(/\s+/g, '.')
59
+ : '');
60
+ if (sel.length + part.length > 100 - 1) return sel || part;
61
+ sel = sel ? part + '>' + sel : part;
62
+ if (el.id) break;
63
+ node = el.parentNode;
97
64
  }
98
- };
99
- var estimateP98LongestInteraction = function estimateP98LongestInteraction() {
100
- var candidateInteractionIndex = Math.min(
101
- longestInteractionList.length - 1,
102
- Math.floor(getInteractionCountForNavigation() / 50)
103
- );
104
- return longestInteractionList[candidateInteractionIndex];
105
- };
106
-
107
- var opts = {};
108
- var metric = {};
109
- initInteractionCountPolyfill();
110
- var handleEntries = function handleEntries(entries) {
111
- entries.forEach(function (entry) {
112
- if (entry.interactionId) {
113
- processEntry(entry);
114
- }
115
- if (entry.entryType === 'first-input') {
116
- var noMatchingEntry = !longestInteractionList.some(function (
117
- interaction
118
- ) {
119
- return interaction.entries.some(function (prevEntry) {
120
- return (
121
- entry.duration === prevEntry.duration &&
122
- entry.startTime === prevEntry.startTime
123
- );
124
- });
125
- });
126
- if (noMatchingEntry) {
127
- processEntry(entry);
65
+ } catch (err) {
66
+ // Do nothing...
67
+ }
68
+ return sel;
69
+ }
70
+
71
+ // https://gist.github.com/karlgroves/7544592
72
+ function getDomPath(el) {
73
+ const stack = [];
74
+ while (el.parentNode != null) {
75
+ let sibCount = 0;
76
+ let sibIndex = 0;
77
+ for (let i = 0; i < el.parentNode.childNodes.length; i++) {
78
+ let sib = el.parentNode.childNodes[i];
79
+ if (sib.nodeName == el.nodeName) {
80
+ if (sib === el) {
81
+ sibIndex = sibCount;
128
82
  }
83
+ sibCount++;
129
84
  }
130
- });
131
- var inp = estimateP98LongestInteraction();
132
- if (inp && inp.latency !== metric.value) {
133
- var cleanedEntries = [];
134
- for (var entry of inp.entries) {
135
- console.log(entry);
136
- cleanedEntries.push({
137
- id: entry.interactionId,
138
- latency: entry.duration,
139
- name: entry.name
140
- });
141
- }
142
- return {latency: inp.latency, entries: cleanedEntries};
143
85
  }
144
- };
145
- var po = observe('event', handleEntries, {
146
- durationThreshold: opts.durationThreshold || 40,
147
- });
148
- if (po) {
149
- po.observe({type: 'first-input', buffered: true});
86
+ if (el.hasAttribute && el.hasAttribute('id') && el.id != '') {
87
+ stack.unshift(el.nodeName.toLowerCase() + '#' + el.id);
88
+ } else if (sibCount > 1) {
89
+ stack.unshift(el.nodeName.toLowerCase() + ':eq(' + sibIndex + ')');
90
+ } else {
91
+ stack.unshift(el.nodeName.toLowerCase());
92
+ }
93
+ el = el.parentNode;
94
+ }
95
+
96
+ return stack.slice(1);
97
+ }
98
+
99
+ // https://github.com/GoogleChrome/web-vitals/blob/main/src/onINP.ts
100
+ const observer = new PerformanceObserver(list => {});
101
+ observer.observe({type: 'event', buffered: true});
102
+ observer.observe({type: 'first-input', buffered: true});
103
+ const entries = observer.takeRecords();
104
+
105
+ const MAX_INTERACTIONS_TO_CONSIDER = 10;
106
+ const longestInteractionList = [];
107
+ const longestInteractionMap = {};
108
+ for (let entry of entries) {
109
+ var minLongestInteraction =
110
+ longestInteractionList[longestInteractionList.length - 1];
111
+ var existingInteraction = longestInteractionMap[entry.interactionId];
112
+ if (
113
+ existingInteraction ||
114
+ longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||
115
+ entry.duration > minLongestInteraction.latency
116
+ ) {
117
+ if (existingInteraction) {
118
+ existingInteraction.entries.push(entry);
119
+ existingInteraction.latency = Math.max(
120
+ existingInteraction.latency,
121
+ entry.duration
122
+ );
123
+ } else {
124
+ var interaction = {
125
+ id: entry.interactionId,
126
+ latency: entry.duration,
127
+ entries: [entry]
128
+ };
129
+ longestInteractionMap[interaction.id] = interaction;
130
+ longestInteractionList.push(interaction);
131
+ }
132
+ longestInteractionList.sort(function (a, b) {
133
+ return b.latency - a.latency;
134
+ });
135
+ longestInteractionList
136
+ .splice(MAX_INTERACTIONS_TO_CONSIDER)
137
+ .forEach(function (i) {
138
+ delete longestInteractionMap[i.id];
139
+ });
140
+ }
141
+ }
142
+
143
+ const inp = longestInteractionList[longestInteractionList.length - 1];
144
+ if (inp) {
145
+ const cleanedEntries = [];
146
+
147
+ for (let entry of inp.entries) {
148
+ cleanedEntries.push({
149
+ id: entry.interactionId,
150
+ latency: entry.duration,
151
+ name: entry.name
152
+ });
150
153
  }
151
- })({});
152
-
154
+
155
+ const longestEntry = inp.entries.sort((a, b) => {
156
+ // Sort by: 1) duration (DESC), then 2) processing time (DESC)
157
+ return (
158
+ b.duration - a.duration ||
159
+ b.processingEnd -
160
+ b.processingStart -
161
+ (a.processingEnd - a.processingStart)
162
+ );
163
+ })[0];
164
+ let element = longestEntry.target;
165
+
166
+ return {
167
+ latency: inp.latency,
168
+ entries: cleanedEntries,
169
+ eventType: longestEntry.name,
170
+ eventTime: longestEntry.startTime,
171
+ eventTarget: getSelector(element),
172
+ loadState: getLoadState(longestEntry.startTime),
173
+ domPath: element ? getDomPath(element).join(' > ') : '',
174
+ tagName: element ? element.tagName : '',
175
+ className: element ? element.className : '',
176
+ tag: element ? element.cloneNode(false).outerHTML : ''
177
+ };
178
+ }
179
+ })({});
@@ -1,142 +1,54 @@
1
1
  (function () {
2
+ // https://github.com/GoogleChrome/web-vitals/blob/main/src/onINP.ts
3
+ const observer = new PerformanceObserver(list => {});
4
+ observer.observe({type: 'event', buffered: true});
5
+ observer.observe({type: 'first-input', buffered: true});
6
+ const entries = observer.takeRecords();
2
7
 
3
- // This is an updated version of
4
- // https://github.com/GoogleChrome/web-vitals/blob/64f133590fcac72c1bc042bf7b4ab729d7e03316/src/onINP.ts
5
- // It was reworked the 19/5-2023
6
-
7
- const supported = PerformanceObserver.supportedEntryTypes;
8
- if (!supported || supported.indexOf('event') === -1 ||  supported.indexOf('first-input') === -1) {
9
- return;
10
- }
11
- var observe = function observe(type, callback, opts) {
12
- try {
13
- if (PerformanceObserver.supportedEntryTypes.includes(type)) {
14
- var po = new PerformanceObserver(function (list) {
15
- Promise.resolve().then(function () {
16
- callback(list.getEntries());
17
- });
18
- });
19
- po.observe(Object.assign({type: type, buffered: true}, opts || {}));
20
- return po;
21
- }
22
- } catch (e) {}
23
- return;
24
- };
25
- var interactionCountEstimate = 0;
26
- var minKnownInteractionId = Infinity;
27
- var maxKnownInteractionId = 0;
28
- var updateEstimate = function updateEstimate(entries) {
29
- entries.forEach(function (e) {
30
- if (e.interactionId) {
31
- minKnownInteractionId = Math.min(
32
- minKnownInteractionId,
33
- e.interactionId
34
- );
35
- maxKnownInteractionId = Math.max(
36
- maxKnownInteractionId,
37
- e.interactionId
38
- );
39
- interactionCountEstimate = maxKnownInteractionId
40
- ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1
41
- : 0;
42
- }
43
- });
44
- };
45
- var po;
46
- var getInteractionCount = function getInteractionCount() {
47
- return po ? interactionCountEstimate : performance.interactionCount || 0;
48
- };
49
- var initInteractionCountPolyfill = function initInteractionCountPolyfill() {
50
- if ('interactionCount' in performance || po) return;
51
- po = observe('event', updateEstimate, {
52
- type: 'event',
53
- buffered: true,
54
- durationThreshold: 0,
55
- });
56
- };
57
- var prevInteractionCount = 0;
58
- var getInteractionCountForNavigation =
59
- function getInteractionCountForNavigation() {
60
- return getInteractionCount() - prevInteractionCount;
61
- };
62
- var MAX_INTERACTIONS_TO_CONSIDER = 10;
63
- var longestInteractionList = [];
64
- var longestInteractionMap = {};
65
- var processEntry = function processEntry(entry) {
66
- var minLongestInteraction =
67
- longestInteractionList[longestInteractionList.length - 1];
68
- var existingInteraction = longestInteractionMap[entry.interactionId];
69
- if (
70
- existingInteraction ||
71
- longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||
72
- entry.duration > minLongestInteraction.latency
73
- ) {
74
- if (existingInteraction) {
75
- existingInteraction.entries.push(entry);
76
- existingInteraction.latency = Math.max(
77
- existingInteraction.latency,
78
- entry.duration
79
- );
80
- } else {
81
- var interaction = {
82
- id: entry.interactionId,
83
- latency: entry.duration,
84
- entries: [entry],
85
- };
86
- longestInteractionMap[interaction.id] = interaction;
87
- longestInteractionList.push(interaction);
88
- }
89
- longestInteractionList.sort(function (a, b) {
90
- return b.latency - a.latency;
91
- });
92
- longestInteractionList
93
- .splice(MAX_INTERACTIONS_TO_CONSIDER)
94
- .forEach(function (i) {
95
- delete longestInteractionMap[i.id];
96
- });
8
+ const MAX_INTERACTIONS_TO_CONSIDER = 10;
9
+ const longestInteractionList = [];
10
+ const longestInteractionMap = {};
11
+ for (let entry of entries) {
12
+ var minLongestInteraction =
13
+ longestInteractionList[longestInteractionList.length - 1];
14
+ var existingInteraction = longestInteractionMap[entry.interactionId];
15
+ if (
16
+ existingInteraction ||
17
+ longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||
18
+ entry.duration > minLongestInteraction.latency
19
+ ) {
20
+ if (existingInteraction) {
21
+ existingInteraction.entries.push(entry);
22
+ existingInteraction.latency = Math.max(
23
+ existingInteraction.latency,
24
+ entry.duration
25
+ );
26
+ } else {
27
+ var interaction = {
28
+ id: entry.interactionId,
29
+ latency: entry.duration,
30
+ entries: [entry]
31
+ };
32
+ longestInteractionMap[interaction.id] = interaction;
33
+ longestInteractionList.push(interaction);
97
34
  }
98
- };
99
- var estimateP98LongestInteraction = function estimateP98LongestInteraction() {
100
- var candidateInteractionIndex = Math.min(
101
- longestInteractionList.length - 1,
102
- Math.floor(getInteractionCountForNavigation() / 50)
103
- );
104
- return longestInteractionList[candidateInteractionIndex];
105
- };
106
-
107
- var opts = {};
108
- initInteractionCountPolyfill();
109
- var handleEntries = function handleEntries(entries) {
110
- entries.forEach(function (entry) {
111
- if (entry.interactionId) {
112
- processEntry(entry);
113
- }
114
- if (entry.entryType === 'first-input') {
115
- var noMatchingEntry = !longestInteractionList.some(function (
116
- interaction
117
- ) {
118
- return interaction.entries.some(function (prevEntry) {
119
- return (
120
- entry.duration === prevEntry.duration &&
121
- entry.startTime === prevEntry.startTime
122
- );
123
- });
124
- });
125
- if (noMatchingEntry) {
126
- processEntry(entry);
127
- }
128
- }
35
+ longestInteractionList.sort(function (a, b) {
36
+ return b.latency - a.latency;
129
37
  });
130
- var inp = estimateP98LongestInteraction();
131
- if (inp && inp.latency !== metric.value) {
132
- return inp.latency;
133
- }
134
- };
135
- var po = observe('event', handleEntries, {
136
- durationThreshold: opts.durationThreshold || 40,
137
- });
138
- if (po) {
139
- po.observe({type: 'first-input', buffered: true});
38
+ longestInteractionList
39
+ .splice(MAX_INTERACTIONS_TO_CONSIDER)
40
+ .forEach(function (i) {
41
+ delete longestInteractionMap[i.id];
42
+ });
140
43
  }
141
- })({});
142
-
44
+ }
45
+
46
+ const inp = longestInteractionList[longestInteractionList.length - 1];
47
+ if (inp) {
48
+ return inp.latency;
49
+ } else {
50
+ if (performance.interactionCount > 0) {
51
+ return 0;
52
+ }
53
+ }
54
+ })({});
@@ -1,5 +1,4 @@
1
1
  import { readFileSync } from 'node:fs';
2
- import { platform } from 'node:os';
3
2
  import intel from 'intel';
4
3
  import { chromeDesktopOptions as defaultChromeOptions } from '../settings/chromeDesktopOptions.js';
5
4
  import { chromeAndroidOptions as defaultAndroidChromeOptions } from '../settings/chromeAndroidOptions.js';
@@ -189,14 +188,6 @@ export function setupChromiumOptions(
189
188
 
190
189
  if (browserOptions.binaryPath) {
191
190
  seleniumOptions.setChromeBinaryPath(browserOptions.binaryPath);
192
- } else {
193
- // Fix for https://github.com/sitespeedio/browsertime/issues/1968
194
- // Same settings for Chrome/Edge
195
- if (options.browser === 'chrome' && platform() === 'darwin') {
196
- seleniumOptions.setChromeBinaryPath(
197
- '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
198
- );
199
- }
200
191
  }
201
192
 
202
193
  if (browserOptions.mobileEmulation) {
@@ -426,6 +426,17 @@ export class Collector {
426
426
  results.geckoPerfStats.push(data.perfStats);
427
427
  }
428
428
 
429
+ // Add Firefox cpu power
430
+ if (data.powerConsumption) {
431
+ if (!results.powerConsumption) {
432
+ results.powerConsumption = [];
433
+ }
434
+ results.powerConsumption.push(data.powerConsumption);
435
+ statistics.addDeep({
436
+ powerConsumption: results.powerConsumption
437
+ });
438
+ }
439
+
429
440
  // Add total memory
430
441
  if (this.options.firefox && this.options.firefox.memoryReport) {
431
442
  statistics.addDeep({