browsertime 19.3.1 → 21.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 (225) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +9 -8
  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 +151 -19
  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/index.js +6 -2
  37. package/lib/core/engine/iteration.js +20 -102
  38. package/lib/firefox/geckoProfiler.js +49 -1
  39. package/lib/firefox/webdriver/builder.js +35 -12
  40. package/lib/firefox/webdriver/firefox.js +1 -1
  41. package/lib/support/cli.js +35 -15
  42. package/lib/support/engineUtils.js +13 -1
  43. package/lib/support/statistics.js +11 -1
  44. package/lib/support/userTiming.js +2 -2
  45. package/package.json +17 -8
  46. package/types/android/index.d.ts +70 -0
  47. package/types/android/index.d.ts.map +1 -0
  48. package/types/chrome/parseCpuTrace.d.ts +21 -0
  49. package/types/chrome/parseCpuTrace.d.ts.map +1 -0
  50. package/types/chrome/traceCategoriesParser.d.ts +2 -0
  51. package/types/chrome/traceCategoriesParser.d.ts.map +1 -0
  52. package/types/chrome/webdriver/traceUtilities.d.ts +8 -0
  53. package/types/chrome/webdriver/traceUtilities.d.ts.map +1 -0
  54. package/types/core/engine/command/action.d.ts +73 -0
  55. package/types/core/engine/command/action.d.ts.map +1 -0
  56. package/types/core/engine/command/actions.d.ts +38 -0
  57. package/types/core/engine/command/actions.d.ts.map +1 -0
  58. package/types/core/engine/command/addText.d.ts +68 -0
  59. package/types/core/engine/command/addText.d.ts.map +1 -0
  60. package/types/core/engine/command/android.d.ts +39 -0
  61. package/types/core/engine/command/android.d.ts.map +1 -0
  62. package/types/core/engine/command/cache.d.ts +53 -0
  63. package/types/core/engine/command/cache.d.ts.map +1 -0
  64. package/types/core/engine/command/chromeDevToolsProtocol.d.ts +61 -0
  65. package/types/core/engine/command/chromeDevToolsProtocol.d.ts.map +1 -0
  66. package/types/core/engine/command/chromeTrace.d.ts +45 -0
  67. package/types/core/engine/command/chromeTrace.d.ts.map +1 -0
  68. package/types/core/engine/command/click.d.ts +151 -0
  69. package/types/core/engine/command/click.d.ts.map +1 -0
  70. package/types/core/engine/command/debug.d.ts +28 -0
  71. package/types/core/engine/command/debug.d.ts.map +1 -0
  72. package/types/core/engine/command/element.d.ts +49 -0
  73. package/types/core/engine/command/element.d.ts.map +1 -0
  74. package/types/core/engine/command/geckoProfiler.d.ts +46 -0
  75. package/types/core/engine/command/geckoProfiler.d.ts.map +1 -0
  76. package/types/core/engine/command/javaScript.d.ts +63 -0
  77. package/types/core/engine/command/javaScript.d.ts.map +1 -0
  78. package/types/core/engine/command/measure.d.ts +194 -0
  79. package/types/core/engine/command/measure.d.ts.map +1 -0
  80. package/types/core/engine/command/meta.d.ts +23 -0
  81. package/types/core/engine/command/meta.d.ts.map +1 -0
  82. package/types/core/engine/command/mouse/clickAndHold.d.ts +82 -0
  83. package/types/core/engine/command/mouse/clickAndHold.d.ts.map +1 -0
  84. package/types/core/engine/command/mouse/contextClick.d.ts +44 -0
  85. package/types/core/engine/command/mouse/contextClick.d.ts.map +1 -0
  86. package/types/core/engine/command/mouse/doubleClick.d.ts +51 -0
  87. package/types/core/engine/command/mouse/doubleClick.d.ts.map +1 -0
  88. package/types/core/engine/command/mouse/index.d.ts +6 -0
  89. package/types/core/engine/command/mouse/index.d.ts.map +1 -0
  90. package/types/core/engine/command/mouse/mouseMove.d.ts +56 -0
  91. package/types/core/engine/command/mouse/mouseMove.d.ts.map +1 -0
  92. package/types/core/engine/command/mouse/singleClick.d.ts +115 -0
  93. package/types/core/engine/command/mouse/singleClick.d.ts.map +1 -0
  94. package/types/core/engine/command/navigation.d.ts +45 -0
  95. package/types/core/engine/command/navigation.d.ts.map +1 -0
  96. package/types/core/engine/command/screenshot.d.ts +33 -0
  97. package/types/core/engine/command/screenshot.d.ts.map +1 -0
  98. package/types/core/engine/command/scroll.d.ts +52 -0
  99. package/types/core/engine/command/scroll.d.ts.map +1 -0
  100. package/types/core/engine/command/select.d.ts +81 -0
  101. package/types/core/engine/command/select.d.ts.map +1 -0
  102. package/types/core/engine/command/set.d.ts +74 -0
  103. package/types/core/engine/command/set.d.ts.map +1 -0
  104. package/types/core/engine/command/stopWatch.d.ts +49 -0
  105. package/types/core/engine/command/stopWatch.d.ts.map +1 -0
  106. package/types/core/engine/command/switch.d.ts +77 -0
  107. package/types/core/engine/command/switch.d.ts.map +1 -0
  108. package/types/core/engine/command/util/lcpHighlightScript.d.ts +2 -0
  109. package/types/core/engine/command/util/lcpHighlightScript.d.ts.map +1 -0
  110. package/types/core/engine/command/util/lsHighlightScript.d.ts +2 -0
  111. package/types/core/engine/command/util/lsHighlightScript.d.ts.map +1 -0
  112. package/types/core/engine/command/wait.d.ts +74 -0
  113. package/types/core/engine/command/wait.d.ts.map +1 -0
  114. package/types/core/engine/commands.d.ts +161 -0
  115. package/types/core/engine/commands.d.ts.map +1 -0
  116. package/types/core/engine/context.d.ts +87 -0
  117. package/types/core/engine/context.d.ts.map +1 -0
  118. package/types/firefox/geckoProfiler.d.ts +11 -0
  119. package/types/firefox/geckoProfiler.d.ts.map +1 -0
  120. package/types/firefox/settings/geckoProfilerDefaults.d.ts +8 -0
  121. package/types/firefox/settings/geckoProfilerDefaults.d.ts.map +1 -0
  122. package/types/scripting.d.ts +2 -0
  123. package/types/support/engineUtils.d.ts +5 -0
  124. package/types/support/engineUtils.d.ts.map +1 -0
  125. package/types/support/errors.d.ts +15 -0
  126. package/types/support/errors.d.ts.map +1 -0
  127. package/types/support/fileUtil.d.ts +10 -0
  128. package/types/support/fileUtil.d.ts.map +1 -0
  129. package/types/support/filters.d.ts +7 -0
  130. package/types/support/filters.d.ts.map +1 -0
  131. package/types/support/getViewPort.d.ts +2 -0
  132. package/types/support/getViewPort.d.ts.map +1 -0
  133. package/types/support/pathToFolder.d.ts +2 -0
  134. package/types/support/pathToFolder.d.ts.map +1 -0
  135. package/types/support/storageManager.d.ts +17 -0
  136. package/types/support/storageManager.d.ts.map +1 -0
  137. package/types/support/tcpdump.d.ts +10 -0
  138. package/types/support/tcpdump.d.ts.map +1 -0
  139. package/types/support/userTiming.d.ts +2 -0
  140. package/types/support/userTiming.d.ts.map +1 -0
  141. package/types/support/util.d.ts +6 -0
  142. package/types/support/util.d.ts.map +1 -0
  143. package/types/video/defaults.d.ts +7 -0
  144. package/types/video/defaults.d.ts.map +1 -0
  145. package/types/video/postprocessing/finetune/addTextToVideo.d.ts +2 -0
  146. package/types/video/postprocessing/finetune/addTextToVideo.d.ts.map +1 -0
  147. package/types/video/postprocessing/finetune/convertFps.d.ts +2 -0
  148. package/types/video/postprocessing/finetune/convertFps.d.ts.map +1 -0
  149. package/types/video/postprocessing/finetune/getFont.d.ts +2 -0
  150. package/types/video/postprocessing/finetune/getFont.d.ts.map +1 -0
  151. package/types/video/postprocessing/finetune/getTimingMetrics.d.ts +2 -0
  152. package/types/video/postprocessing/finetune/getTimingMetrics.d.ts.map +1 -0
  153. package/types/video/postprocessing/finetune/index.d.ts +2 -0
  154. package/types/video/postprocessing/finetune/index.d.ts.map +1 -0
  155. package/types/video/postprocessing/finetune/removeOrange.d.ts +2 -0
  156. package/types/video/postprocessing/finetune/removeOrange.d.ts.map +1 -0
  157. package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts +5 -0
  158. package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts.map +1 -0
  159. package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts +5 -0
  160. package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts.map +1 -0
  161. package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts +3 -0
  162. package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts.map +1 -0
  163. package/types/video/screenRecording/android/recorder.d.ts +11 -0
  164. package/types/video/screenRecording/android/recorder.d.ts.map +1 -0
  165. package/types/video/screenRecording/desktop/convert.d.ts +2 -0
  166. package/types/video/screenRecording/desktop/convert.d.ts.map +1 -0
  167. package/types/video/screenRecording/desktop/desktopRecorder.d.ts +28 -0
  168. package/types/video/screenRecording/desktop/desktopRecorder.d.ts.map +1 -0
  169. package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts +17 -0
  170. package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts.map +1 -0
  171. package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts +2 -0
  172. package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts.map +1 -0
  173. package/types/video/screenRecording/desktop/osx/getScreen.d.ts +2 -0
  174. package/types/video/screenRecording/desktop/osx/getScreen.d.ts.map +1 -0
  175. package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts +13 -0
  176. package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts.map +1 -0
  177. package/types/video/screenRecording/ios/convertToMp4.d.ts +2 -0
  178. package/types/video/screenRecording/ios/convertToMp4.d.ts.map +1 -0
  179. package/types/video/screenRecording/ios/iosRecorder.d.ts +14 -0
  180. package/types/video/screenRecording/ios/iosRecorder.d.ts.map +1 -0
  181. package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts +2 -0
  182. package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts.map +1 -0
  183. package/types/video/screenRecording/iosSimulator/recorder.d.ts +9 -0
  184. package/types/video/screenRecording/iosSimulator/recorder.d.ts.map +1 -0
  185. package/types/video/screenRecording/recorder.d.ts +7 -0
  186. package/types/video/screenRecording/recorder.d.ts.map +1 -0
  187. package/types/video/screenRecording/setOrangeBackground.d.ts +2 -0
  188. package/types/video/screenRecording/setOrangeBackground.d.ts.map +1 -0
  189. package/types/video/video.d.ts +41 -0
  190. package/types/video/video.d.ts.map +1 -0
  191. package/CONTRIBUTING.md +0 -24
  192. package/browsersupport/firefox-profile/cert9.db +0 -0
  193. package/browsersupport/firefox-profile/chrome/userChrome.css +0 -4
  194. package/browsersupport/firefox-profile/key4.db +0 -0
  195. package/docs/examples/README.md +0 -9
  196. package/docs/examples/advance.md +0 -12
  197. package/docs/examples/android.md +0 -54
  198. package/docs/examples/basic.md +0 -36
  199. package/docs/examples/chrome.md +0 -28
  200. package/docs/examples/firefox.md +0 -10
  201. package/docs/issues.md +0 -18
  202. package/docs/new-style-script-objects.md +0 -38
  203. package/docs/sequence-diagrams/loadAndWait.wsd +0 -24
  204. package/docs/sequence-diagrams/run.wsd +0 -24
  205. package/vendor/mac/x86/qvh +0 -0
  206. package/visualmetrics/__init__.py +0 -1
  207. package/visualmetrics/test_data/ms_000000.png +0 -0
  208. package/visualmetrics/test_data/ms_000920.png +0 -0
  209. package/visualmetrics/test_data/ms_001000.png +0 -0
  210. package/visualmetrics/test_data/ms_001080.png +0 -0
  211. package/visualmetrics/test_data/ms_001200.png +0 -0
  212. package/visualmetrics/test_data/ms_001240.png +0 -0
  213. package/visualmetrics/test_data/ms_001280.png +0 -0
  214. package/visualmetrics/test_data/ms_001360.png +0 -0
  215. package/visualmetrics/test_data/ms_001400.png +0 -0
  216. package/visualmetrics/test_data/ms_001520.png +0 -0
  217. package/visualmetrics/test_data/ms_002040.png +0 -0
  218. package/visualmetrics/test_data/ms_002600.png +0 -0
  219. package/visualmetrics/test_data/ms_003160.png +0 -0
  220. package/visualmetrics/test_data/ms_003720.png +0 -0
  221. package/visualmetrics/test_data/ms_004280.png +0 -0
  222. package/visualmetrics/test_data/ms_004880.png +0 -0
  223. package/visualmetrics/test_data/ms_005440.png +0 -0
  224. package/visualmetrics/test_data/ms_006000.png +0 -0
  225. package/visualmetrics/test_visualmetrics.py +0 -34
