browsertime 16.16.0 → 17.0.0-beta.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 +52 -0
- package/bin/browsertime.js +43 -43
- package/bin/browsertimeWebPageReplay.js +10 -9
- package/browserscripts/pageinfo/generator.js +1 -1
- package/index.js +14 -13
- package/lib/android/gnirehtet.js +14 -15
- package/lib/android/index.js +92 -89
- package/lib/android/root.js +6 -9
- package/lib/chrome/chromeDevtoolsProtocol.js +46 -45
- package/lib/chrome/har.js +12 -13
- package/lib/chrome/longTaskMetrics.js +3 -5
- package/lib/chrome/parseCpuTrace.js +13 -10
- package/lib/chrome/settings/chromeAndroidOptions.js +1 -3
- package/lib/chrome/settings/chromeDesktopOptions.js +1 -3
- package/lib/chrome/settings/traceCategories.js +1 -3
- package/lib/chrome/traceCategoriesParser.js +35 -36
- package/lib/chrome/webdriver/builder.js +18 -26
- package/lib/chrome/webdriver/chromium.js +56 -46
- package/lib/chrome/webdriver/setupChromiumOptions.js +32 -27
- package/lib/connectivity/humble.js +13 -14
- package/lib/connectivity/index.js +74 -77
- package/lib/connectivity/trafficShapeParser.js +31 -35
- package/lib/core/engine/collector.js +25 -22
- package/lib/core/engine/command/addText.js +24 -27
- package/lib/core/engine/command/android.js +7 -11
- package/lib/core/engine/command/cache.js +3 -4
- package/lib/core/engine/command/chromeDevToolsProtocol.js +20 -20
- package/lib/core/engine/command/click.js +48 -49
- package/lib/core/engine/command/debug.js +3 -4
- package/lib/core/engine/command/javaScript.js +18 -19
- package/lib/core/engine/command/measure.js +31 -37
- package/lib/core/engine/command/meta.js +1 -4
- package/lib/core/engine/command/mouse/clickAndHold.js +36 -39
- package/lib/core/engine/command/mouse/contextClick.js +17 -18
- package/lib/core/engine/command/mouse/doubleClick.js +17 -19
- package/lib/core/engine/command/mouse/index.js +5 -9
- package/lib/core/engine/command/mouse/mouseMove.js +19 -23
- package/lib/core/engine/command/mouse/singleClick.js +15 -19
- package/lib/core/engine/command/navigation.js +12 -14
- package/lib/core/engine/command/screenshot.js +1 -4
- package/lib/core/engine/command/scroll.js +4 -7
- package/lib/core/engine/command/select.js +26 -26
- package/lib/core/engine/command/set.js +25 -23
- package/lib/core/engine/command/stopWatch.js +5 -8
- package/lib/core/engine/command/switch.js +18 -20
- package/lib/core/engine/command/util/lcpHighlightScript.js +1 -2
- package/lib/core/engine/command/util/lsHighlightScript.js +1 -2
- package/lib/core/engine/command/wait.js +18 -18
- package/lib/core/engine/index.js +81 -71
- package/lib/core/engine/iteration.js +93 -79
- package/lib/core/engine/run.js +5 -9
- package/lib/core/pageCompleteChecks/defaultPageCompleteCheck.js +1 -2
- package/lib/core/pageCompleteChecks/pageCompleteCheckByInactivity.js +1 -3
- package/lib/core/pageCompleteChecks/spaInactivity.js +1 -3
- package/lib/core/seleniumRunner.js +92 -100
- package/lib/core/webdriver/index.js +24 -21
- package/lib/edge/webdriver/builder.js +21 -26
- package/lib/extensionserver/httpServer.js +17 -21
- package/lib/extensionserver/index.js +8 -12
- package/lib/extensionserver/setup.js +12 -12
- package/lib/firefox/geckoProfiler.js +27 -21
- package/lib/firefox/getHAR.js +7 -8
- package/lib/firefox/memoryReport.js +9 -11
- package/lib/firefox/perfStats.js +5 -7
- package/lib/firefox/settings/disableSafeBrowsingPreferences.js +1 -3
- package/lib/firefox/settings/disableTrackingProtectionPreferences.js +1 -3
- package/lib/firefox/settings/firefoxPreferences.js +2 -4
- package/lib/firefox/settings/geckoProfilerDefaults.js +5 -9
- package/lib/firefox/webdriver/builder.js +66 -63
- package/lib/firefox/webdriver/firefox.js +43 -48
- package/lib/safari/webdriver/builder.js +4 -5
- package/lib/safari/webdriver/safari.js +4 -8
- package/lib/screenshot/defaults.js +1 -3
- package/lib/screenshot/index.js +24 -21
- package/lib/support/browserScript.js +65 -56
- package/lib/support/cli.js +123 -85
- package/lib/support/dns.js +6 -7
- package/lib/support/engineUtils.js +85 -38
- package/lib/support/errors.js +4 -13
- package/lib/support/fileUtil.js +81 -68
- package/lib/support/filters.js +15 -20
- package/lib/support/getViewPort.js +6 -7
- package/lib/support/har/index.js +208 -216
- package/lib/support/images/index.js +54 -26
- package/lib/support/logging.js +20 -17
- package/lib/support/pathToFolder.js +18 -23
- package/lib/support/preURL.js +5 -6
- package/lib/support/processes.js +4 -6
- package/lib/support/setResourceTimingBufferSize.js +2 -4
- package/lib/support/statistics.js +58 -56
- package/lib/support/stop.js +7 -8
- package/lib/support/storageManager.js +44 -44
- package/lib/support/tcpdump.js +22 -16
- package/lib/support/userTiming.js +7 -13
- package/lib/support/util.js +204 -224
- package/lib/support/xvfb.js +11 -13
- package/lib/video/defaults.js +6 -10
- package/lib/video/postprocessing/finetune/addTextToVideo.js +15 -15
- package/lib/video/postprocessing/finetune/convertFps.js +14 -8
- package/lib/video/postprocessing/finetune/getFont.js +7 -9
- package/lib/video/postprocessing/finetune/getTimingMetrics.js +19 -18
- package/lib/video/postprocessing/finetune/index.js +40 -36
- package/lib/video/postprocessing/finetune/removeOrange.js +10 -11
- package/lib/video/postprocessing/visualmetrics/extraMetrics.js +17 -13
- package/lib/video/postprocessing/visualmetrics/getVideoMetrics.js +12 -13
- package/lib/video/postprocessing/visualmetrics/visualMetrics.js +117 -128
- package/lib/video/screenRecording/android/recorder.js +12 -17
- package/lib/video/screenRecording/desktop/convert.js +13 -11
- package/lib/video/screenRecording/desktop/desktopRecorder.js +29 -24
- package/lib/video/screenRecording/desktop/ffmpegRecorder.js +60 -63
- package/lib/video/screenRecording/desktop/osx/getSPDisplaysDataType.js +4 -6
- package/lib/video/screenRecording/desktop/osx/getScreen.js +9 -10
- package/lib/video/screenRecording/firefox/firefoxWindowRecorder.js +54 -54
- package/lib/video/screenRecording/ios/convertToMp4.js +10 -11
- package/lib/video/screenRecording/ios/iosRecorder.js +23 -21
- package/lib/video/screenRecording/iosSimulator/convertToMp4.js +10 -11
- package/lib/video/screenRecording/iosSimulator/recorder.js +10 -9
- package/lib/video/screenRecording/recorder.js +8 -9
- package/lib/video/screenRecording/setOrangeBackground.js +5 -6
- package/lib/video/video.js +28 -34
- package/package.json +19 -17
package/lib/support/util.js
CHANGED
|
@@ -1,252 +1,232 @@
|
|
|
1
|
-
|
|
1
|
+
import groupBy from 'lodash.groupby';
|
|
2
|
+
import intel from 'intel';
|
|
3
|
+
const log = intel.getLogger('browsertime');
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (inMs) {
|
|
11
|
-
if (value < 1000) {
|
|
12
|
-
return value + 'ms';
|
|
13
|
-
} else {
|
|
14
|
-
return (value / 1000).toFixed(2) + 's';
|
|
15
|
-
}
|
|
16
|
-
} else return value;
|
|
17
|
-
}
|
|
5
|
+
export function formatMetric(name, metric, multiple, inMs, extras) {
|
|
6
|
+
if (metric === undefined) return;
|
|
7
|
+
function fmt(value) {
|
|
8
|
+
if (inMs) {
|
|
9
|
+
return value < 1000 ? value + 'ms' : (value / 1000).toFixed(2) + 's';
|
|
10
|
+
} else return value;
|
|
11
|
+
}
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (totalSize > 1024) {
|
|
63
|
-
totalSize = (totalSize / 1024).toFixed(2) + ' kb';
|
|
64
|
-
} else {
|
|
65
|
-
totalSize = totalSize + ' bytes';
|
|
13
|
+
let formatted = `${name}: ${fmt(multiple ? metric.median : metric)}`;
|
|
14
|
+
if (extras) {
|
|
15
|
+
formatted += ` (σ${fmt(metric.stddev.toFixed(2))} ${
|
|
16
|
+
metric.stddev > 0 ? metric.rsd.toFixed(1) : '0'
|
|
17
|
+
}%)`;
|
|
18
|
+
}
|
|
19
|
+
return formatted;
|
|
20
|
+
}
|
|
21
|
+
export function logResultLogLine(results) {
|
|
22
|
+
let index = 0;
|
|
23
|
+
for (let result of results) {
|
|
24
|
+
let totalSize = 0;
|
|
25
|
+
let requests = '';
|
|
26
|
+
let firstPaint = '',
|
|
27
|
+
domContent = '',
|
|
28
|
+
pageLoad = '',
|
|
29
|
+
speedIndex = '',
|
|
30
|
+
perceptualSpeedIndex = '',
|
|
31
|
+
contentfulSpeedIndex = '',
|
|
32
|
+
startRender = '',
|
|
33
|
+
visualComplete85 = '',
|
|
34
|
+
backEndTime = '',
|
|
35
|
+
lastVisualChange = '',
|
|
36
|
+
memory = '',
|
|
37
|
+
lcp = '',
|
|
38
|
+
fcp = '',
|
|
39
|
+
cls = '',
|
|
40
|
+
tbt = '',
|
|
41
|
+
nRuns = result.browserScripts.length,
|
|
42
|
+
m = nRuns > 1;
|
|
43
|
+
if (results.har && results.har.log.pages[index]) {
|
|
44
|
+
// get the id
|
|
45
|
+
let pageId = results.har.log.pages[index].id;
|
|
46
|
+
let entriesByPage = groupBy(results.har.log.entries, 'pageref');
|
|
47
|
+
requests = entriesByPage[pageId]
|
|
48
|
+
? entriesByPage[pageId].length + ' requests'
|
|
49
|
+
: '';
|
|
50
|
+
if (entriesByPage[pageId]) {
|
|
51
|
+
for (const request of entriesByPage[pageId]) {
|
|
52
|
+
// transfer size
|
|
53
|
+
totalSize += request.response.bodySize;
|
|
66
54
|
}
|
|
67
55
|
}
|
|
56
|
+
totalSize =
|
|
57
|
+
totalSize > 1024
|
|
58
|
+
? (totalSize / 1024).toFixed(2) + ' kb'
|
|
59
|
+
: totalSize + ' bytes';
|
|
60
|
+
}
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
62
|
+
if (result.statistics.timings && result.statistics.timings.pageTimings) {
|
|
63
|
+
let pt = result.statistics.timings.pageTimings,
|
|
64
|
+
t = result.statistics.timings,
|
|
65
|
+
vm = result.statistics.visualMetrics,
|
|
66
|
+
pi = result.statistics.pageinfo,
|
|
67
|
+
cpu = result.statistics.cpu;
|
|
75
68
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
firstPaint = formatMetric('firstPaint', t.firstPaint, true, true, m);
|
|
70
|
+
if (t.largestContentfulPaint) {
|
|
71
|
+
lcp = formatMetric(
|
|
72
|
+
'LCP',
|
|
73
|
+
t.largestContentfulPaint.renderTime,
|
|
79
74
|
true,
|
|
80
75
|
true,
|
|
81
76
|
m
|
|
82
77
|
);
|
|
83
|
-
|
|
84
|
-
lcp = this.formatMetric(
|
|
85
|
-
'LCP',
|
|
86
|
-
t.largestContentfulPaint.renderTime,
|
|
87
|
-
true,
|
|
88
|
-
true,
|
|
89
|
-
m
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (pi && pi.cumulativeLayoutShift) {
|
|
94
|
-
cls = this.formatMetric(
|
|
95
|
-
'CLS',
|
|
96
|
-
pi.cumulativeLayoutShift,
|
|
97
|
-
true,
|
|
98
|
-
false,
|
|
99
|
-
m
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (cpu && cpu.longTasks && cpu.longTasks.totalBlockingTime) {
|
|
104
|
-
tbt = this.formatMetric(
|
|
105
|
-
'TBT',
|
|
106
|
-
cpu.longTasks.totalBlockingTime,
|
|
107
|
-
true,
|
|
108
|
-
true,
|
|
109
|
-
m
|
|
110
|
-
);
|
|
111
|
-
}
|
|
78
|
+
}
|
|
112
79
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
) {
|
|
117
|
-
fcp = this.formatMetric(
|
|
118
|
-
'FCP',
|
|
119
|
-
result.statistics.timings.paintTiming['first-contentful-paint'],
|
|
120
|
-
true,
|
|
121
|
-
true,
|
|
122
|
-
m
|
|
123
|
-
);
|
|
124
|
-
}
|
|
80
|
+
if (pi && pi.cumulativeLayoutShift) {
|
|
81
|
+
cls = formatMetric('CLS', pi.cumulativeLayoutShift, true, false, m);
|
|
82
|
+
}
|
|
125
83
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
true,
|
|
131
|
-
m
|
|
132
|
-
);
|
|
133
|
-
speedIndex = this.formatMetric(
|
|
134
|
-
'speedIndex',
|
|
135
|
-
vm ? vm.SpeedIndex : vm,
|
|
136
|
-
true,
|
|
137
|
-
true,
|
|
138
|
-
m
|
|
139
|
-
);
|
|
140
|
-
perceptualSpeedIndex = this.formatMetric(
|
|
141
|
-
'perceptualSpeedIndex',
|
|
142
|
-
vm ? vm.PerceptualSpeedIndex : vm,
|
|
143
|
-
true,
|
|
144
|
-
true,
|
|
145
|
-
m
|
|
146
|
-
);
|
|
147
|
-
contentfulSpeedIndex = this.formatMetric(
|
|
148
|
-
'contentfulSpeedIndex',
|
|
149
|
-
vm ? vm.ContentfulSpeedIndex : vm,
|
|
150
|
-
true,
|
|
151
|
-
true,
|
|
152
|
-
m
|
|
153
|
-
);
|
|
154
|
-
startRender = this.formatMetric(
|
|
155
|
-
'firstVisualChange',
|
|
156
|
-
vm ? vm.FirstVisualChange : vm,
|
|
84
|
+
if (cpu && cpu.longTasks && cpu.longTasks.totalBlockingTime) {
|
|
85
|
+
tbt = formatMetric(
|
|
86
|
+
'TBT',
|
|
87
|
+
cpu.longTasks.totalBlockingTime,
|
|
157
88
|
true,
|
|
158
89
|
true,
|
|
159
90
|
m
|
|
160
91
|
);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
'
|
|
170
|
-
vm ? vm.VisualComplete85 : vm,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (
|
|
95
|
+
result.statistics.timings.paintTiming &&
|
|
96
|
+
result.statistics.timings.paintTiming['first-contentful-paint']
|
|
97
|
+
) {
|
|
98
|
+
fcp = formatMetric(
|
|
99
|
+
'FCP',
|
|
100
|
+
result.statistics.timings.paintTiming['first-contentful-paint'],
|
|
171
101
|
true,
|
|
172
102
|
true,
|
|
173
103
|
m
|
|
174
104
|
);
|
|
175
|
-
pageLoad = this.formatMetric('Load', pt.pageLoadTime, true, true, m);
|
|
176
|
-
backEndTime = this.formatMetric('TTFB', pt.backEndTime, true, true, m);
|
|
177
105
|
}
|
|
178
106
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
107
|
+
domContent = formatMetric(
|
|
108
|
+
'DOMContentLoaded',
|
|
109
|
+
pt.domContentLoadedTime,
|
|
110
|
+
true,
|
|
111
|
+
true,
|
|
112
|
+
m
|
|
113
|
+
);
|
|
114
|
+
speedIndex = formatMetric(
|
|
115
|
+
'speedIndex',
|
|
116
|
+
vm ? vm.SpeedIndex : vm,
|
|
117
|
+
true,
|
|
118
|
+
true,
|
|
119
|
+
m
|
|
120
|
+
);
|
|
121
|
+
perceptualSpeedIndex = formatMetric(
|
|
122
|
+
'perceptualSpeedIndex',
|
|
123
|
+
vm ? vm.PerceptualSpeedIndex : vm,
|
|
124
|
+
true,
|
|
125
|
+
true,
|
|
126
|
+
m
|
|
127
|
+
);
|
|
128
|
+
contentfulSpeedIndex = formatMetric(
|
|
129
|
+
'contentfulSpeedIndex',
|
|
130
|
+
vm ? vm.ContentfulSpeedIndex : vm,
|
|
131
|
+
true,
|
|
132
|
+
true,
|
|
133
|
+
m
|
|
134
|
+
);
|
|
135
|
+
startRender = formatMetric(
|
|
136
|
+
'firstVisualChange',
|
|
137
|
+
vm ? vm.FirstVisualChange : vm,
|
|
138
|
+
true,
|
|
139
|
+
true,
|
|
140
|
+
m
|
|
141
|
+
);
|
|
142
|
+
lastVisualChange = formatMetric(
|
|
143
|
+
'lastVisualChange',
|
|
144
|
+
vm ? vm.LastVisualChange : vm,
|
|
145
|
+
true,
|
|
146
|
+
true,
|
|
147
|
+
m
|
|
148
|
+
);
|
|
149
|
+
visualComplete85 = formatMetric(
|
|
150
|
+
'visualComplete85',
|
|
151
|
+
vm ? vm.VisualComplete85 : vm,
|
|
152
|
+
true,
|
|
153
|
+
true,
|
|
154
|
+
m
|
|
155
|
+
);
|
|
156
|
+
pageLoad = formatMetric('Load', pt.pageLoadTime, true, true, m);
|
|
157
|
+
backEndTime = formatMetric('TTFB', pt.backEndTime, true, true, m);
|
|
158
|
+
}
|
|
184
159
|
|
|
185
|
-
|
|
186
|
-
|
|
160
|
+
if (result.statistics.memory) {
|
|
161
|
+
let mem = result.statistics.memory;
|
|
162
|
+
for (let value in mem) {
|
|
163
|
+
mem[value] = Math.round(mem[value] / 1024 / 1024);
|
|
187
164
|
}
|
|
188
165
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
`${totalSize > 0 ? totalSize : ''}`,
|
|
192
|
-
backEndTime,
|
|
193
|
-
firstPaint,
|
|
194
|
-
startRender,
|
|
195
|
-
fcp,
|
|
196
|
-
domContent,
|
|
197
|
-
lcp,
|
|
198
|
-
cls,
|
|
199
|
-
tbt,
|
|
200
|
-
pageLoad,
|
|
201
|
-
memory,
|
|
202
|
-
speedIndex,
|
|
203
|
-
perceptualSpeedIndex,
|
|
204
|
-
contentfulSpeedIndex,
|
|
205
|
-
visualComplete85,
|
|
206
|
-
lastVisualChange
|
|
207
|
-
],
|
|
208
|
-
note = m ? ` (${nRuns} runs)` : '';
|
|
209
|
-
|
|
210
|
-
lines = lines.filter(Boolean).join(', ');
|
|
211
|
-
log.info(`${result.info.url} ${lines}${note}`);
|
|
212
|
-
index++;
|
|
166
|
+
memory = formatMetric('Memory', mem, true, false, m);
|
|
167
|
+
memory = memory + 'mb';
|
|
213
168
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
169
|
+
|
|
170
|
+
let lines = [
|
|
171
|
+
`${requests}`,
|
|
172
|
+
`${totalSize > 0 ? totalSize : ''}`,
|
|
173
|
+
backEndTime,
|
|
174
|
+
firstPaint,
|
|
175
|
+
startRender,
|
|
176
|
+
fcp,
|
|
177
|
+
domContent,
|
|
178
|
+
lcp,
|
|
179
|
+
cls,
|
|
180
|
+
tbt,
|
|
181
|
+
pageLoad,
|
|
182
|
+
memory,
|
|
183
|
+
speedIndex,
|
|
184
|
+
perceptualSpeedIndex,
|
|
185
|
+
contentfulSpeedIndex,
|
|
186
|
+
visualComplete85,
|
|
187
|
+
lastVisualChange
|
|
188
|
+
],
|
|
189
|
+
note = m ? ` (${nRuns} runs)` : '';
|
|
190
|
+
|
|
191
|
+
lines = lines.filter(Boolean).join(', ');
|
|
192
|
+
log.info(`${result.info.url} ${lines}${note}`);
|
|
193
|
+
index++;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
export function toArray(arrayLike) {
|
|
197
|
+
if (arrayLike === undefined || arrayLike === null) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
if (Array.isArray(arrayLike)) {
|
|
201
|
+
return arrayLike;
|
|
202
|
+
}
|
|
203
|
+
return [arrayLike];
|
|
204
|
+
}
|
|
205
|
+
export function jsonifyVisualProgress(visualProgress) {
|
|
206
|
+
// Original data looks like
|
|
207
|
+
// "0=0, 1500=81, 1516=81, 1533=84, 1550=84, 1566=84, 1600=95, 1683=95, 1833=100"
|
|
208
|
+
if (typeof visualProgress === 'string') {
|
|
209
|
+
const visualProgressArray = [];
|
|
210
|
+
for (const value of visualProgress.split(', ')) {
|
|
211
|
+
const [timestamp, percent] = value.split('=');
|
|
212
|
+
visualProgressArray.push({
|
|
213
|
+
timestamp: Number.parseInt(timestamp, 10),
|
|
214
|
+
percent: Number.parseInt(percent, 10)
|
|
215
|
+
});
|
|
237
216
|
}
|
|
238
|
-
return
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
217
|
+
return visualProgressArray;
|
|
218
|
+
}
|
|
219
|
+
return visualProgress;
|
|
220
|
+
}
|
|
221
|
+
export function adjustVisualProgressTimestamps(
|
|
222
|
+
visualProgress,
|
|
223
|
+
profilerStartTime,
|
|
224
|
+
recordingStartTime
|
|
225
|
+
) {
|
|
226
|
+
// calculate offset between unix timestamps which represents the profiler start
|
|
227
|
+
// time and the time of the first frame after the orange frame after recording start
|
|
228
|
+
for (const value of visualProgress) {
|
|
229
|
+
value.timestamp += recordingStartTime - profilerStartTime;
|
|
251
230
|
}
|
|
252
|
-
|
|
231
|
+
return visualProgress;
|
|
232
|
+
}
|
package/lib/support/xvfb.js
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import { promisify } from 'node:util';
|
|
2
|
+
import get from 'lodash.get';
|
|
3
|
+
import Xvfb from '@cypress/xvfb';
|
|
4
|
+
import { xvfbDisplay } from '../video/defaults.js';
|
|
5
|
+
import getViewPort from '../support/getViewPort.js';
|
|
6
|
+
import { isAndroidConfigured } from '../android/index.js';
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
const get = require('lodash.get');
|
|
5
|
-
const videoDefaults = require('../video/defaults');
|
|
6
|
-
const getViewPort = require('../support/getViewPort');
|
|
7
|
-
const { promisify } = require('util');
|
|
8
|
-
const { isAndroidConfigured } = require('../android');
|
|
9
|
-
|
|
10
|
-
function buildXvfbArgs({ display, screen = 0, size, silent }) {
|
|
8
|
+
function buildXvfbArguments({ display, screen = 0, size, silent }) {
|
|
11
9
|
return {
|
|
12
10
|
displayNum: display,
|
|
13
11
|
silent,
|
|
@@ -23,12 +21,12 @@ async function startXvfb({ size, options }) {
|
|
|
23
21
|
const viewPort = size.split('x');
|
|
24
22
|
xvfbSize = Number(viewPort[0]) + extraSizeInFirefox + 'x' + viewPort[1];
|
|
25
23
|
}
|
|
26
|
-
const
|
|
27
|
-
display: get(options, 'xvfbParams.display',
|
|
24
|
+
const xvfbArguments = buildXvfbArguments({
|
|
25
|
+
display: get(options, 'xvfbParams.display', xvfbDisplay),
|
|
28
26
|
size: xvfbSize,
|
|
29
27
|
silent: options.verbose >= 2 ? false : true
|
|
30
28
|
});
|
|
31
|
-
const xvfb = new Xvfb(
|
|
29
|
+
const xvfb = new Xvfb(xvfbArguments);
|
|
32
30
|
const start = promisify(xvfb.start.bind(xvfb));
|
|
33
31
|
await start();
|
|
34
32
|
return xvfb;
|
|
@@ -70,4 +68,4 @@ class XVFB {
|
|
|
70
68
|
}
|
|
71
69
|
}
|
|
72
70
|
|
|
73
|
-
|
|
71
|
+
export default XVFB;
|
package/lib/video/defaults.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
addTimer: true,
|
|
8
|
-
convert: true,
|
|
9
|
-
threads: 0
|
|
10
|
-
};
|
|
1
|
+
export const framerate = 30;
|
|
2
|
+
export const crf = 23;
|
|
3
|
+
export const xvfbDisplay = 99;
|
|
4
|
+
export const addTimer = true;
|
|
5
|
+
export const convert = true;
|
|
6
|
+
export const threads = 0;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const { isAndroidConfigured } = require('../../../android');
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import intel from 'intel';
|
|
3
|
+
import getTimingMetrics from './getTimingMetrics.js';
|
|
4
|
+
import getFont from './getFont.js';
|
|
5
|
+
import { isAndroidConfigured } from '../../../android/index.js';
|
|
6
|
+
const log = intel.getLogger('browsertime.video');
|
|
8
7
|
|
|
9
8
|
function isSmallish(options) {
|
|
10
9
|
return (
|
|
@@ -15,7 +14,7 @@ function isSmallish(options) {
|
|
|
15
14
|
);
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
export default async function (
|
|
19
18
|
inputFile,
|
|
20
19
|
outputFile,
|
|
21
20
|
videoMetrics,
|
|
@@ -23,7 +22,7 @@ module.exports = async function (
|
|
|
23
22
|
options
|
|
24
23
|
) {
|
|
25
24
|
/** Add timer and metrics to the video */
|
|
26
|
-
const
|
|
25
|
+
const arguments_ = ['-nostdin', '-i', inputFile, '-c:v', 'libx264'];
|
|
27
26
|
const allTimingMetrics = getTimingMetrics(
|
|
28
27
|
videoMetrics,
|
|
29
28
|
timingMetrics,
|
|
@@ -40,11 +39,12 @@ module.exports = async function (
|
|
|
40
39
|
fontSize = 32;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
arguments_.push(
|
|
44
43
|
'-vf',
|
|
45
|
-
`drawtext=${fontFile}x=w/2-(tw/2): y=H-h/10:fontcolor=white:fontsize=h/${fontSize}:box=1:boxcolor=0x000000AA:text='%{pts\\:hms}'${allTimingMetrics}
|
|
44
|
+
`drawtext=${fontFile}x=w/2-(tw/2): y=H-h/10:fontcolor=white:fontsize=h/${fontSize}:box=1:boxcolor=0x000000AA:text='%{pts\\:hms}'${allTimingMetrics}`,
|
|
45
|
+
'-y',
|
|
46
|
+
outputFile
|
|
46
47
|
);
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
48
|
+
log.verbose('Adding text with FFMPEG ' + arguments_.join(' '));
|
|
49
|
+
return execa('ffmpeg', arguments_);
|
|
50
|
+
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import intel from 'intel';
|
|
3
|
+
const log = intel.getLogger('browsertime.video');
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export default async function (source, destination, framerate) {
|
|
6
|
+
const scriptArguments = [
|
|
7
|
+
'-nostdin',
|
|
8
|
+
'-i',
|
|
9
|
+
source,
|
|
10
|
+
'-r',
|
|
11
|
+
framerate,
|
|
12
|
+
destination
|
|
13
|
+
];
|
|
8
14
|
log.info('Converting video to %s fps', framerate);
|
|
9
|
-
return execa('ffmpeg',
|
|
10
|
-
}
|
|
15
|
+
return execa('ffmpeg', scriptArguments);
|
|
16
|
+
}
|
|
@@ -1,17 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
module.exports = function (options) {
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
export default function (options) {
|
|
5
3
|
// If the font is not part of the params and we're on macOS
|
|
6
4
|
// we check that SFNSMono.ttf is available
|
|
7
5
|
if (!options.videoParams.fontPath && process.platform === 'darwin') {
|
|
8
6
|
const systemFontFile = '/System/Library/Fonts/SFNSMono.ttf';
|
|
9
7
|
try {
|
|
10
|
-
if (
|
|
8
|
+
if (existsSync(systemFontFile)) {
|
|
11
9
|
return systemFontFile + ':';
|
|
12
10
|
}
|
|
13
11
|
return '';
|
|
14
|
-
} catch
|
|
12
|
+
} catch {
|
|
15
13
|
return '';
|
|
16
14
|
}
|
|
17
15
|
} else if (!options.videoParams.fontPath && options.docker) {
|
|
@@ -19,15 +17,15 @@ module.exports = function (options) {
|
|
|
19
17
|
const systemFontFile =
|
|
20
18
|
'/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf';
|
|
21
19
|
try {
|
|
22
|
-
if (
|
|
20
|
+
if (existsSync(systemFontFile)) {
|
|
23
21
|
return systemFontFile + ':';
|
|
24
22
|
}
|
|
25
23
|
return '';
|
|
26
|
-
} catch
|
|
24
|
+
} catch {
|
|
27
25
|
return '';
|
|
28
26
|
}
|
|
29
27
|
} else
|
|
30
28
|
return options.videoParams.fontPath
|
|
31
29
|
? options.videoParams.fontPath + ':'
|
|
32
30
|
: '';
|
|
33
|
-
}
|
|
31
|
+
}
|