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.
- package/CHANGELOG.md +30 -0
- package/README.md +2 -2
- package/bin/browsertime.js +9 -3
- package/browserscripts/pageinfo/interactionToNextPaintInfo.js +170 -143
- package/browserscripts/timings/interactionToNextPaint.js +49 -137
- package/lib/chrome/webdriver/setupChromiumOptions.js +0 -9
- package/lib/core/engine/collector.js +11 -0
- package/lib/core/engine/command/actions.js +52 -0
- package/lib/core/engine/command/addText.js +48 -30
- package/lib/core/engine/command/android.js +43 -4
- package/lib/core/engine/command/cache.js +39 -2
- package/lib/core/engine/command/chromeDevToolsProtocol.js +51 -1
- package/lib/core/engine/command/chromeTrace.js +34 -0
- package/lib/core/engine/command/click.js +102 -52
- package/lib/core/engine/command/debug.js +19 -2
- package/lib/core/engine/command/element.js +66 -0
- package/lib/core/engine/command/geckoProfiler.js +41 -1
- package/lib/core/engine/command/javaScript.js +43 -20
- package/lib/core/engine/command/measure.js +147 -15
- package/lib/core/engine/command/meta.js +17 -0
- package/lib/core/engine/command/mouse/clickAndHold.js +56 -29
- package/lib/core/engine/command/mouse/contextClick.js +30 -11
- package/lib/core/engine/command/mouse/doubleClick.js +35 -11
- package/lib/core/engine/command/mouse/mouseMove.js +38 -16
- package/lib/core/engine/command/mouse/singleClick.js +187 -12
- package/lib/core/engine/command/navigation.js +31 -3
- package/lib/core/engine/command/screenshot.js +33 -0
- package/lib/core/engine/command/scroll.js +35 -13
- package/lib/core/engine/command/select.js +55 -36
- package/lib/core/engine/command/set.js +51 -36
- package/lib/core/engine/command/stopWatch.js +30 -9
- package/lib/core/engine/command/switch.js +49 -11
- package/lib/core/engine/command/wait.js +50 -25
- package/lib/core/engine/commands.js +267 -0
- package/lib/core/engine/context.js +81 -0
- package/lib/core/engine/iteration.js +20 -102
- package/lib/firefox/geckoProfiler.js +49 -1
- package/lib/firefox/webdriver/builder.js +4 -9
- package/lib/firefox/webdriver/firefox.js +1 -1
- package/lib/support/cli.js +7 -0
- package/lib/support/getViewPort.js +6 -1
- package/lib/support/statistics.js +11 -1
- package/package.json +22 -12
- package/types/android/index.d.ts +70 -0
- package/types/android/index.d.ts.map +1 -0
- package/types/chrome/parseCpuTrace.d.ts +21 -0
- package/types/chrome/parseCpuTrace.d.ts.map +1 -0
- package/types/chrome/traceCategoriesParser.d.ts +2 -0
- package/types/chrome/traceCategoriesParser.d.ts.map +1 -0
- package/types/chrome/webdriver/traceUtilities.d.ts +8 -0
- package/types/chrome/webdriver/traceUtilities.d.ts.map +1 -0
- package/types/core/engine/command/action.d.ts +73 -0
- package/types/core/engine/command/action.d.ts.map +1 -0
- package/types/core/engine/command/actions.d.ts +38 -0
- package/types/core/engine/command/actions.d.ts.map +1 -0
- package/types/core/engine/command/addText.d.ts +68 -0
- package/types/core/engine/command/addText.d.ts.map +1 -0
- package/types/core/engine/command/android.d.ts +39 -0
- package/types/core/engine/command/android.d.ts.map +1 -0
- package/types/core/engine/command/cache.d.ts +53 -0
- package/types/core/engine/command/cache.d.ts.map +1 -0
- package/types/core/engine/command/chromeDevToolsProtocol.d.ts +61 -0
- package/types/core/engine/command/chromeDevToolsProtocol.d.ts.map +1 -0
- package/types/core/engine/command/chromeTrace.d.ts +45 -0
- package/types/core/engine/command/chromeTrace.d.ts.map +1 -0
- package/types/core/engine/command/click.d.ts +151 -0
- package/types/core/engine/command/click.d.ts.map +1 -0
- package/types/core/engine/command/debug.d.ts +28 -0
- package/types/core/engine/command/debug.d.ts.map +1 -0
- package/types/core/engine/command/element.d.ts +49 -0
- package/types/core/engine/command/element.d.ts.map +1 -0
- package/types/core/engine/command/geckoProfiler.d.ts +46 -0
- package/types/core/engine/command/geckoProfiler.d.ts.map +1 -0
- package/types/core/engine/command/javaScript.d.ts +63 -0
- package/types/core/engine/command/javaScript.d.ts.map +1 -0
- package/types/core/engine/command/measure.d.ts +194 -0
- package/types/core/engine/command/measure.d.ts.map +1 -0
- package/types/core/engine/command/meta.d.ts +23 -0
- package/types/core/engine/command/meta.d.ts.map +1 -0
- package/types/core/engine/command/mouse/clickAndHold.d.ts +82 -0
- package/types/core/engine/command/mouse/clickAndHold.d.ts.map +1 -0
- package/types/core/engine/command/mouse/contextClick.d.ts +44 -0
- package/types/core/engine/command/mouse/contextClick.d.ts.map +1 -0
- package/types/core/engine/command/mouse/doubleClick.d.ts +51 -0
- package/types/core/engine/command/mouse/doubleClick.d.ts.map +1 -0
- package/types/core/engine/command/mouse/index.d.ts +6 -0
- package/types/core/engine/command/mouse/index.d.ts.map +1 -0
- package/types/core/engine/command/mouse/mouseMove.d.ts +56 -0
- package/types/core/engine/command/mouse/mouseMove.d.ts.map +1 -0
- package/types/core/engine/command/mouse/singleClick.d.ts +115 -0
- package/types/core/engine/command/mouse/singleClick.d.ts.map +1 -0
- package/types/core/engine/command/navigation.d.ts +45 -0
- package/types/core/engine/command/navigation.d.ts.map +1 -0
- package/types/core/engine/command/screenshot.d.ts +33 -0
- package/types/core/engine/command/screenshot.d.ts.map +1 -0
- package/types/core/engine/command/scroll.d.ts +52 -0
- package/types/core/engine/command/scroll.d.ts.map +1 -0
- package/types/core/engine/command/select.d.ts +81 -0
- package/types/core/engine/command/select.d.ts.map +1 -0
- package/types/core/engine/command/set.d.ts +74 -0
- package/types/core/engine/command/set.d.ts.map +1 -0
- package/types/core/engine/command/stopWatch.d.ts +49 -0
- package/types/core/engine/command/stopWatch.d.ts.map +1 -0
- package/types/core/engine/command/switch.d.ts +77 -0
- package/types/core/engine/command/switch.d.ts.map +1 -0
- package/types/core/engine/command/util/lcpHighlightScript.d.ts +2 -0
- package/types/core/engine/command/util/lcpHighlightScript.d.ts.map +1 -0
- package/types/core/engine/command/util/lsHighlightScript.d.ts +2 -0
- package/types/core/engine/command/util/lsHighlightScript.d.ts.map +1 -0
- package/types/core/engine/command/wait.d.ts +74 -0
- package/types/core/engine/command/wait.d.ts.map +1 -0
- package/types/core/engine/commands.d.ts +161 -0
- package/types/core/engine/commands.d.ts.map +1 -0
- package/types/core/engine/context.d.ts +87 -0
- package/types/core/engine/context.d.ts.map +1 -0
- package/types/firefox/geckoProfiler.d.ts +11 -0
- package/types/firefox/geckoProfiler.d.ts.map +1 -0
- package/types/firefox/settings/geckoProfilerDefaults.d.ts +8 -0
- package/types/firefox/settings/geckoProfilerDefaults.d.ts.map +1 -0
- package/types/scripting.d.ts +2 -0
- package/types/support/engineUtils.d.ts +5 -0
- package/types/support/engineUtils.d.ts.map +1 -0
- package/types/support/errors.d.ts +15 -0
- package/types/support/errors.d.ts.map +1 -0
- package/types/support/fileUtil.d.ts +10 -0
- package/types/support/fileUtil.d.ts.map +1 -0
- package/types/support/filters.d.ts +7 -0
- package/types/support/filters.d.ts.map +1 -0
- package/types/support/getViewPort.d.ts +2 -0
- package/types/support/getViewPort.d.ts.map +1 -0
- package/types/support/pathToFolder.d.ts +2 -0
- package/types/support/pathToFolder.d.ts.map +1 -0
- package/types/support/storageManager.d.ts +17 -0
- package/types/support/storageManager.d.ts.map +1 -0
- package/types/support/tcpdump.d.ts +10 -0
- package/types/support/tcpdump.d.ts.map +1 -0
- package/types/support/userTiming.d.ts +2 -0
- package/types/support/userTiming.d.ts.map +1 -0
- package/types/support/util.d.ts +6 -0
- package/types/support/util.d.ts.map +1 -0
- package/types/video/defaults.d.ts +7 -0
- package/types/video/defaults.d.ts.map +1 -0
- package/types/video/postprocessing/finetune/addTextToVideo.d.ts +2 -0
- package/types/video/postprocessing/finetune/addTextToVideo.d.ts.map +1 -0
- package/types/video/postprocessing/finetune/convertFps.d.ts +2 -0
- package/types/video/postprocessing/finetune/convertFps.d.ts.map +1 -0
- package/types/video/postprocessing/finetune/getFont.d.ts +2 -0
- package/types/video/postprocessing/finetune/getFont.d.ts.map +1 -0
- package/types/video/postprocessing/finetune/getTimingMetrics.d.ts +2 -0
- package/types/video/postprocessing/finetune/getTimingMetrics.d.ts.map +1 -0
- package/types/video/postprocessing/finetune/index.d.ts +2 -0
- package/types/video/postprocessing/finetune/index.d.ts.map +1 -0
- package/types/video/postprocessing/finetune/removeOrange.d.ts +2 -0
- package/types/video/postprocessing/finetune/removeOrange.d.ts.map +1 -0
- package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts +5 -0
- package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts.map +1 -0
- package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts +5 -0
- package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts.map +1 -0
- package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts +3 -0
- package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts.map +1 -0
- package/types/video/screenRecording/android/recorder.d.ts +11 -0
- package/types/video/screenRecording/android/recorder.d.ts.map +1 -0
- package/types/video/screenRecording/desktop/convert.d.ts +2 -0
- package/types/video/screenRecording/desktop/convert.d.ts.map +1 -0
- package/types/video/screenRecording/desktop/desktopRecorder.d.ts +28 -0
- package/types/video/screenRecording/desktop/desktopRecorder.d.ts.map +1 -0
- package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts +17 -0
- package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts.map +1 -0
- package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts +2 -0
- package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts.map +1 -0
- package/types/video/screenRecording/desktop/osx/getScreen.d.ts +2 -0
- package/types/video/screenRecording/desktop/osx/getScreen.d.ts.map +1 -0
- package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts +13 -0
- package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts.map +1 -0
- package/types/video/screenRecording/ios/convertToMp4.d.ts +2 -0
- package/types/video/screenRecording/ios/convertToMp4.d.ts.map +1 -0
- package/types/video/screenRecording/ios/iosRecorder.d.ts +14 -0
- package/types/video/screenRecording/ios/iosRecorder.d.ts.map +1 -0
- package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts +2 -0
- package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts.map +1 -0
- package/types/video/screenRecording/iosSimulator/recorder.d.ts +9 -0
- package/types/video/screenRecording/iosSimulator/recorder.d.ts.map +1 -0
- package/types/video/screenRecording/recorder.d.ts +7 -0
- package/types/video/screenRecording/recorder.d.ts.map +1 -0
- package/types/video/screenRecording/setOrangeBackground.d.ts +2 -0
- package/types/video/screenRecording/setOrangeBackground.d.ts.map +1 -0
- package/types/video/video.d.ts +41 -0
- package/types/video/video.d.ts.map +1 -0
- package/browsersupport/firefox-profile/cert9.db +0 -0
- package/browsersupport/firefox-profile/chrome/userChrome.css +0 -4
- package/browsersupport/firefox-profile/key4.db +0 -0
- package/vendor/mac/x86/qvh +0 -0
- package/visualmetrics/__init__.py +0 -1
- package/visualmetrics/test_data/ms_000000.png +0 -0
- package/visualmetrics/test_data/ms_000920.png +0 -0
- package/visualmetrics/test_data/ms_001000.png +0 -0
- package/visualmetrics/test_data/ms_001080.png +0 -0
- package/visualmetrics/test_data/ms_001200.png +0 -0
- package/visualmetrics/test_data/ms_001240.png +0 -0
- package/visualmetrics/test_data/ms_001280.png +0 -0
- package/visualmetrics/test_data/ms_001360.png +0 -0
- package/visualmetrics/test_data/ms_001400.png +0 -0
- package/visualmetrics/test_data/ms_001520.png +0 -0
- package/visualmetrics/test_data/ms_002040.png +0 -0
- package/visualmetrics/test_data/ms_002600.png +0 -0
- package/visualmetrics/test_data/ms_003160.png +0 -0
- package/visualmetrics/test_data/ms_003720.png +0 -0
- package/visualmetrics/test_data/ms_004280.png +0 -0
- package/visualmetrics/test_data/ms_004880.png +0 -0
- package/visualmetrics/test_data/ms_005440.png +0 -0
- package/visualmetrics/test_data/ms_006000.png +0 -0
- 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:
|
|
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:
|
|
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:
|
package/bin/browsertime.js
CHANGED
|
@@ -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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
if (
|
|
113
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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({
|