package/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Browsertime changelog (we do [semantic versioning](https://semver.org))
2
2
 
3
+ ## 21.0.0 - 2024-01-07
4
+
5
+ The new version uses JSDoc to generate documentation for scripting and make it possible to use code completion/Intellisense! Documentation for that is coming soon.
6
+
7
+ ### Added
8
+ * Upgraded to [Geckodriver 0.34.0](https://github.com/mozilla/geckodriver/releases/tag/v0.34.0) [#2049](https://github.com/sitespeedio/browsertime/pull/2049).
9
+ * 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).
10
+ * Added more commands for mouse click on text [#2054](https://github.com/sitespeedio/browsertime/pull/2054).
11
+ * Updated AndroidCommand so you can run shell on your Android device as root [#2055](https://github.com/sitespeedio/browsertime/pull/2055).
12
+ * 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).
13
+ * Generate documentation for scripting using JSDoc [#2059](https://github.com/sitespeedio/browsertime/pull/2059).
14
+ * 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)
15
+
16
+
17
+ ### Fixed
18
+ * Make sure the visual metrics files are inlcuded in the Docker file [#2053](https://github.com/sitespeedio/browsertime/pull/2053).
19
+ * Removing QVH from the npm package (used for iPhone video recording but not working) [#2051](https://github.com/sitespeedio/browsertime/pull/2051)
20
+ * Removing visual metrics test images from the npm package [#2050](https://github.com/sitespeedio/browsertime/pull/2050).
21
+ * Removed the Chromedriver fix that was needed when Chrome for testing broke testing on Chrome :D [#2045](https://github.com/sitespeedio/browsertime/pull/2045).
22
+ * 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).
23
+ * Updated documentation for scripting with better JSDoc [#204](https://github.com/sitespeedio/browsertime/pull/2048).
24
+ * 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).
25
+
26
+ ## 20.0.0 - 2023-12-22
27
+
28
+ ### Breaking
29
+ * Changed `--userTimingWhitelist` to `--userTimingAllowList` in [#2023](https://github.com/sitespeedio/browsertime/pull/2023).
30
+ * 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)
31
+
32
+ ### Fixed
33
+ * Group page load parameters as PageLoad to make them easier to find using `--help` [#2035](https://github.com/sitespeedio/browsertime/pull/2035).
34
+ * Fix starting Firefox 121 on Mac [#2043](https://github.com/sitespeedio/browsertime/pull/2043).
35
+
36
+ ### Added
37
+ * Firefox 121 in the Docker container.g
38
+
3
39
  ## 19.3.1 - 2023-12-18
4
40
  ### Fixed
5
41
  * Ensure that visual metrics python script is included in the release.
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:
@@ -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.
@@ -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({