browsertime 16.17.0 → 17.0.0-beta.1
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 +44 -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 +22 -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 +82 -72
- package/lib/core/engine/iteration.js +83 -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 +44 -49
- 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 +120 -87
- 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/android/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
1
|
+
import { promisify } from 'node:util';
|
|
2
|
+
import { mkdir as _mkdir, createWriteStream } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { EOL as endOfLine } from 'node:os';
|
|
5
|
+
import { execa } from 'execa';
|
|
6
|
+
import intel from 'intel';
|
|
7
|
+
import adbKit from '@devicefarmer/adbkit';
|
|
8
|
+
const { createClient, util } = adbKit;
|
|
9
|
+
import get from 'lodash.get';
|
|
10
|
+
const log = intel.getLogger('browsertime.android');
|
|
11
|
+
const mkdir = promisify(_mkdir);
|
|
12
12
|
const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
13
13
|
|
|
14
|
-
class Android {
|
|
14
|
+
export class Android {
|
|
15
15
|
constructor(options) {
|
|
16
16
|
if (Android.instance) {
|
|
17
17
|
// This is hack for https://github.com/sitespeedio/browsertime/issues/1239
|
|
@@ -21,7 +21,7 @@ class Android {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
Android.instance = this;
|
|
24
|
-
this.client =
|
|
24
|
+
this.client = createClient();
|
|
25
25
|
this.id = get(
|
|
26
26
|
options,
|
|
27
27
|
'chrome.android.deviceSerial',
|
|
@@ -44,7 +44,7 @@ class Android {
|
|
|
44
44
|
if (devices.length > 0) {
|
|
45
45
|
this.id = devices[0].id;
|
|
46
46
|
} else {
|
|
47
|
-
throw Error('No Android phone was found');
|
|
47
|
+
throw new Error('No Android phone was found');
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -59,7 +59,7 @@ class Android {
|
|
|
59
59
|
|
|
60
60
|
async _runCommandAndGet(command) {
|
|
61
61
|
const data = await this.client.shell(this.id, command);
|
|
62
|
-
const output = await
|
|
62
|
+
const output = await util.readAll(data);
|
|
63
63
|
return output.toString().trim();
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -68,7 +68,7 @@ class Android {
|
|
|
68
68
|
this.id,
|
|
69
69
|
'su - root -c "' + command + '"'
|
|
70
70
|
);
|
|
71
|
-
const output = await
|
|
71
|
+
const output = await util.readAll(data);
|
|
72
72
|
return output.toString().trim();
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -77,7 +77,7 @@ class Android {
|
|
|
77
77
|
this.id,
|
|
78
78
|
'su - root -c "' + command + ' && echo SUCCESS || echo FAIL"'
|
|
79
79
|
);
|
|
80
|
-
const output = await
|
|
80
|
+
const output = await util.readAll(data);
|
|
81
81
|
const result = output.toString().trim();
|
|
82
82
|
if (result === 'FAIL') {
|
|
83
83
|
log.error('Failing running as root:' + command);
|
|
@@ -95,7 +95,7 @@ class Android {
|
|
|
95
95
|
resolve();
|
|
96
96
|
});
|
|
97
97
|
transfer.on('error', reject);
|
|
98
|
-
transfer.pipe(
|
|
98
|
+
transfer.pipe(createWriteStream(destinationPath));
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
|
|
@@ -104,7 +104,7 @@ class Android {
|
|
|
104
104
|
|
|
105
105
|
for (const file of files) {
|
|
106
106
|
const fullSourcePath = `${sourcePath}/${file.name}`;
|
|
107
|
-
const fullDestinationPath =
|
|
107
|
+
const fullDestinationPath = join(destinationPath, file.name);
|
|
108
108
|
|
|
109
109
|
if (file.isFile()) {
|
|
110
110
|
await this._downloadFile(fullSourcePath, fullDestinationPath);
|
|
@@ -142,34 +142,40 @@ class Android {
|
|
|
142
142
|
|
|
143
143
|
async reboot() {
|
|
144
144
|
await this.client.reboot(this.id);
|
|
145
|
-
return delay(
|
|
145
|
+
return delay(60_000);
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
async getTemperature() {
|
|
149
|
-
const
|
|
149
|
+
const temporary = Number(
|
|
150
150
|
await this._runCommandAndGet(
|
|
151
151
|
`dumpsys battery | grep temperature | grep -Eo '[0-9]{1,3}'`
|
|
152
152
|
)
|
|
153
153
|
);
|
|
154
|
-
return
|
|
154
|
+
return temporary / 10;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
async getMeta() {
|
|
158
|
-
const rawModel = await
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const
|
|
158
|
+
const rawModel = await util.readAll(
|
|
159
|
+
await this._runCommand(`getprop ro.product.model`)
|
|
160
|
+
);
|
|
161
|
+
const model = rawModel.toString().trim();
|
|
162
|
+
const rawName = await util.readAll(
|
|
163
|
+
await this._runCommand(`getprop ro.product.name`)
|
|
164
|
+
);
|
|
165
|
+
const name = rawName.toString().trim();
|
|
166
|
+
const rawDevice = await util.readAll(
|
|
167
|
+
await this._runCommand(`getprop ro.product.device`)
|
|
168
|
+
);
|
|
169
|
+
const device = rawDevice.toString().trim();
|
|
170
|
+
const rawId = await util.readAll(
|
|
171
|
+
await this._runCommand(`getprop ro.serialno`)
|
|
172
|
+
);
|
|
173
|
+
const id = rawId.toString().trim();
|
|
166
174
|
const wifi = await this.getWifi();
|
|
167
|
-
const rawRelease = await
|
|
168
|
-
`getprop ro.build.version.release `
|
|
175
|
+
const rawRelease = await util.readAll(
|
|
176
|
+
await this._runCommand(`getprop ro.build.version.release `)
|
|
169
177
|
);
|
|
170
|
-
const androidVersion = (
|
|
171
|
-
.toString()
|
|
172
|
-
.trim();
|
|
178
|
+
const androidVersion = rawRelease.toString().trim();
|
|
173
179
|
return { model, name, device, androidVersion, id, wifi };
|
|
174
180
|
}
|
|
175
181
|
|
|
@@ -200,7 +206,7 @@ class Android {
|
|
|
200
206
|
const regex = /(tcp:\d)\w+/g;
|
|
201
207
|
const closeThemAll = [];
|
|
202
208
|
for (let fw of allForwards) {
|
|
203
|
-
if (fw.
|
|
209
|
+
if (fw.includes(this.id)) {
|
|
204
210
|
const f = fw.match(regex);
|
|
205
211
|
if (f.length > 0) {
|
|
206
212
|
closeThemAll.push(
|
|
@@ -221,9 +227,7 @@ class Android {
|
|
|
221
227
|
|
|
222
228
|
async ping(address) {
|
|
223
229
|
const result = await this._runCommandAndGet(`ping -c 1 ${address}`);
|
|
224
|
-
|
|
225
|
-
return true;
|
|
226
|
-
} else return false;
|
|
230
|
+
return result.includes('rtt') ? true : false;
|
|
227
231
|
}
|
|
228
232
|
|
|
229
233
|
async clickPowerButton() {
|
|
@@ -232,17 +236,19 @@ class Android {
|
|
|
232
236
|
}
|
|
233
237
|
|
|
234
238
|
async getWifi() {
|
|
235
|
-
const rawWifiInfo = await
|
|
236
|
-
|
|
239
|
+
const rawWifiInfo = await util.readAll(
|
|
240
|
+
await this._runCommand(
|
|
241
|
+
`dumpsys netstats | grep -E 'iface=wlan.*networkId'`
|
|
242
|
+
)
|
|
237
243
|
);
|
|
238
|
-
const wifiInfo =
|
|
239
|
-
const wifi = wifiInfo.match(/
|
|
244
|
+
const wifiInfo = rawWifiInfo.toString().trim();
|
|
245
|
+
const wifi = wifiInfo.match(/"[^"]*"|^[^"]*$/)[0].replace(/"/g, '');
|
|
240
246
|
return wifi;
|
|
241
247
|
}
|
|
242
248
|
|
|
243
249
|
async closeAppNotRespondingPopup() {
|
|
244
250
|
const result = await this._runCommandAndGet('dumpsys window windows');
|
|
245
|
-
if (result.
|
|
251
|
+
if (result.includes('Application Not Responding')) {
|
|
246
252
|
await this._runCommand('input keyevent KEYCODE_DPAD_RIGHT');
|
|
247
253
|
await this._runCommand('input keyevent KEYCODE_DPAD_RIGHT');
|
|
248
254
|
return this._runCommand('input keyevent KEYCODE_ENTER');
|
|
@@ -285,7 +291,7 @@ class Android {
|
|
|
285
291
|
}
|
|
286
292
|
}
|
|
287
293
|
|
|
288
|
-
return
|
|
294
|
+
return;
|
|
289
295
|
}
|
|
290
296
|
|
|
291
297
|
async _pidofWithPidof(packageName) {
|
|
@@ -293,7 +299,7 @@ class Android {
|
|
|
293
299
|
const cmd1 = `pidof ${packageName}`;
|
|
294
300
|
log.debug(`pidof ${cmd1}`);
|
|
295
301
|
const proc1 = await this._runCommand(cmd1);
|
|
296
|
-
const ps1 = await
|
|
302
|
+
const ps1 = await util.readAll(proc1);
|
|
297
303
|
const ps = ps1.toString();
|
|
298
304
|
log.debug(`pidof ${ps}`);
|
|
299
305
|
|
|
@@ -309,7 +315,7 @@ class Android {
|
|
|
309
315
|
return Number.parseInt(ps.trim());
|
|
310
316
|
}
|
|
311
317
|
|
|
312
|
-
return
|
|
318
|
+
return;
|
|
313
319
|
}
|
|
314
320
|
|
|
315
321
|
async _pidofWithPs(packageName) {
|
|
@@ -322,11 +328,11 @@ class Android {
|
|
|
322
328
|
const cmd = `ps`;
|
|
323
329
|
log.debug(`pidof ${cmd}`);
|
|
324
330
|
const proc = await this._runCommand(cmd);
|
|
325
|
-
const
|
|
326
|
-
const ps =
|
|
331
|
+
const psTemporary = await util.readAll(proc);
|
|
332
|
+
const ps = psTemporary.toString();
|
|
327
333
|
log.debug(`pidof ${ps}`);
|
|
328
334
|
|
|
329
|
-
const lines = ps.split(/[\r
|
|
335
|
+
const lines = ps.split(/[\n\r]+/);
|
|
330
336
|
|
|
331
337
|
// Galaxy S5 example:
|
|
332
338
|
// USER PID PPID VSIZE RSS WCHAN PC NAME
|
|
@@ -343,7 +349,7 @@ class Android {
|
|
|
343
349
|
// methodologies like pidof work so we don't need to handle that here.
|
|
344
350
|
const packageNameIndex = headerParts.indexOf('NAME') + 1;
|
|
345
351
|
|
|
346
|
-
for (const line of ps.split(/[\r
|
|
352
|
+
for (const line of ps.split(/[\n\r]+/)) {
|
|
347
353
|
const lineParts = line.split(/\s+/);
|
|
348
354
|
const processPackage = lineParts[packageNameIndex];
|
|
349
355
|
const processPid = lineParts[pidIndex];
|
|
@@ -358,7 +364,7 @@ class Android {
|
|
|
358
364
|
}
|
|
359
365
|
}
|
|
360
366
|
|
|
361
|
-
return
|
|
367
|
+
return;
|
|
362
368
|
}
|
|
363
369
|
|
|
364
370
|
async _processStartTime(pid) {
|
|
@@ -376,8 +382,8 @@ class Android {
|
|
|
376
382
|
// `cut` and `awk`, to make this more robust.
|
|
377
383
|
const cut = `echo $EPOCHREALTIME && cut -d ' ' -f 1 /proc/uptime && cut -d ' ' -f 22 /proc/self/stat /proc/${pid}/stat`;
|
|
378
384
|
// const awk = `date +%s%3N && awk '{print $1}' /proc/uptime && awk '{print $22}' /proc/self/stat /proc/${pid}/stat`;
|
|
379
|
-
const statAndTimestamp = await this._runCommand(cut);
|
|
380
|
-
const output =
|
|
385
|
+
const statAndTimestamp = await util.readAll(await this._runCommand(cut));
|
|
386
|
+
const output = statAndTimestamp.toString();
|
|
381
387
|
|
|
382
388
|
const [
|
|
383
389
|
dateInS,
|
|
@@ -386,9 +392,9 @@ class Android {
|
|
|
386
392
|
processStartTimeAfterSystemStartTimeInJiffies
|
|
387
393
|
] = output
|
|
388
394
|
.trim()
|
|
389
|
-
.split(/[\r
|
|
395
|
+
.split(/[\n\r]+/)
|
|
390
396
|
.map(v => Number.parseFloat(v.trim()));
|
|
391
|
-
const dateInMs = Math.round(dateInS * 1000
|
|
397
|
+
const dateInMs = Math.round(dateInS * 1000);
|
|
392
398
|
|
|
393
399
|
// Usually 100, but this isn't strictly guaranteed by Android.
|
|
394
400
|
const jiffesPerSeconds = Math.round(
|
|
@@ -401,7 +407,7 @@ class Android {
|
|
|
401
407
|
(processStartTimeAfterSystemStartTimeInJiffies * MILLIS_PER_S) /
|
|
402
408
|
jiffesPerSeconds;
|
|
403
409
|
|
|
404
|
-
const
|
|
410
|
+
const object = {
|
|
405
411
|
dateInMs,
|
|
406
412
|
systemUptimeInSeconds,
|
|
407
413
|
utilStartTimeAfterSystemStartTimeInJiffies,
|
|
@@ -411,15 +417,15 @@ class Android {
|
|
|
411
417
|
};
|
|
412
418
|
// log.debug(`_processStartTime`, obj); // Too verbose for regular use.
|
|
413
419
|
|
|
414
|
-
return
|
|
420
|
+
return object;
|
|
415
421
|
}
|
|
416
422
|
|
|
417
423
|
async processStartTime(pid, count = 3) {
|
|
418
424
|
// This is inheritently racy and therefore noisy. Average `count` trials.
|
|
419
425
|
let total = 0;
|
|
420
|
-
for (let
|
|
421
|
-
const
|
|
422
|
-
total +=
|
|
426
|
+
for (let index = 0; index < count; index++) {
|
|
427
|
+
const object = await this._processStartTime(pid);
|
|
428
|
+
total += object.processStartTimeInMs;
|
|
423
429
|
}
|
|
424
430
|
return Math.round(total / count);
|
|
425
431
|
}
|
|
@@ -474,7 +480,7 @@ async function parsePowerMetrics(batterystats, packageName) {
|
|
|
474
480
|
let found;
|
|
475
481
|
let powerData = {};
|
|
476
482
|
|
|
477
|
-
batterystats.split(/\r?\n/)
|
|
483
|
+
for (const line of batterystats.split(/\r?\n/)) {
|
|
478
484
|
if (!uid) {
|
|
479
485
|
// Find the applications UID first
|
|
480
486
|
let match = line.match(reUid);
|
|
@@ -482,7 +488,7 @@ async function parsePowerMetrics(batterystats, packageName) {
|
|
|
482
488
|
uid = match[1];
|
|
483
489
|
rePower = new RegExp(`.+Uid ${uid}: ([0-9.]+)(.*)`);
|
|
484
490
|
}
|
|
485
|
-
|
|
491
|
+
continue;
|
|
486
492
|
}
|
|
487
493
|
if (!foundEstimations) {
|
|
488
494
|
// Ignore all lines until we find the estimation section
|
|
@@ -490,20 +496,20 @@ async function parsePowerMetrics(batterystats, packageName) {
|
|
|
490
496
|
if (match) {
|
|
491
497
|
foundEstimations = true;
|
|
492
498
|
}
|
|
493
|
-
|
|
499
|
+
continue;
|
|
494
500
|
}
|
|
495
501
|
if (!('full-screen' in powerData)) {
|
|
496
502
|
// Measures the full power used by the screen (not app-specific)
|
|
497
503
|
let match = line.match(reScreen);
|
|
498
504
|
if (match) {
|
|
499
|
-
powerData['full-screen'] = parseFloat(match[1]);
|
|
505
|
+
powerData['full-screen'] = Number.parseFloat(match[1]);
|
|
500
506
|
}
|
|
501
507
|
}
|
|
502
508
|
if (!('full-wifi' in powerData)) {
|
|
503
509
|
// Measures the full power used by the wifi (not app-specific)
|
|
504
510
|
let match = line.match(reWifi);
|
|
505
511
|
if (match) {
|
|
506
|
-
powerData['full-wifi'] = parseFloat(match[1]);
|
|
512
|
+
powerData['full-wifi'] = Number.parseFloat(match[1]);
|
|
507
513
|
}
|
|
508
514
|
}
|
|
509
515
|
if (rePower && !found) {
|
|
@@ -511,44 +517,41 @@ async function parsePowerMetrics(batterystats, packageName) {
|
|
|
511
517
|
// Uid u0a120: 0.826 ( cpu=0.826, wifi=99 )
|
|
512
518
|
let match = line.match(rePower);
|
|
513
519
|
if (!match) {
|
|
514
|
-
|
|
520
|
+
continue;
|
|
515
521
|
}
|
|
516
522
|
found = true;
|
|
517
523
|
|
|
518
524
|
// First value is the total used by the app
|
|
519
|
-
powerData['total'] = parseFloat(match[1]);
|
|
525
|
+
powerData['total'] = Number.parseFloat(match[1]);
|
|
520
526
|
|
|
521
527
|
// Gather the breakdown of the total value from
|
|
522
528
|
// the "name=val" entries in the line
|
|
523
529
|
let breakdown = match[2];
|
|
524
530
|
if (breakdown) {
|
|
525
|
-
match = breakdown.match(/([
|
|
531
|
+
match = breakdown.match(/([A-Za-z]+)=([\d.]+)/g);
|
|
526
532
|
if (!match) {
|
|
527
|
-
|
|
533
|
+
continue;
|
|
528
534
|
}
|
|
529
|
-
|
|
535
|
+
for (const category of match) {
|
|
530
536
|
let [name, value] = category.split('=');
|
|
531
|
-
powerData[name] = parseFloat(value);
|
|
532
|
-
}
|
|
537
|
+
powerData[name] = Number.parseFloat(value);
|
|
538
|
+
}
|
|
533
539
|
}
|
|
534
540
|
}
|
|
535
|
-
}
|
|
541
|
+
}
|
|
536
542
|
|
|
537
543
|
return powerData;
|
|
538
544
|
}
|
|
539
545
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
: false;
|
|
553
|
-
}
|
|
554
|
-
};
|
|
546
|
+
export function isAndroidConfigured(options) {
|
|
547
|
+
if (options.android && options.android.enabled === true) {
|
|
548
|
+
return true;
|
|
549
|
+
}
|
|
550
|
+
return get(
|
|
551
|
+
options,
|
|
552
|
+
'chrome.android.package',
|
|
553
|
+
get(options, 'firefox.android.package', false)
|
|
554
|
+
)
|
|
555
|
+
? true
|
|
556
|
+
: false;
|
|
557
|
+
}
|
package/lib/android/root.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const log = require('intel').getLogger('browsertime.android');
|
|
1
|
+
import intel from 'intel';
|
|
2
|
+
const log = intel.getLogger('browsertime.android');
|
|
4
3
|
|
|
5
4
|
// Adopted from
|
|
6
5
|
// https://dxr.mozilla.org/mozilla-central/source/testing/raptor/raptor/performance_tuning.py
|
|
@@ -74,12 +73,12 @@ class RootedDevice {
|
|
|
74
73
|
// # MSM8937(8x 1.4GHz)
|
|
75
74
|
// values obtained from:
|
|
76
75
|
// /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
|
|
77
|
-
for (let
|
|
76
|
+
for (let index = 0; index < 8; index++) {
|
|
78
77
|
await this.client._runAsRoot(
|
|
79
|
-
`echo performance > /sys/devices/system/cpu/cpu${
|
|
78
|
+
`echo performance > /sys/devices/system/cpu/cpu${index}/cpufreq/scaling_governor`
|
|
80
79
|
);
|
|
81
80
|
await this.client._runAsRoot(
|
|
82
|
-
`echo 1401000 > /sys/devices/system/cpu/cpu${
|
|
81
|
+
`echo 1401000 > /sys/devices/system/cpu/cpu${index}/cpufreq/scaling_min_freq`
|
|
83
82
|
);
|
|
84
83
|
}
|
|
85
84
|
}
|
|
@@ -201,6 +200,4 @@ class RootedDevice {
|
|
|
201
200
|
}
|
|
202
201
|
}
|
|
203
202
|
|
|
204
|
-
|
|
205
|
-
RootedDevice
|
|
206
|
-
};
|
|
203
|
+
export default RootedDevice;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const defaultTraceCategories = require('./settings/traceCategories');
|
|
1
|
+
import intel from 'intel';
|
|
2
|
+
import CDP from 'chrome-remote-interface';
|
|
3
|
+
import btoa from 'btoa';
|
|
4
|
+
const log = intel.getLogger('browsertime.chrome.cdp');
|
|
5
|
+
import { toArray } from '../support/util.js';
|
|
6
|
+
import defaultTraceCategories from './settings/traceCategories.js';
|
|
8
7
|
|
|
9
8
|
const MIME_TYPE_MATCHERS = [
|
|
10
9
|
[/^text\/html/, 'html'],
|
|
@@ -35,7 +34,7 @@ class ChromeDevtoolsProtocol {
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
if (this.chrome.traceCategory) {
|
|
38
|
-
const extraCategories =
|
|
37
|
+
const extraCategories = toArray(this.chrome.traceCategory);
|
|
39
38
|
Array.prototype.push.apply(this.chromeTraceCategories, extraCategories);
|
|
40
39
|
}
|
|
41
40
|
|
|
@@ -50,14 +49,12 @@ class ChromeDevtoolsProtocol {
|
|
|
50
49
|
// https://github.com/cyrus-and/chrome-remote-interface/issues/332
|
|
51
50
|
|
|
52
51
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this.cdpClient = await CDP({ port: this.options.devToolsPort });
|
|
60
|
-
}
|
|
52
|
+
this.cdpClient = await (this.chrome.android
|
|
53
|
+
? CDP({
|
|
54
|
+
local: true,
|
|
55
|
+
port: this.options.devToolsPort
|
|
56
|
+
})
|
|
57
|
+
: CDP({ port: this.options.devToolsPort }));
|
|
61
58
|
// Enable what's needs to be enabled
|
|
62
59
|
// Page is needed to inject JS to a page
|
|
63
60
|
await this.cdpClient.Page.enable();
|
|
@@ -67,9 +64,9 @@ class ChromeDevtoolsProtocol {
|
|
|
67
64
|
await this.cdpClient.Performance.enable();
|
|
68
65
|
|
|
69
66
|
this.isTracingDataCollectedAdded = false;
|
|
70
|
-
} catch (
|
|
71
|
-
log.error('Could not setup the Chrome Devtools Protocol',
|
|
72
|
-
throw
|
|
67
|
+
} catch (error) {
|
|
68
|
+
log.error('Could not setup the Chrome Devtools Protocol', error);
|
|
69
|
+
throw error;
|
|
73
70
|
}
|
|
74
71
|
}
|
|
75
72
|
async startTrace() {
|
|
@@ -121,12 +118,12 @@ class ChromeDevtoolsProtocol {
|
|
|
121
118
|
}
|
|
122
119
|
|
|
123
120
|
async blockUrls(blockers) {
|
|
124
|
-
const block =
|
|
121
|
+
const block = toArray(blockers);
|
|
125
122
|
return this.cdpClient.Network.setBlockedURLs({ urls: block });
|
|
126
123
|
}
|
|
127
124
|
|
|
128
125
|
async setCookies(url, cookie) {
|
|
129
|
-
const cookies =
|
|
126
|
+
const cookies = toArray(cookie);
|
|
130
127
|
for (let cookieParts of cookies) {
|
|
131
128
|
const parts = new Array(
|
|
132
129
|
cookieParts.slice(0, cookieParts.indexOf('=')),
|
|
@@ -153,9 +150,9 @@ class ChromeDevtoolsProtocol {
|
|
|
153
150
|
}
|
|
154
151
|
|
|
155
152
|
async loadingFailed() {
|
|
156
|
-
return this.cdpClient.Network.loadingFailed(
|
|
157
|
-
if (
|
|
158
|
-
log.debug('Could not load document:' +
|
|
153
|
+
return this.cdpClient.Network.loadingFailed(parameter => {
|
|
154
|
+
if (parameter.type === 'Document') {
|
|
155
|
+
log.debug('Could not load document:' + parameter.errorText);
|
|
159
156
|
}
|
|
160
157
|
});
|
|
161
158
|
}
|
|
@@ -163,10 +160,10 @@ class ChromeDevtoolsProtocol {
|
|
|
163
160
|
async setRequestHeaders(requestHeaders) {
|
|
164
161
|
// Our cli don't validate parameters
|
|
165
162
|
// so -run will become -r etc
|
|
166
|
-
const headersArray =
|
|
163
|
+
const headersArray = toArray(requestHeaders);
|
|
167
164
|
const headers = {};
|
|
168
165
|
for (let header of headersArray) {
|
|
169
|
-
if (header.indexOf && header.
|
|
166
|
+
if (header.indexOf && header.includes(':')) {
|
|
170
167
|
const parts = header.split(':');
|
|
171
168
|
headers[parts[0]] = parts[1];
|
|
172
169
|
} else {
|
|
@@ -185,8 +182,8 @@ class ChromeDevtoolsProtocol {
|
|
|
185
182
|
return this.cdpClient.on(event, f);
|
|
186
183
|
}
|
|
187
184
|
|
|
188
|
-
async send(cmd,
|
|
189
|
-
return this.cdpClient.send(cmd,
|
|
185
|
+
async send(cmd, parameters) {
|
|
186
|
+
return this.cdpClient.send(cmd, parameters);
|
|
190
187
|
}
|
|
191
188
|
|
|
192
189
|
async close() {
|
|
@@ -210,27 +207,31 @@ class ChromeDevtoolsProtocol {
|
|
|
210
207
|
requestId: entry._requestId
|
|
211
208
|
});
|
|
212
209
|
entry.response.content.text = html.body;
|
|
213
|
-
} catch (
|
|
214
|
-
log.debug(
|
|
210
|
+
} catch (error) {
|
|
211
|
+
log.debug(
|
|
212
|
+
'Could not find a matching resource to get the HTML',
|
|
213
|
+
error
|
|
214
|
+
);
|
|
215
215
|
}
|
|
216
|
-
} else if (
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
entry.
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
216
|
+
} else if (
|
|
217
|
+
this.chrome.includeResponseBodies === 'all' &&
|
|
218
|
+
getContentType(entry.response.content.mimeType) !== 'other'
|
|
219
|
+
) {
|
|
220
|
+
try {
|
|
221
|
+
const response = await this.cdpClient.Network.getResponseBody({
|
|
222
|
+
requestId: entry._requestId
|
|
223
|
+
});
|
|
224
|
+
entry.response.content.text = response.body;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
log.debug(
|
|
227
|
+
'Could not find a matching resource to get the ' +
|
|
228
|
+
entry.response.content.mimeType,
|
|
229
|
+
error
|
|
230
|
+
);
|
|
230
231
|
}
|
|
231
232
|
}
|
|
232
233
|
}
|
|
233
234
|
}
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
|
-
|
|
237
|
+
export default ChromeDevtoolsProtocol;
|
package/lib/chrome/har.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
import intel from 'intel';
|
|
2
|
+
import { harFromMessages } from 'chrome-har';
|
|
3
|
+
import { logging } from 'selenium-webdriver';
|
|
4
|
+
const log = intel.getLogger('browsertime.chrome');
|
|
5
|
+
import { addBrowser } from '../support/har/index.js';
|
|
6
|
+
const { Type } = logging;
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
const perflogParser = require('chrome-har');
|
|
5
|
-
const harBuilder = require('../support/har');
|
|
6
|
-
const { Type } = require('selenium-webdriver').logging;
|
|
7
|
-
|
|
8
|
-
module.exports = async function (
|
|
8
|
+
export default async function (
|
|
9
9
|
runner,
|
|
10
10
|
result,
|
|
11
11
|
index,
|
|
@@ -32,15 +32,14 @@ module.exports = async function (
|
|
|
32
32
|
// https://bugs.chromium.org/p/chromedriver/issues/detail?id=1811
|
|
33
33
|
await runner.getLogs(Type.PERFORMANCE);
|
|
34
34
|
|
|
35
|
-
const har =
|
|
35
|
+
const har = harFromMessages(messages);
|
|
36
36
|
|
|
37
37
|
if (includeResponseBodies === 'html' || includeResponseBodies === 'all') {
|
|
38
38
|
await cdpClient.setResponseBodies(har);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
).product.split('/');
|
|
41
|
+
const getVersion = await cdpClient.send('Browser.getVersion');
|
|
42
|
+
const versionInfo = getVersion.product.split('/');
|
|
44
43
|
const info = {
|
|
45
44
|
name: versionInfo[0],
|
|
46
45
|
version: versionInfo[1]
|
|
@@ -49,7 +48,7 @@ module.exports = async function (
|
|
|
49
48
|
if (mobileEmulation) {
|
|
50
49
|
info.name = `Chrome Emulated ${chrome.mobileEmulation.deviceName}`;
|
|
51
50
|
}
|
|
52
|
-
|
|
51
|
+
addBrowser(har, info.name, info.version);
|
|
53
52
|
|
|
54
53
|
if (androidClient) {
|
|
55
54
|
har.log._android = await androidClient.getMeta();
|
|
@@ -69,4 +68,4 @@ module.exports = async function (
|
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
return har;
|
|
72
|
-
}
|
|
71
|
+
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import get from 'lodash.get';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
module.exports = function (result, options) {
|
|
3
|
+
export default function (result, options) {
|
|
6
4
|
let totalDurationFirstPaint = 0;
|
|
7
5
|
let totalDurationFirstContentFulPaint = 0;
|
|
8
6
|
let totalDurationLargestContentFulPaint = 0;
|
|
@@ -96,4 +94,4 @@ module.exports = function (result, options) {
|
|
|
96
94
|
}
|
|
97
95
|
};
|
|
98
96
|
return cpu;
|
|
99
|
-
}
|
|
97
|
+
}
|