browsertime 21.4.0 → 21.5.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,6 +1,15 @@
1
1
  # Browsertime changelog (we do [semantic versioning](https://semver.org))
2
2
 
3
+ ## 21.5.0 - 2024-03-12
4
+ ### Added
5
+ * Firefox:
6
+ * Move injectJS functionality to Bidi [#2088](https://github.com/sitespeedio/browsertime/pull/2088). This makes it possible to inject JS in Firefox on mobile.
7
+ * Expose Bidi in commands [#2091](https://github.com/sitespeedio/browsertime/pull/2091). You can now use webdriver bidi direct in your commands.
8
+ ### Fixed
9
+ * Fixed command action.clear() that actually didn't clear the command [#2095](https://github.com/sitespeedio/browsertime/pull/2095).
10
+
3
11
  ## 21.4.0 - 2024-03-08
12
+ ### Added
4
13
  * Added the following trace categories for Chrome that now is used by default when you turn on the timeline: 'disabled-by-default-devtools.timeline.frame', 'disabled-by-default-devtools.timeline.invalidationTracking','loading', 'latencyInfo' - done in [#2086](https://github.com/sitespeedio/browsertime/pull/2086).
5
14
  * Added a simple Loaf-script to get the 10 largest loaf. Lets iterate over the script and see how we can get the most useful information from it [#2087](https://github.com/sitespeedio/browsertime/pull/2087).
6
15
 
@@ -30,7 +30,7 @@ export class Actions {
30
30
  * cleared.
31
31
  */
32
32
  async clear() {
33
- return this.driver.actions().clear();
33
+ return this.actions.clear();
34
34
  }
35
35
 
36
36
  /**
@@ -0,0 +1,113 @@
1
+ import intel from 'intel';
2
+ const log = intel.getLogger('browsertime.command.bidi');
3
+
4
+ /**
5
+ * Manages interactions using Bidi. At the moment this only works for Firefox
6
+ * but Chrome and maybe other browsers will support it in the future.
7
+ * @class
8
+ * @hideconstructor
9
+ * @see https://w3c.github.io/webdriver-bidi/
10
+ */
11
+ export class Bidi {
12
+ constructor(engineDelegate, browserName) {
13
+ /**
14
+ * @private
15
+ */
16
+ this.engineDelegate = engineDelegate;
17
+ /**
18
+ * @private
19
+ */
20
+ this.browserName = browserName;
21
+ }
22
+
23
+ /**
24
+ * Add a fanction that will get the events that you subscribes.
25
+ * @async
26
+ * @param {Function} f - The callback function to handle incoming messages. The function will get an event passed on to it. Remember to subscribe to the event.
27
+ * @throws {Error} Throws an error if the method is called in a browser other than Firefox.
28
+ */
29
+ async onMessage(f) {
30
+ if (this.browserName === 'firefox') {
31
+ const client = await this.engineDelegate.getBidi();
32
+ const ws = await client.socket;
33
+ ws.on('message', f);
34
+ } else {
35
+ throw new Error('Bidi only supported in Firefox');
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Retrieves the raw client for Bidi.
41
+ * @async
42
+ * @example const bidi = await commands.bidi.getRawClient();
43
+ * @returns {Promise<Object>} A promise that resolves to the Bidi client.
44
+ * @throws {Error} Throws an error if the browser is not supported.
45
+ */
46
+ async getRawClient() {
47
+ if (this.browserName === 'firefox') {
48
+ return this.engineDelegate.getBidi();
49
+ } else {
50
+ throw new Error('Bidi only supported in Firefox');
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Subscribe to a event.
56
+ * @async
57
+ * @param {string} messageType The type of message to subscribe to.
58
+ * @returns {Promise<Object>} A promise that resolves you have subscribed.
59
+ * @throws {Error} Throws an error if the method is called in a browser other than Firefox.
60
+ */
61
+ async subscribe(messageType) {
62
+ if (this.browserName === 'firefox') {
63
+ const client = await this.engineDelegate.getBidi();
64
+ return client.subscribe(messageType, [
65
+ await this.engineDelegate.getWindowHandle()
66
+ ]);
67
+ } else {
68
+ throw new Error('Bidi only supported in Firefox');
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Unsubscribe to an event.
74
+ * @async
75
+ * @param {string} messageType The type of message to unsubscribe to.
76
+ * @returns {Promise<Object>} A promise that resolves you have unsubscribed.
77
+ * @throws {Error} Throws an error if the method is called in a browser other than Firefox.
78
+ */
79
+ async unsubscribe(messageType) {
80
+ if (this.browserName === 'firefox') {
81
+ const client = await this.engineDelegate.getBidi();
82
+ return client.unsubscribe(messageType, [
83
+ this.engineDelegate.getWindowHandle()
84
+ ]);
85
+ } else {
86
+ throw new Error('Bidi only supported in Firefox');
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Sends a command using Bidi.
92
+ *
93
+ * @async
94
+ * @example await commands.bidi.send({});
95
+ * @param {Object} parameters - The paramaters for the command.
96
+ * @throws {Error} Throws an error if the browser is not supported or if the command fails.
97
+ * @returns {Promise<Object>} A promise that resolves when the command has been sent.
98
+ */
99
+ async send(parameters) {
100
+ if (this.browserName === 'firefox') {
101
+ try {
102
+ const client = await this.engineDelegate.getBidi();
103
+ return client.send(parameters);
104
+ } catch (error) {
105
+ log.error('Could not send to Bidi command %j', parameters);
106
+ log.verbose(error);
107
+ `Could not send to Bidi command ${parameters} `;
108
+ }
109
+ } else {
110
+ throw new Error('Bidi only supported in Firefox');
111
+ }
112
+ }
113
+ }
@@ -13,6 +13,7 @@ import { Meta } from './command/meta.js';
13
13
  import { Watch as StopWatch } from './command/stopWatch.js';
14
14
  import { Select } from './command/select.js';
15
15
  import { Debug } from './command/debug.js';
16
+ import { Bidi } from './command/bidi.js';
16
17
  import { AndroidCommand } from './command/android.js';
17
18
  import { ChromeDevelopmentToolsProtocol } from './command/chromeDevToolsProtocol.js';
18
19
  import { ChromeTrace } from './command/chromeTrace.js';
@@ -200,6 +201,13 @@ export class Commands {
200
201
  */
201
202
  this.cdp = cdp;
202
203
 
204
+ /**
205
+ *
206
+ * Use WebDriver Bidi. Availible in Firefox and in the future more browsers.
207
+ * @type {Bidi}
208
+ */
209
+ this.bidi = new Bidi(engineDelegate, options.browser);
210
+
203
211
  /**
204
212
  * Provides commands for interacting with an Android device.
205
213
  * @type {AndroidCommand}
@@ -20,7 +20,6 @@ export class ExtensionServer {
20
20
  options.block ||
21
21
  options.basicAuth ||
22
22
  options.cookie ||
23
- options.injectJs ||
24
23
  options.clearCacheKeepCookies)
25
24
  ? true
26
25
  : false;
@@ -24,10 +24,6 @@ function generateURL(port, testUrl, options) {
24
24
  query.ba = options.basicAuth + '@' + testUrl;
25
25
  }
26
26
 
27
- if (options.injectJs && options.browser === 'firefox') {
28
- query.js = options.injectJs;
29
- }
30
-
31
27
  if (options.cookie) {
32
28
  const cookies = toArray(options.cookie);
33
29
  query.cookie = [];
@@ -0,0 +1,25 @@
1
+ import intel from 'intel';
2
+ const log = intel.getLogger('browsertime.firefox.bidi');
3
+
4
+ export class FirefoxBidi {
5
+ constructor(bidi, browsingContextId, options) {
6
+ this.options = options;
7
+ this.bidi = bidi;
8
+ this.browsingContextId = browsingContextId;
9
+ }
10
+
11
+ async injectJavaScript(script) {
12
+ const params = {
13
+ method: 'script.addPreloadScript',
14
+ params: {
15
+ functionDeclaration: script
16
+ }
17
+ };
18
+
19
+ try {
20
+ await this.bidi.send(params);
21
+ } catch (error) {
22
+ log.error('Could not inject JavaScript:' + error);
23
+ }
24
+ }
25
+ }
@@ -202,7 +202,7 @@ export async function configureBuilder(builder, baseDir, options) {
202
202
 
203
203
  // Enable bidi for HAR support
204
204
  if (firefoxConfig.bidihar) {
205
- ffOptions.enableBidi();
205
+ /* We do not need to do anything for bidi har */
206
206
  } else {
207
207
  if (!options.skipHar) {
208
208
  if (isAndroidConfigured(options)) {
@@ -13,6 +13,7 @@ import { GeckoProfiler } from '../geckoProfiler.js';
13
13
  import { MemoryReport } from '../memoryReport.js';
14
14
  import { PerfStats } from '../perfStats.js';
15
15
  import { NetworkManager } from '../networkManager.js';
16
+ import { FirefoxBidi } from '../firefoxBidi.js';
16
17
  import { getHAR } from '../getHAR.js';
17
18
 
18
19
  const log = intel.getLogger('browsertime.firefox');
@@ -52,21 +53,43 @@ export class Firefox {
52
53
  * configure what you need.
53
54
  */
54
55
  async afterBrowserStart(runner) {
56
+ this.windowId = await runner.getDriver().getWindowHandle();
57
+
55
58
  if (this.firefoxConfig.bidihar) {
56
- const windowId = await runner.getDriver().getWindowHandle();
57
59
  this.har = new adapters.SeleniumBiDiHarRecorder({
58
- browsingContextIds: [windowId],
60
+ browsingContextIds: [this.windowId],
59
61
  debugLogs:
60
62
  this.options.verbose >= 2 || this.firefoxConfig.enableBidiHarLog,
61
63
  driver: runner.getDriver()
62
64
  });
63
65
  }
66
+
67
+ this.bidi = new FirefoxBidi(
68
+ await runner.getDriver().getBidi(),
69
+ this.windowId,
70
+ this.options
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Get the Bidi client (used by scripting) for browsers that supports it.
76
+ */
77
+ getBidi() {
78
+ return this.bidi;
79
+ }
80
+
81
+ getWindowHandle() {
82
+ return this.windowId;
64
83
  }
65
84
 
66
85
  /**
67
86
  * Before the first iteration of your tests start.
68
87
  */
69
88
  async beforeStartIteration(runner) {
89
+ if (this.options.injectJs) {
90
+ await this.bidi.injectJavaScript(this.options.injectJs);
91
+ }
92
+
70
93
  if (
71
94
  this.firefoxConfig.appendToUserAgent ||
72
95
  this.options.appendToUserAgent
@@ -1095,7 +1095,7 @@ export function parseCommandLine() {
1095
1095
  })
1096
1096
  .option('injectJs', {
1097
1097
  describe:
1098
- 'Inject JavaScript into the current page at document_start. Works for Firefox and Chrome. More info: https://developer.mozilla.org/docs/Mozilla/Add-ons/WebExtensions/API/contentScripts'
1098
+ 'Inject JavaScript into the current page at document_start. Works for Firefox, Chrome and Edge. When injecting to Firefox make sure to wrap the code in a function!'
1099
1099
  })
1100
1100
  .option('block', {
1101
1101
  describe:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "browsertime",
3
3
  "description": "Get performance metrics from your web page using Browsertime.",
4
- "version": "21.4.0",
4
+ "version": "21.5.0",
5
5
  "bin": "./bin/browsertime.js",
6
6
  "type": "module",
7
7
  "types": "./types/scripting.d.ts",
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Manages interactions using Bidi. At the moment this only works for Firefox
3
+ * but Chrome and maybe other browsers will support it in the future.
4
+ * @class
5
+ * @hideconstructor
6
+ * @see https://w3c.github.io/webdriver-bidi/
7
+ */
8
+ export class Bidi {
9
+ constructor(engineDelegate: any, browserName: any);
10
+ /**
11
+ * @private
12
+ */
13
+ private engineDelegate;
14
+ /**
15
+ * @private
16
+ */
17
+ private browserName;
18
+ /**
19
+ * Add a fanction that will get the events that you subscribes.
20
+ * @async
21
+ * @param {Function} f - The callback function to handle incoming messages. The function will get an event passed on to it. Remember to subscribe to the event.
22
+ * @throws {Error} Throws an error if the method is called in a browser other than Firefox.
23
+ */
24
+ onMessage(f: Function): Promise<void>;
25
+ /**
26
+ * Retrieves the raw client for Bidi.
27
+ * @async
28
+ * @example const bidi = await commands.bidi.getRawClient();
29
+ * @returns {Promise<Object>} A promise that resolves to the Bidi client.
30
+ * @throws {Error} Throws an error if the browser is not supported.
31
+ */
32
+ getRawClient(): Promise<any>;
33
+ /**
34
+ * Subscribe to a event.
35
+ * @async
36
+ * @param {string} messageType The type of message to subscribe to.
37
+ * @returns {Promise<Object>} A promise that resolves you have subscribed.
38
+ * @throws {Error} Throws an error if the method is called in a browser other than Firefox.
39
+ */
40
+ subscribe(messageType: string): Promise<any>;
41
+ /**
42
+ * Unsubscribe to an event.
43
+ * @async
44
+ * @param {string} messageType The type of message to unsubscribe to.
45
+ * @returns {Promise<Object>} A promise that resolves you have unsubscribed.
46
+ * @throws {Error} Throws an error if the method is called in a browser other than Firefox.
47
+ */
48
+ unsubscribe(messageType: string): Promise<any>;
49
+ /**
50
+ * Sends a command using Bidi.
51
+ *
52
+ * @async
53
+ * @example await commands.bidi.send({});
54
+ * @param {Object} parameters - The paramaters for the command.
55
+ * @throws {Error} Throws an error if the browser is not supported or if the command fails.
56
+ * @returns {Promise<Object>} A promise that resolves when the command has been sent.
57
+ */
58
+ send(parameters: any): Promise<any>;
59
+ }
60
+ //# sourceMappingURL=bidi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bidi.d.ts","sourceRoot":"","sources":["../../../../lib/core/engine/command/bidi.js"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH;IACE,mDASC;IARC;;OAEG;IACH,uBAAoC;IACpC;;OAEG;IACH,oBAA8B;IAGhC;;;;;OAKG;IACH,sCAQC;IAED;;;;;;OAMG;IACH,gBAHa,YAAe,CAS3B;IAED;;;;;;OAMG;IACH,uBAJW,MAAM,GACJ,YAAe,CAY3B;IAED;;;;;;OAMG;IACH,yBAJW,MAAM,GACH,YAAe,CAY5B;IAED;;;;;;;;OAQG;IACH,uBAFa,YAAe,CAe3B;CACF"}
@@ -104,6 +104,12 @@ export class Commands {
104
104
  * @type {ChromeDevelopmentToolsProtocol}
105
105
  */
106
106
  cdp: ChromeDevelopmentToolsProtocol;
107
+ /**
108
+ *
109
+ * Use WebDriver Bidi. Availible in Firefox and in the future more browsers.
110
+ * @type {Bidi}
111
+ */
112
+ bidi: Bidi;
107
113
  /**
108
114
  * Provides commands for interacting with an Android device.
109
115
  * @type {AndroidCommand}
@@ -153,6 +159,7 @@ import { Cache } from './command/cache.js';
153
159
  import { Meta } from './command/meta.js';
154
160
  import { Screenshot } from './command/screenshot.js';
155
161
  import { ChromeDevelopmentToolsProtocol } from './command/chromeDevToolsProtocol.js';
162
+ import { Bidi } from './command/bidi.js';
156
163
  import { AndroidCommand } from './command/android.js';
157
164
  import { Debug } from './command/debug.js';
158
165
  import { Select } from './command/select.js';
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../lib/core/engine/commands.js"],"names":[],"mappings":"AA6BA;;;GAGG;AACH;IACE,sRAuOC;IApMC,+BAMC;IAMD;;;OAGG;IACH,OAFU,WAAW,CAE+C;IAEpE;;;OAGG;IACH,OAFU,KAAK,CAEmC;IAElD;;;OAGG;IACH,QAFU,MAAM,CAE0B;IAE1C;;;OAGG;IACH,SAFU,OAAO,CAEkB;IAEnC;;;OAGG;IACH,MAFU,IAAI,CAEkC;IAEhD;;;OAGG;IACH,SAFU,OAAO,CAEK;IAEtB;;;;;;;;OAQG;IACH,mBAA+C;IAE/C;;;OAGG;IACH,YAFU,UAAU,CAEwC;IAE5D;;;;;OAKG;IACH,gBAAyC;IAEzC;;;;;OAKG;IACH,wBAAmD;IAEnD;;;OAGG;IACH,IAFU,UAAU,CAEgC;IAEpD;;;OAGG;IACH,QAFU,MAAM,CAMf;IAED;;;OAGG;IACH,KAFU,GAAG,CAEc;IAE3B;;;OAGG;IACH,WAFU,SAAS,CAEoB;IAEvC;;;OAGG;IACH,OAFU,KAAK,CAEuD;IAEtE;;;OAGG;IACH,MAFU,IAAI,CAEQ;IAEtB;;;OAGG;IACH,YAFU,UAAU,CAE+C;IAEnE;;;OAGG;IACH,KAFU,8BAA8B,CAE1B;IAEd;;;OAGG;IACH,SAFU,cAAc,CAEkB;IAE1C;;;;OAIG;IACH,OAFW,KAAK,CAEwB;IAExC;;;OAGG;IACH,WA0BC;IAED;;;OAGG;IACH,QAFU,MAAM,CAEiB;IAEjC;;;;OAIG;IACH,QAHU,OAAO,CAGiB;IAElC;;;OAGG;IACH,SAFU,OAAO,CAEkB;CAEtC;sDA9OqD,4BAA4B;4BAXtD,0BAA0B;sBAfhC,oBAAoB;uBAuBnB,qBAAqB;wBAxBpB,sBAAsB;qBAGzB,mBAAmB;wBAChB,sBAAsB;2BAqBnB,yBAAyB;2BApBzB,yBAAyB;uBAC7B,qBAAqB;oBAExB,kBAAkB;mCAGH,wBAAwB;sBAFrC,oBAAoB;qBACrB,mBAAmB;2BAHb,yBAAyB;+CAQL,qCAAqC;+BADrD,sBAAsB;sBAD/B,oBAAoB;uBADnB,qBAAqB;wBAbpB,sBAAsB;wBAGtB,sBAAsB"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../../lib/core/engine/commands.js"],"names":[],"mappings":"AA8BA;;;GAGG;AACH;IACE,sRA8OC;IA3MC,+BAMC;IAMD;;;OAGG;IACH,OAFU,WAAW,CAE+C;IAEpE;;;OAGG;IACH,OAFU,KAAK,CAEmC;IAElD;;;OAGG;IACH,QAFU,MAAM,CAE0B;IAE1C;;;OAGG;IACH,SAFU,OAAO,CAEkB;IAEnC;;;OAGG;IACH,MAFU,IAAI,CAEkC;IAEhD;;;OAGG;IACH,SAFU,OAAO,CAEK;IAEtB;;;;;;;;OAQG;IACH,mBAA+C;IAE/C;;;OAGG;IACH,YAFU,UAAU,CAEwC;IAE5D;;;;;OAKG;IACH,gBAAyC;IAEzC;;;;;OAKG;IACH,wBAAmD;IAEnD;;;OAGG;IACH,IAFU,UAAU,CAEgC;IAEpD;;;OAGG;IACH,QAFU,MAAM,CAMf;IAED;;;OAGG;IACH,KAFU,GAAG,CAEc;IAE3B;;;OAGG;IACH,WAFU,SAAS,CAEoB;IAEvC;;;OAGG;IACH,OAFU,KAAK,CAEuD;IAEtE;;;OAGG;IACH,MAFU,IAAI,CAEQ;IAEtB;;;OAGG;IACH,YAFU,UAAU,CAE+C;IAEnE;;;OAGG;IACH,KAFU,8BAA8B,CAE1B;IAEd;;;;OAIG;IACH,MAFU,IAAI,CAEuC;IAErD;;;OAGG;IACH,SAFU,cAAc,CAEkB;IAE1C;;;;OAIG;IACH,OAFW,KAAK,CAEwB;IAExC;;;OAGG;IACH,WA0BC;IAED;;;OAGG;IACH,QAFU,MAAM,CAEiB;IAEjC;;;;OAIG;IACH,QAHU,OAAO,CAGiB;IAElC;;;OAGG;IACH,SAFU,OAAO,CAEkB;CAEtC;sDArPqD,4BAA4B;4BAXtD,0BAA0B;sBAhBhC,oBAAoB;uBAwBnB,qBAAqB;wBAzBpB,sBAAsB;qBAGzB,mBAAmB;wBAChB,sBAAsB;2BAsBnB,yBAAyB;2BArBzB,yBAAyB;uBAC7B,qBAAqB;oBAExB,kBAAkB;mCAGH,wBAAwB;sBAFrC,oBAAoB;qBACrB,mBAAmB;2BAHb,yBAAyB;+CASL,qCAAqC;qBAF/D,mBAAmB;+BACT,sBAAsB;sBAF/B,oBAAoB;uBADnB,qBAAqB;wBAbpB,sBAAsB;wBAGtB,sBAAsB"}