browsertime 17.15.0 → 17.17.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 CHANGED
@@ -1,5 +1,17 @@
1
1
  # Browsertime changelog (we do [semantic versioning](https://semver.org))
2
2
 
3
+ ## 17.17.0 - 2022-10-11
4
+ ### Added
5
+ * Firefox 118, Edge 117 and Chrome/Chromedriver 118 in the Docker container [#1996](https://github.com/sitespeedio/browsertime/pull/1996).
6
+ * Expose trace start/stop for Chrome in scripting (the same way as for Firefox). Thank you [KS](https://github.com/92kns) for [#1988](https://github.com/sitespeedio/browsertime/pull/1988). Documentation is coming when the functionality is rolled out in sitespeed.io.
7
+
8
+ ## 17.16.0 - 2022-09-04
9
+ ### Added
10
+ * Firefox 117 and Edge 116 in the Docker container.
11
+
12
+ ### Fixed
13
+ * Updated the BiDi HAR exporter for Firefox to version 0.0.12. This version will not work with Firefox 116 so if you use the BiDi HAR exporter you need to upgrade to Firefox 117.
14
+
3
15
  ## 17.15.0 - 2022-08-16
4
16
  ### Added
5
17
  * Updated Chrome and Chromedriver to 116.
@@ -15,11 +15,7 @@ import { parse } from '../traceCategoriesParser.js';
15
15
  import { pathToFolder } from '../../support/pathToFolder.js';
16
16
  import { ChromeDevtoolsProtocol } from '../chromeDevtoolsProtocol.js';
17
17
  import { Android, isAndroidConfigured } from '../../android/index.js';
18
- import {
19
- getFirstContentFulPaintEvent,
20
- getLargestContentfulPaintEvent,
21
- getRecalculateStyleElementsAndTimeBefore
22
- } from './traceUtilities.js';
18
+ import { getRenderBlocking } from './traceUtilities.js';
23
19
  const unlink = promisify(_unlink);
24
20
  const rm = promisify(_rm);
25
21
 
@@ -160,7 +156,11 @@ export class Chromium {
160
156
  await this.android.resetPowerUsage();
161
157
  }
162
158
 
163
- if (this.collectTracingEvents && !this.isTracing) {
159
+ if (
160
+ this.collectTracingEvents &&
161
+ !this.isTracing &&
162
+ this.options.chrome.timelineRecordingType !== 'custom'
163
+ ) {
164
164
  this.isTracing = true;
165
165
  return this.cdpClient.startTrace();
166
166
  }
@@ -174,7 +174,11 @@ export class Chromium {
174
174
  */
175
175
  async afterPageCompleteCheck(runner, index, url, alias) {
176
176
  const result = { url, alias };
177
- if (this.collectTracingEvents && this.isTracing) {
177
+ if (
178
+ this.collectTracingEvents &&
179
+ this.isTracing &&
180
+ this.options.chrome.timelineRecordingType !== 'custom'
181
+ ) {
178
182
  // We are ready and can stop collecting events
179
183
  this.isTracing = false;
180
184
  this.events = await this.cdpClient.stopTrace();
@@ -334,7 +338,10 @@ export class Chromium {
334
338
  await this.storageManager.gzip(filename, gzFilename, true);
335
339
  }
336
340
 
337
- if (this.collectTracingEvents) {
341
+ if (
342
+ this.collectTracingEvents &&
343
+ this.options.chrome.timelineRecordingType !== 'custom'
344
+ ) {
338
345
  const trace = parse(this.events, result.url);
339
346
  const name = this.options.enableProfileRun
340
347
  ? `trace-${index}-extra-run.json`
@@ -345,50 +352,19 @@ export class Chromium {
345
352
  result.cpu = cpu;
346
353
 
347
354
  // Collect render blocking info
348
- const renderBlockingInfo = {};
349
- const urlsWithBlockingInfo = trace.traceEvents.filter(
350
- task =>
351
- task.cat === 'devtools.timeline' &&
352
- task.name === 'ResourceSendRequest' &&
353
- task.args.data.url &&
354
- task.args.data.renderBlocking
355
- );
356
- for (let asset of urlsWithBlockingInfo) {
357
- renderBlockingInfo[asset.args.data.url] =
358
- asset.args.data.renderBlocking;
359
- }
360
-
361
- const fcpEvent = getFirstContentFulPaintEvent(trace.traceEvents);
362
- const lcpEvent = getLargestContentfulPaintEvent(trace.traceEvents);
363
-
364
- result.renderBlocking = { recalculateStyle: {}, requests: {} };
365
-
366
- if (fcpEvent) {
367
- const beforeFCP = getRecalculateStyleElementsAndTimeBefore(
368
- trace.traceEvents,
369
- fcpEvent.ts
370
- );
371
- result.renderBlocking.recalculateStyle.beforeFCP = beforeFCP;
372
- }
373
-
374
- if (lcpEvent) {
375
- const beforeLCP = getRecalculateStyleElementsAndTimeBefore(
376
- trace.traceEvents,
377
- lcpEvent.ts
378
- );
379
- result.renderBlocking.recalculateStyle.beforeLCP = beforeLCP;
380
- }
355
+ const render = await getRenderBlocking(trace);
356
+ result.renderBlocking = render.renderBlocking;
381
357
 
382
358
  if (!this.options.skipHar) {
383
359
  for (let harRequest of this.hars[index - 1].log.entries) {
384
- if (renderBlockingInfo[harRequest.request.url]) {
360
+ if (render.renderBlockingInfo[harRequest.request.url]) {
385
361
  harRequest._renderBlocking =
386
- renderBlockingInfo[harRequest.request.url];
362
+ render.renderBlockingInfo[harRequest.request.url];
387
363
  }
388
364
  }
389
365
  }
390
366
 
391
- result.renderBlocking.requests = renderBlockingInfo;
367
+ result.renderBlocking.requests = render.renderBlockingInfo;
392
368
  }
393
369
 
394
370
  // Google Web Vitals hacksery
@@ -1,7 +1,7 @@
1
1
  import intel from 'intel';
2
2
  const log = intel.getLogger('browsertime.chrome');
3
3
 
4
- export function getLargestContentfulPaintEvent(traceEvents) {
4
+ function getLargestContentfulPaintEvent(traceEvents) {
5
5
  const lcpCandidates = traceEvents.filter(
6
6
  task => task.name === 'largestContentfulPaint::Candidate'
7
7
  );
@@ -20,7 +20,7 @@ export function getLargestContentfulPaintEvent(traceEvents) {
20
20
  }
21
21
  }
22
22
 
23
- export function getFirstContentFulPaintEvent(traceEvents) {
23
+ function getFirstContentFulPaintEvent(traceEvents) {
24
24
  // Get first contentful paint
25
25
  const fcpEvent = traceEvents.find(
26
26
  task => task.name === 'firstContentfulPaint'
@@ -33,10 +33,7 @@ export function getFirstContentFulPaintEvent(traceEvents) {
33
33
  }
34
34
  }
35
35
 
36
- export function getRecalculateStyleElementsAndTimeBefore(
37
- traceEvents,
38
- timestamp
39
- ) {
36
+ function getRecalculateStyleElementsAndTimeBefore(traceEvents, timestamp) {
40
37
  const recalculatesBefore = traceEvents.filter(
41
38
  task =>
42
39
  task.cat === 'disabled-by-default-devtools.timeline' &&
@@ -62,3 +59,41 @@ export function getRecalculateStyleElementsAndTimeBefore(
62
59
 
63
60
  return { elements, durationInMillis: duration / 1000 };
64
61
  }
62
+
63
+ export async function getRenderBlocking(trace) {
64
+ const renderBlockingInfo = {};
65
+
66
+ const urlsWithBlockingInfo = trace.traceEvents.filter(
67
+ task =>
68
+ task.cat === 'devtools.timeline' &&
69
+ task.name === 'ResourceSendRequest' &&
70
+ task.args.data.url &&
71
+ task.args.data.renderBlocking
72
+ );
73
+ for (let asset of urlsWithBlockingInfo) {
74
+ renderBlockingInfo[asset.args.data.url] = asset.args.data.renderBlocking;
75
+ }
76
+
77
+ const fcpEvent = getFirstContentFulPaintEvent(trace.traceEvents);
78
+ const lcpEvent = getLargestContentfulPaintEvent(trace.traceEvents);
79
+
80
+ const renderBlocking = { recalculateStyle: {}, requests: {} };
81
+
82
+ if (fcpEvent) {
83
+ const beforeFCP = getRecalculateStyleElementsAndTimeBefore(
84
+ trace.traceEvents,
85
+ fcpEvent.ts
86
+ );
87
+ renderBlocking.recalculateStyle.beforeFCP = beforeFCP;
88
+ }
89
+
90
+ if (lcpEvent) {
91
+ const beforeLCP = getRecalculateStyleElementsAndTimeBefore(
92
+ trace.traceEvents,
93
+ lcpEvent.ts
94
+ );
95
+ renderBlocking.recalculateStyle.beforeLCP = beforeLCP;
96
+ }
97
+
98
+ return { renderBlockingInfo, renderBlocking };
99
+ }
@@ -0,0 +1,63 @@
1
+ import intel from 'intel';
2
+
3
+ import { getRenderBlocking } from '../../../chrome/webdriver/traceUtilities.js';
4
+ import { parse } from '../../../chrome/traceCategoriesParser.js';
5
+ import { parseCPUTrace } from '../../../chrome/parseCpuTrace.js';
6
+ const log = intel.getLogger('browsertime.command.chrometrace');
7
+ export class ChromeTrace {
8
+ constructor(engineDelegate, index, options, result) {
9
+ this.engineDelegate = engineDelegate;
10
+ this.options = options;
11
+ this.result = result;
12
+ this.index = index;
13
+ }
14
+
15
+ async start() {
16
+ if (this.options.browser === 'chrome') {
17
+ if (this.options.chrome.timelineRecordingType === 'custom') {
18
+ return this.engineDelegate.getCDPClient().startTrace();
19
+ } else {
20
+ log.info(
21
+ 'You need to set traceRecordingType to custom to turn on the profiler in scripting'
22
+ );
23
+ }
24
+ } else {
25
+ throw new Error('Trace only works in Chrome');
26
+ }
27
+ }
28
+
29
+ async stop() {
30
+ if (this.options.browser === 'chrome') {
31
+ if (this.options.chrome.timelineRecordingType === 'custom') {
32
+ let result = this.result[0];
33
+
34
+ this.events = [];
35
+ this.events = await this.engineDelegate.getCDPClient().stopTrace();
36
+ const trace = parse(this.events, result.url);
37
+ const name = this.options.enableProfileRun
38
+ ? `trace-${this.index}-extra-run.json`
39
+ : `trace-${this.index}.json`;
40
+ result.extraJson[name] = trace;
41
+
42
+ const cpu = await parseCPUTrace(trace, result.url);
43
+ result.cpu = cpu;
44
+
45
+ // Collect render blocking info
46
+ const render = await getRenderBlocking(trace);
47
+
48
+ result.renderBlocking = render.renderBlocking;
49
+
50
+ if (!this.options.skipHar) {
51
+ for (let harRequest of this.hars[this.index - 1].log.entries) {
52
+ if (render.renderBlockingInfo[harRequest.request.url]) {
53
+ harRequest._renderBlocking =
54
+ render.renderBlockingInfo[harRequest.request.url];
55
+ }
56
+ }
57
+ }
58
+ }
59
+ } else {
60
+ throw new Error('Trace only works in Chrome');
61
+ }
62
+ }
63
+ }
@@ -24,6 +24,7 @@ import { Select } from './command/select.js';
24
24
  import { Debug } from './command/debug.js';
25
25
  import { AndroidCommand } from './command/android.js';
26
26
  import { ChromeDevelopmentToolsProtocol } from './command/chromeDevToolsProtocol.js';
27
+ import { ChromeTrace } from './command/chromeTrace.js';
27
28
  import {
28
29
  addConnectivity,
29
30
  removeConnectivity
@@ -164,10 +165,12 @@ export class Iteration {
164
165
  engineDelegate,
165
166
  options.browser
166
167
  );
168
+ const trace = new ChromeTrace(engineDelegate, index, options, result);
167
169
  const android = new Android(options);
168
170
  const debug = new Debug(browser, options);
169
171
  const commands = {
170
172
  profiler: profiler,
173
+ trace: trace,
171
174
  click: new Click(browser, this.pageCompleteCheck),
172
175
  scroll: new Scroll(browser, options),
173
176
  addText: new AddText(browser),
@@ -274,6 +274,14 @@ export function parseCommandLine() {
274
274
  type: 'boolean',
275
275
  group: 'chrome'
276
276
  })
277
+ .option('chrome.timelineRecordingType', {
278
+ alias: 'chrome.traceRecordingType',
279
+ describe: 'Expose the start/stop commands for the chrome trace',
280
+ default: 'pageload',
281
+ choices: ['pageload', 'custom'],
282
+ type: 'string',
283
+ group: 'chrome'
284
+ })
277
285
  .option('chrome.collectPerfLog', {
278
286
  type: 'boolean',
279
287
  describe:
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "browsertime",
3
3
  "description": "Get performance metrics from your web page using Browsertime.",
4
- "version": "17.15.0",
4
+ "version": "17.17.0",
5
5
  "bin": "./bin/browsertime.js",
6
6
  "type": "module",
7
7
  "dependencies": {
8
8
  "@cypress/xvfb": "1.2.4",
9
9
  "@devicefarmer/adbkit": "2.11.3",
10
- "@sitespeed.io/chromedriver": "116.0.5845-96",
10
+ "@sitespeed.io/chromedriver": "118.0.5993-70",
11
11
  "@sitespeed.io/edgedriver": "115.0.1901-183",
12
12
  "@sitespeed.io/geckodriver": "0.33.0",
13
13
  "@sitespeed.io/throttle": "5.0.0",
14
14
  "@sitespeed.io/tracium": "0.3.3",
15
- "ff-test-bidi-har-export": "0.0.11",
15
+ "ff-test-bidi-har-export": "0.0.12",
16
16
  "btoa": "1.2.1",
17
17
  "chrome-har": "0.13.2",
18
18
  "chrome-remote-interface": "0.33.0",
@@ -29,7 +29,7 @@
29
29
  "lodash.merge": "4.6.2",
30
30
  "lodash.pick": "4.4.0",
31
31
  "lodash.set": "4.3.2",
32
- "selenium-webdriver": "4.11.1",
32
+ "selenium-webdriver": "4.12.0",
33
33
  "yargs": "17.7.2"
34
34
  },
35
35
  "optionalDependencies": {