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.
Files changed (212) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -2
  3. package/bin/browsertime.js +9 -3
  4. package/browserscripts/pageinfo/interactionToNextPaintInfo.js +170 -143
  5. package/browserscripts/timings/interactionToNextPaint.js +49 -137
  6. package/lib/chrome/webdriver/setupChromiumOptions.js +0 -9
  7. package/lib/core/engine/collector.js +11 -0
  8. package/lib/core/engine/command/actions.js +52 -0
  9. package/lib/core/engine/command/addText.js +48 -30
  10. package/lib/core/engine/command/android.js +43 -4
  11. package/lib/core/engine/command/cache.js +39 -2
  12. package/lib/core/engine/command/chromeDevToolsProtocol.js +51 -1
  13. package/lib/core/engine/command/chromeTrace.js +34 -0
  14. package/lib/core/engine/command/click.js +102 -52
  15. package/lib/core/engine/command/debug.js +19 -2
  16. package/lib/core/engine/command/element.js +66 -0
  17. package/lib/core/engine/command/geckoProfiler.js +41 -1
  18. package/lib/core/engine/command/javaScript.js +43 -20
  19. package/lib/core/engine/command/measure.js +147 -15
  20. package/lib/core/engine/command/meta.js +17 -0
  21. package/lib/core/engine/command/mouse/clickAndHold.js +56 -29
  22. package/lib/core/engine/command/mouse/contextClick.js +30 -11
  23. package/lib/core/engine/command/mouse/doubleClick.js +35 -11
  24. package/lib/core/engine/command/mouse/mouseMove.js +38 -16
  25. package/lib/core/engine/command/mouse/singleClick.js +187 -12
  26. package/lib/core/engine/command/navigation.js +31 -3
  27. package/lib/core/engine/command/screenshot.js +33 -0
  28. package/lib/core/engine/command/scroll.js +35 -13
  29. package/lib/core/engine/command/select.js +55 -36
  30. package/lib/core/engine/command/set.js +51 -36
  31. package/lib/core/engine/command/stopWatch.js +30 -9
  32. package/lib/core/engine/command/switch.js +49 -11
  33. package/lib/core/engine/command/wait.js +50 -25
  34. package/lib/core/engine/commands.js +267 -0
  35. package/lib/core/engine/context.js +81 -0
  36. package/lib/core/engine/iteration.js +20 -102
  37. package/lib/firefox/geckoProfiler.js +49 -1
  38. package/lib/firefox/webdriver/builder.js +4 -9
  39. package/lib/firefox/webdriver/firefox.js +1 -1
  40. package/lib/support/cli.js +7 -0
  41. package/lib/support/getViewPort.js +6 -1
  42. package/lib/support/statistics.js +11 -1
  43. package/package.json +22 -12
  44. package/types/android/index.d.ts +70 -0
  45. package/types/android/index.d.ts.map +1 -0
  46. package/types/chrome/parseCpuTrace.d.ts +21 -0
  47. package/types/chrome/parseCpuTrace.d.ts.map +1 -0
  48. package/types/chrome/traceCategoriesParser.d.ts +2 -0
  49. package/types/chrome/traceCategoriesParser.d.ts.map +1 -0
  50. package/types/chrome/webdriver/traceUtilities.d.ts +8 -0
  51. package/types/chrome/webdriver/traceUtilities.d.ts.map +1 -0
  52. package/types/core/engine/command/action.d.ts +73 -0
  53. package/types/core/engine/command/action.d.ts.map +1 -0
  54. package/types/core/engine/command/actions.d.ts +38 -0
  55. package/types/core/engine/command/actions.d.ts.map +1 -0
  56. package/types/core/engine/command/addText.d.ts +68 -0
  57. package/types/core/engine/command/addText.d.ts.map +1 -0
  58. package/types/core/engine/command/android.d.ts +39 -0
  59. package/types/core/engine/command/android.d.ts.map +1 -0
  60. package/types/core/engine/command/cache.d.ts +53 -0
  61. package/types/core/engine/command/cache.d.ts.map +1 -0
  62. package/types/core/engine/command/chromeDevToolsProtocol.d.ts +61 -0
  63. package/types/core/engine/command/chromeDevToolsProtocol.d.ts.map +1 -0
  64. package/types/core/engine/command/chromeTrace.d.ts +45 -0
  65. package/types/core/engine/command/chromeTrace.d.ts.map +1 -0
  66. package/types/core/engine/command/click.d.ts +151 -0
  67. package/types/core/engine/command/click.d.ts.map +1 -0
  68. package/types/core/engine/command/debug.d.ts +28 -0
  69. package/types/core/engine/command/debug.d.ts.map +1 -0
  70. package/types/core/engine/command/element.d.ts +49 -0
  71. package/types/core/engine/command/element.d.ts.map +1 -0
  72. package/types/core/engine/command/geckoProfiler.d.ts +46 -0
  73. package/types/core/engine/command/geckoProfiler.d.ts.map +1 -0
  74. package/types/core/engine/command/javaScript.d.ts +63 -0
  75. package/types/core/engine/command/javaScript.d.ts.map +1 -0
  76. package/types/core/engine/command/measure.d.ts +194 -0
  77. package/types/core/engine/command/measure.d.ts.map +1 -0
  78. package/types/core/engine/command/meta.d.ts +23 -0
  79. package/types/core/engine/command/meta.d.ts.map +1 -0
  80. package/types/core/engine/command/mouse/clickAndHold.d.ts +82 -0
  81. package/types/core/engine/command/mouse/clickAndHold.d.ts.map +1 -0
  82. package/types/core/engine/command/mouse/contextClick.d.ts +44 -0
  83. package/types/core/engine/command/mouse/contextClick.d.ts.map +1 -0
  84. package/types/core/engine/command/mouse/doubleClick.d.ts +51 -0
  85. package/types/core/engine/command/mouse/doubleClick.d.ts.map +1 -0
  86. package/types/core/engine/command/mouse/index.d.ts +6 -0
  87. package/types/core/engine/command/mouse/index.d.ts.map +1 -0
  88. package/types/core/engine/command/mouse/mouseMove.d.ts +56 -0
  89. package/types/core/engine/command/mouse/mouseMove.d.ts.map +1 -0
  90. package/types/core/engine/command/mouse/singleClick.d.ts +115 -0
  91. package/types/core/engine/command/mouse/singleClick.d.ts.map +1 -0
  92. package/types/core/engine/command/navigation.d.ts +45 -0
  93. package/types/core/engine/command/navigation.d.ts.map +1 -0
  94. package/types/core/engine/command/screenshot.d.ts +33 -0
  95. package/types/core/engine/command/screenshot.d.ts.map +1 -0
  96. package/types/core/engine/command/scroll.d.ts +52 -0
  97. package/types/core/engine/command/scroll.d.ts.map +1 -0
  98. package/types/core/engine/command/select.d.ts +81 -0
  99. package/types/core/engine/command/select.d.ts.map +1 -0
  100. package/types/core/engine/command/set.d.ts +74 -0
  101. package/types/core/engine/command/set.d.ts.map +1 -0
  102. package/types/core/engine/command/stopWatch.d.ts +49 -0
  103. package/types/core/engine/command/stopWatch.d.ts.map +1 -0
  104. package/types/core/engine/command/switch.d.ts +77 -0
  105. package/types/core/engine/command/switch.d.ts.map +1 -0
  106. package/types/core/engine/command/util/lcpHighlightScript.d.ts +2 -0
  107. package/types/core/engine/command/util/lcpHighlightScript.d.ts.map +1 -0
  108. package/types/core/engine/command/util/lsHighlightScript.d.ts +2 -0
  109. package/types/core/engine/command/util/lsHighlightScript.d.ts.map +1 -0
  110. package/types/core/engine/command/wait.d.ts +74 -0
  111. package/types/core/engine/command/wait.d.ts.map +1 -0
  112. package/types/core/engine/commands.d.ts +161 -0
  113. package/types/core/engine/commands.d.ts.map +1 -0
  114. package/types/core/engine/context.d.ts +87 -0
  115. package/types/core/engine/context.d.ts.map +1 -0
  116. package/types/firefox/geckoProfiler.d.ts +11 -0
  117. package/types/firefox/geckoProfiler.d.ts.map +1 -0
  118. package/types/firefox/settings/geckoProfilerDefaults.d.ts +8 -0
  119. package/types/firefox/settings/geckoProfilerDefaults.d.ts.map +1 -0
  120. package/types/scripting.d.ts +2 -0
  121. package/types/support/engineUtils.d.ts +5 -0
  122. package/types/support/engineUtils.d.ts.map +1 -0
  123. package/types/support/errors.d.ts +15 -0
  124. package/types/support/errors.d.ts.map +1 -0
  125. package/types/support/fileUtil.d.ts +10 -0
  126. package/types/support/fileUtil.d.ts.map +1 -0
  127. package/types/support/filters.d.ts +7 -0
  128. package/types/support/filters.d.ts.map +1 -0
  129. package/types/support/getViewPort.d.ts +2 -0
  130. package/types/support/getViewPort.d.ts.map +1 -0
  131. package/types/support/pathToFolder.d.ts +2 -0
  132. package/types/support/pathToFolder.d.ts.map +1 -0
  133. package/types/support/storageManager.d.ts +17 -0
  134. package/types/support/storageManager.d.ts.map +1 -0
  135. package/types/support/tcpdump.d.ts +10 -0
  136. package/types/support/tcpdump.d.ts.map +1 -0
  137. package/types/support/userTiming.d.ts +2 -0
  138. package/types/support/userTiming.d.ts.map +1 -0
  139. package/types/support/util.d.ts +6 -0
  140. package/types/support/util.d.ts.map +1 -0
  141. package/types/video/defaults.d.ts +7 -0
  142. package/types/video/defaults.d.ts.map +1 -0
  143. package/types/video/postprocessing/finetune/addTextToVideo.d.ts +2 -0
  144. package/types/video/postprocessing/finetune/addTextToVideo.d.ts.map +1 -0
  145. package/types/video/postprocessing/finetune/convertFps.d.ts +2 -0
  146. package/types/video/postprocessing/finetune/convertFps.d.ts.map +1 -0
  147. package/types/video/postprocessing/finetune/getFont.d.ts +2 -0
  148. package/types/video/postprocessing/finetune/getFont.d.ts.map +1 -0
  149. package/types/video/postprocessing/finetune/getTimingMetrics.d.ts +2 -0
  150. package/types/video/postprocessing/finetune/getTimingMetrics.d.ts.map +1 -0
  151. package/types/video/postprocessing/finetune/index.d.ts +2 -0
  152. package/types/video/postprocessing/finetune/index.d.ts.map +1 -0
  153. package/types/video/postprocessing/finetune/removeOrange.d.ts +2 -0
  154. package/types/video/postprocessing/finetune/removeOrange.d.ts.map +1 -0
  155. package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts +5 -0
  156. package/types/video/postprocessing/visualmetrics/extraMetrics.d.ts.map +1 -0
  157. package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts +5 -0
  158. package/types/video/postprocessing/visualmetrics/getVideoMetrics.d.ts.map +1 -0
  159. package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts +3 -0
  160. package/types/video/postprocessing/visualmetrics/visualMetrics.d.ts.map +1 -0
  161. package/types/video/screenRecording/android/recorder.d.ts +11 -0
  162. package/types/video/screenRecording/android/recorder.d.ts.map +1 -0
  163. package/types/video/screenRecording/desktop/convert.d.ts +2 -0
  164. package/types/video/screenRecording/desktop/convert.d.ts.map +1 -0
  165. package/types/video/screenRecording/desktop/desktopRecorder.d.ts +28 -0
  166. package/types/video/screenRecording/desktop/desktopRecorder.d.ts.map +1 -0
  167. package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts +17 -0
  168. package/types/video/screenRecording/desktop/ffmpegRecorder.d.ts.map +1 -0
  169. package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts +2 -0
  170. package/types/video/screenRecording/desktop/osx/getSPDisplaysDataType.d.ts.map +1 -0
  171. package/types/video/screenRecording/desktop/osx/getScreen.d.ts +2 -0
  172. package/types/video/screenRecording/desktop/osx/getScreen.d.ts.map +1 -0
  173. package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts +13 -0
  174. package/types/video/screenRecording/firefox/firefoxWindowRecorder.d.ts.map +1 -0
  175. package/types/video/screenRecording/ios/convertToMp4.d.ts +2 -0
  176. package/types/video/screenRecording/ios/convertToMp4.d.ts.map +1 -0
  177. package/types/video/screenRecording/ios/iosRecorder.d.ts +14 -0
  178. package/types/video/screenRecording/ios/iosRecorder.d.ts.map +1 -0
  179. package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts +2 -0
  180. package/types/video/screenRecording/iosSimulator/convertToMp4.d.ts.map +1 -0
  181. package/types/video/screenRecording/iosSimulator/recorder.d.ts +9 -0
  182. package/types/video/screenRecording/iosSimulator/recorder.d.ts.map +1 -0
  183. package/types/video/screenRecording/recorder.d.ts +7 -0
  184. package/types/video/screenRecording/recorder.d.ts.map +1 -0
  185. package/types/video/screenRecording/setOrangeBackground.d.ts +2 -0
  186. package/types/video/screenRecording/setOrangeBackground.d.ts.map +1 -0
  187. package/types/video/video.d.ts +41 -0
  188. package/types/video/video.d.ts.map +1 -0
  189. package/browsersupport/firefox-profile/cert9.db +0 -0
  190. package/browsersupport/firefox-profile/chrome/userChrome.css +0 -4
  191. package/browsersupport/firefox-profile/key4.db +0 -0
  192. package/vendor/mac/x86/qvh +0 -0
  193. package/visualmetrics/__init__.py +0 -1
  194. package/visualmetrics/test_data/ms_000000.png +0 -0
  195. package/visualmetrics/test_data/ms_000920.png +0 -0
  196. package/visualmetrics/test_data/ms_001000.png +0 -0
  197. package/visualmetrics/test_data/ms_001080.png +0 -0
  198. package/visualmetrics/test_data/ms_001200.png +0 -0
  199. package/visualmetrics/test_data/ms_001240.png +0 -0
  200. package/visualmetrics/test_data/ms_001280.png +0 -0
  201. package/visualmetrics/test_data/ms_001360.png +0 -0
  202. package/visualmetrics/test_data/ms_001400.png +0 -0
  203. package/visualmetrics/test_data/ms_001520.png +0 -0
  204. package/visualmetrics/test_data/ms_002040.png +0 -0
  205. package/visualmetrics/test_data/ms_002600.png +0 -0
  206. package/visualmetrics/test_data/ms_003160.png +0 -0
  207. package/visualmetrics/test_data/ms_003720.png +0 -0
  208. package/visualmetrics/test_data/ms_004280.png +0 -0
  209. package/visualmetrics/test_data/ms_004880.png +0 -0
  210. package/visualmetrics/test_data/ms_005440.png +0 -0
  211. package/visualmetrics/test_data/ms_006000.png +0 -0
  212. package/visualmetrics/test_visualmetrics.py +0 -34
@@ -0,0 +1,267 @@
1
+ import { Actions } from './command/actions.js';
2
+ import { AddText } from './command/addText.js';
3
+ import { Click } from './command/click.js';
4
+ import { Element } from './command/element.js';
5
+ import { Wait } from './command/wait.js';
6
+ import { Measure } from './command/measure.js';
7
+ import { JavaScript } from './command/javaScript.js';
8
+ import { Switch } from './command/switch.js';
9
+ import { Screenshot } from './command/screenshot.js';
10
+ import { Set } from './command/set.js';
11
+ import { Cache } from './command/cache.js';
12
+ import { Meta } from './command/meta.js';
13
+ import { Watch as StopWatch } from './command/stopWatch.js';
14
+ import { Select } from './command/select.js';
15
+ import { Debug } from './command/debug.js';
16
+ import { AndroidCommand } from './command/android.js';
17
+ import { ChromeDevelopmentToolsProtocol } from './command/chromeDevToolsProtocol.js';
18
+ import { ChromeTrace } from './command/chromeTrace.js';
19
+ import {
20
+ SingleClick,
21
+ DoubleClick,
22
+ ClickAndHold,
23
+ ContextClick,
24
+ MouseMove
25
+ } from './command/mouse/index.js';
26
+ import { Scroll } from './command/scroll.js';
27
+ import { Navigation } from './command/navigation.js';
28
+ import { GeckoProfiler } from '../../firefox/geckoProfiler.js';
29
+ import { GeckoProfiler as GeckoProfilerCommand } from './command/geckoProfiler.js';
30
+ /**
31
+ * Represents the set of commands available in a Browsertime script.
32
+ * @hideconstructor
33
+ */
34
+ export class Commands {
35
+ constructor(
36
+ browser,
37
+ engineDelegate,
38
+ index,
39
+ result,
40
+ storageManager,
41
+ pageCompleteCheck,
42
+ extensionServer,
43
+ context,
44
+ videos,
45
+ screenshotManager,
46
+ scriptsByCategory,
47
+ asyncScriptsByCategory,
48
+ postURLScripts,
49
+ options
50
+ ) {
51
+ const measure = new Measure(
52
+ browser,
53
+ index,
54
+ pageCompleteCheck,
55
+ result,
56
+ engineDelegate,
57
+ extensionServer,
58
+ storageManager,
59
+ videos,
60
+ scriptsByCategory,
61
+ asyncScriptsByCategory,
62
+ postURLScripts,
63
+ context,
64
+ screenshotManager,
65
+ options
66
+ );
67
+
68
+ const browserProfiler = new GeckoProfiler(browser, storageManager, options);
69
+ // Profiler
70
+ this.profiler = new GeckoProfilerCommand(
71
+ browserProfiler,
72
+ browser,
73
+ index,
74
+ options,
75
+ result
76
+ );
77
+ const cdp = new ChromeDevelopmentToolsProtocol(
78
+ engineDelegate,
79
+ options.browser
80
+ );
81
+
82
+ /**
83
+ * Manages Chrome trace functionality, enabling custom profiling and trace collection in Chrome.
84
+ * @type {ChromeTrace}
85
+ */
86
+ this.trace = new ChromeTrace(engineDelegate, index, options, result);
87
+
88
+ /**
89
+ * Provides functionality to perform click actions on elements in a web page using various selectors.
90
+ * @type {Click}
91
+ */
92
+ this.click = new Click(browser, pageCompleteCheck);
93
+
94
+ /**
95
+ * Provides functionality to control page scrolling in the browser.
96
+ * @type {Scroll}
97
+ */
98
+ this.scroll = new Scroll(browser, options);
99
+
100
+ /**
101
+ * Provides functionality to add text to elements on a web page using various selectors.
102
+ * @type {AddText}
103
+ */
104
+ this.addText = new AddText(browser);
105
+
106
+ /**
107
+ * Provides functionality to wait for different conditions in the browser.
108
+ * @type {Wait}
109
+ */
110
+ this.wait = new Wait(browser, pageCompleteCheck);
111
+
112
+ /**
113
+ * Provides functionality for measuring a navigation.
114
+ * @type {Measure}
115
+ */
116
+ this.measure = measure;
117
+
118
+ /**
119
+ * Navigates to a specified URL and handles additional setup for a page visit.
120
+ * @async
121
+ * @example await commands.navigate('https://www.example.org');
122
+ * @type {Function}
123
+ * @param {string} url - The URL to navigate to.
124
+ * @throws {Error} Throws an error if navigation or setup fails.
125
+ * @returns {Promise<void>} A promise that resolves when the navigation and setup are
126
+ */
127
+ this.navigate = measure._navigate.bind(measure);
128
+
129
+ /**
130
+ * Provides functionality to control browser navigation such as back, forward, and refresh actions.
131
+ * @type {Navigation}
132
+ */
133
+ this.navigation = new Navigation(browser, pageCompleteCheck);
134
+
135
+ /**
136
+ * Add a text that will be an error attached to the current page.
137
+ * @example await commands.error('My error message');
138
+ * @param {string} message - The error message.
139
+ * @type {Function}
140
+ */
141
+ this.error = measure._error.bind(measure);
142
+
143
+ /**
144
+ * Mark this run as an failure. Add a message that explains the failure.
145
+ * @example await commands.markAsFailure('My failure message');
146
+ * @param {string} message - The message attached as a failure
147
+ * @type {Function}
148
+ */
149
+ this.markAsFailure = measure._failure.bind(measure);
150
+
151
+ /**
152
+ * Executes JavaScript in the browser context.
153
+ * @type {JavaScript}
154
+ */
155
+ this.js = new JavaScript(browser, pageCompleteCheck);
156
+
157
+ /**
158
+ * Switches context to different frames, windows, or tabs in the browser.
159
+ * @type {Switch}
160
+ */
161
+ this.switch = new Switch(
162
+ browser,
163
+ pageCompleteCheck,
164
+ measure._navigate.bind(measure)
165
+ );
166
+
167
+ /**
168
+ * Sets values on HTML elements in the page.
169
+ * @type {Set}
170
+ */
171
+ this.set = new Set(browser);
172
+
173
+ /**
174
+ * Stopwatch utility for measuring time intervals.
175
+ * @type {StopWatch}
176
+ */
177
+ this.stopWatch = new StopWatch(measure);
178
+
179
+ /**
180
+ * Manages the browser's cache.
181
+ * @type {Cache}
182
+ */
183
+ this.cache = new Cache(browser, options.browser, extensionServer, cdp);
184
+
185
+ /**
186
+ * Adds metadata to the user journey.
187
+ * @type {Meta}
188
+ */
189
+ this.meta = new Meta();
190
+
191
+ /**
192
+ * Takes and manages screenshots.
193
+ * @type {Screenshot}
194
+ */
195
+ this.screenshot = new Screenshot(screenshotManager, browser, index);
196
+
197
+ /**
198
+ * Use the Chrome DevTools Protocol, available in Chrome and Edge.
199
+ * @type {ChromeDevelopmentToolsProtocol}
200
+ */
201
+ this.cdp = cdp;
202
+
203
+ /**
204
+ * Provides commands for interacting with an Android device.
205
+ * @type {AndroidCommand}
206
+ */
207
+ this.android = new AndroidCommand(options);
208
+
209
+ /**
210
+ * Provides debugging capabilities within a browser automation script.
211
+ * It allows setting breakpoints to pause script execution and inspect the current state.
212
+ * @type {Debug}
213
+ */
214
+ this.debug = new Debug(browser, options);
215
+
216
+ /**
217
+ * Interact with the page using the mouse.
218
+ * @type {Object}
219
+ */
220
+ this.mouse = {
221
+ /**
222
+ * Move the mouse cursor to elements or specific positions on a web page.
223
+ * @type {MouseMove}
224
+ */
225
+ moveTo: new MouseMove(browser),
226
+ /**
227
+ * Perform a context click (right-click) on elements in a web page.
228
+ * @type {ContextClick}
229
+ */
230
+ contextClick: new ContextClick(browser),
231
+ /**
232
+ * Provides functionality to perform a single click action on elements or at specific positions in a web page.
233
+ * @type {SingleClick}
234
+ */
235
+ singleClick: new SingleClick(browser, pageCompleteCheck),
236
+ /**
237
+ * Provides functionality to perform a double-click action on elements in a web page.
238
+ * @type {DoubleClick}
239
+ */
240
+ doubleClick: new DoubleClick(browser, pageCompleteCheck),
241
+ /**
242
+ * Provides functionality to click and hold elements on a web page using different strategies.
243
+ * @type {ClickAndHold}
244
+ */
245
+ clickAndHold: new ClickAndHold(browser)
246
+ };
247
+
248
+ /**
249
+ * Interact with a select element.
250
+ * @type {Select}
251
+ */
252
+ this.select = new Select(browser);
253
+
254
+ /**
255
+ * Selenium's action sequence functionality.
256
+ * @type {Actions}
257
+ * @see https://www.selenium.dev/documentation/webdriver/actions_api/
258
+ */
259
+ this.action = new Actions(browser);
260
+
261
+ /**
262
+ * Get Selenium's WebElements.
263
+ * @type {Element}
264
+ */
265
+ this.element = new Element(browser);
266
+ }
267
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @typedef {Object} Logger
3
+ * @property {function(string): void} trace - Function to log trace messages.
4
+ * @property {function(string): void} verbose - Function to log verbose messages.
5
+ * @property {function(string): void} info - Function to log info messages.
6
+ * @property {function(string): void} warn - Function to log warning messages.
7
+ * @property {function(string): void} error - Function to log error messages.
8
+ * @property {function(string): void} critical - Function to log critical messages.
9
+ */
10
+
11
+ /**
12
+ * @typedef {typeof import('selenium-webdriver')} WebDriverClass
13
+ * @typedef {import('selenium-webdriver').WebDriver} WebDriverInstance
14
+ */
15
+
16
+ /**
17
+ * Class representing the context of a Browsertime run.
18
+ * @hideconstructor
19
+ * @class
20
+ */
21
+ export class Context {
22
+ constructor(
23
+ options,
24
+ result,
25
+ log,
26
+ storageManager,
27
+ index,
28
+ webdriver,
29
+ instantiatedDriver
30
+ ) {
31
+ /**
32
+ * This is the yargs object you get from the cli. If you add --my.id you can get that using options.my.id.
33
+ * @type {Object}
34
+ */
35
+ this.options = options;
36
+
37
+ /**
38
+ * Here the result from each run is stored.
39
+ * @type {Object}
40
+ */
41
+ this.result = result;
42
+
43
+ /**
44
+ * @type {Logger}
45
+ */
46
+ this.log = log;
47
+
48
+ /**
49
+ * The index of the iteration.
50
+ * @type {number}
51
+ */
52
+ this.index = index;
53
+
54
+ /**
55
+ * Storage manager to save things to disk.
56
+ * @type {import('../../support/storageManager.js').StorageManager}
57
+ */
58
+ this.storageManager = storageManager;
59
+
60
+ /**
61
+ * @type {Object}
62
+ */
63
+ this.taskData = {};
64
+
65
+ /**
66
+ * Get raw Selenium functionality.
67
+ * @see https://www.selenium.dev/selenium/docs/api/javascript/module/selenium-webdriver/index.html
68
+ * @type {{webdriver: WebDriverClass, driver: WebDriverInstance}}
69
+ */
70
+ this.selenium = {
71
+ /**
72
+ * @typedef {typeof import('selenium-webdriver')} WebDriverClass
73
+ */
74
+ webdriver,
75
+ /**
76
+ * @typedef {import('selenium-webdriver').WebDriver} WebDriverInstance
77
+ */
78
+ driver: instantiatedDriver
79
+ };
80
+ }
81
+ }
@@ -2,6 +2,8 @@ import { platform } from 'node:os';
2
2
  import webdriver from 'selenium-webdriver';
3
3
  import intel from 'intel';
4
4
 
5
+ import { Context } from './context.js';
6
+ import { Commands } from './commands.js';
5
7
  import { SeleniumRunner } from '../seleniumRunner.js';
6
8
  import { preURL } from '../../support/preURL.js';
7
9
  import { setResourceTimingBufferSize } from '../../support/setResourceTimingBufferSize.js';
@@ -9,41 +11,16 @@ import { ScreenshotManager } from '../../screenshot/index.js';
9
11
  import { ExtensionServer } from '../../extensionserver/index.js';
10
12
  import { Video } from '../../video/video.js';
11
13
  import { stop } from '../../support/stop.js';
12
- import { AddText } from './command/addText.js';
13
- import { Click } from './command/click.js';
14
- import { Wait } from './command/wait.js';
15
- import { Measure } from './command/measure.js';
16
- import { JavaScript } from './command/javaScript.js';
17
- import { Switch } from './command/switch.js';
18
- import { Screenshot } from './command/screenshot.js';
19
- import { Set } from './command/set.js';
20
- import { Cache } from './command/cache.js';
21
- import { Meta } from './command/meta.js';
22
- import { Watch as StopWatch } from './command/stopWatch.js';
23
- import { Select } from './command/select.js';
24
- import { Debug } from './command/debug.js';
25
- import { AndroidCommand } from './command/android.js';
26
- import { ChromeDevelopmentToolsProtocol } from './command/chromeDevToolsProtocol.js';
27
- import { ChromeTrace } from './command/chromeTrace.js';
14
+
28
15
  import {
29
16
  addConnectivity,
30
17
  removeConnectivity
31
18
  } from '../../connectivity/index.js';
32
19
  import { jsonifyVisualProgress } from '../../support/util.js';
33
20
  import { flushDNS } from '../../support/dns.js';
34
- import {
35
- SingleClick,
36
- DoubleClick,
37
- ClickAndHold,
38
- ContextClick,
39
- MouseMove
40
- } from './command/mouse/index.js';
21
+
41
22
  import { getNumberOfRunningProcesses } from '../../support/processes.js';
42
23
  import { isAndroidConfigured, Android } from '../../android/index.js';
43
- import { Scroll } from './command/scroll.js';
44
- import { Navigation } from './command/navigation.js';
45
- import { GeckoProfiler } from '../../firefox/geckoProfiler.js';
46
- import { GeckoProfiler as GeckoProfilerCommand } from './command/geckoProfiler.js';
47
24
  const log = intel.getLogger('browsertime');
48
25
  const delay = ms => new Promise(res => setTimeout(res, ms));
49
26
 
@@ -118,93 +95,33 @@ export class Iteration {
118
95
  await engineDelegate.afterBrowserStart(browser);
119
96
 
120
97
  // The data we push to all selenium scripts
121
- const context = {
122
- // TODO we want to have the URL here so we can use scripts to login
123
- // and then access the supplied URL
98
+ const context = new Context(
124
99
  options,
125
100
  result,
126
101
  log,
127
- storageManager: this.storageManager,
128
- taskData: {},
102
+ this.storageManager,
129
103
  index,
130
- selenium: {
131
- webdriver, // The Selenium WebDriver public API object https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index.html
132
- driver: browser.getDriver() // The instantiated version of the WebDriver https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html
133
- }
134
- };
104
+ webdriver,
105
+ browser.getDriver()
106
+ );
135
107
 
136
- const measure = new Measure(
108
+ const commands = new Commands(
137
109
  browser,
110
+ engineDelegate,
138
111
  index,
139
- this.pageCompleteCheck,
140
112
  result,
141
- engineDelegate,
142
- extensionServer,
143
113
  this.storageManager,
114
+ this.pageCompleteCheck,
115
+ extensionServer,
116
+ context,
144
117
  videos,
118
+ screenshotManager,
145
119
  this.scriptsByCategory,
146
120
  this.asyncScriptsByCategory,
147
121
  this.postURLScripts,
148
- context,
149
- screenshotManager,
150
122
  options
151
123
  );
152
124
 
153
- const browserProfiler = new GeckoProfiler(
154
- browser,
155
- this.storageManager,
156
- this.options
157
- );
158
- const profiler = new GeckoProfilerCommand(
159
- browserProfiler,
160
- browser,
161
- index,
162
- this.options,
163
- result
164
- );
165
- const cdp = new ChromeDevelopmentToolsProtocol(
166
- engineDelegate,
167
- options.browser
168
- );
169
- const trace = new ChromeTrace(engineDelegate, index, options, result);
170
- const android = new Android(options);
171
- const debug = new Debug(browser, options);
172
- const commands = {
173
- profiler: profiler,
174
- trace: trace,
175
- click: new Click(browser, this.pageCompleteCheck),
176
- scroll: new Scroll(browser, options),
177
- addText: new AddText(browser),
178
- wait: new Wait(browser, this.pageCompleteCheck),
179
- measure: measure,
180
- navigate: measure._navigate.bind(measure),
181
- navigation: new Navigation(browser, this.pageCompleteCheck),
182
- error: measure._error.bind(measure),
183
- markAsFailure: measure._failure.bind(measure),
184
- js: new JavaScript(browser, this.pageCompleteCheck),
185
- switch: new Switch(
186
- browser,
187
- this.pageCompleteCheck,
188
- measure._navigate.bind(measure)
189
- ),
190
- set: new Set(browser),
191
- stopWatch: new StopWatch(measure),
192
- cache: new Cache(browser, options.browser, extensionServer, cdp),
193
- meta: new Meta(),
194
- screenshot: new Screenshot(screenshotManager, browser, index),
195
- cdp,
196
- android: new AndroidCommand(options),
197
- debug: debug,
198
- mouse: {
199
- moveTo: new MouseMove(browser),
200
- contextClick: new ContextClick(browser),
201
- singleClick: new SingleClick(browser, this.pageCompleteCheck),
202
- doubleClick: new DoubleClick(browser, this.pageCompleteCheck),
203
- clickAndHold: new ClickAndHold(browser)
204
- },
205
- select: new Select(browser)
206
- };
207
-
208
125
  // Safari can't load data:text URLs at startup, so you can either choose
209
126
  // your own URL or use the blank one
210
127
  const startURL =
@@ -223,7 +140,8 @@ export class Iteration {
223
140
  // browser to get ready
224
141
  if (isAndroidConfigured(options)) {
225
142
  await delay(ANDROID_DELAY_TIME);
226
- batteryTemperature.start = await android.getTemperature();
143
+ this.android = new Android(options);
144
+ batteryTemperature.start = await this.android.getTemperature();
227
145
  }
228
146
 
229
147
  await delay(options.timeToSettle || 100);
@@ -270,7 +188,7 @@ export class Iteration {
270
188
 
271
189
  // if we are in debig mode we wait on a continue command
272
190
  if (options.debug) {
273
- await debug.breakpoint('End-of-iteration');
191
+ await commands.debug.breakpoint('End-of-iteration');
274
192
  }
275
193
 
276
194
  if (options.browser === 'firefox' && options.debug) {
@@ -293,8 +211,8 @@ export class Iteration {
293
211
  await engineDelegate.afterBrowserStopped();
294
212
 
295
213
  if (isAndroidConfigured(options)) {
296
- batteryTemperature.stop = await android.getTemperature();
297
- await android.removeDevtoolsFw();
214
+ batteryTemperature.stop = await this.android.getTemperature();
215
+ await this.android.removeDevtoolsFw();
298
216
  }
299
217
 
300
218
  if (options.visualMetrics && !options.videoParams.debug) {
@@ -8,6 +8,26 @@ import { BrowserError } from '../support/errors.js';
8
8
  const delay = ms => new Promise(res => setTimeout(res, ms));
9
9
  const log = intel.getLogger('browsertime.firefox');
10
10
 
11
+ // Return power usage in Wh
12
+ function computePowerSum(counter) {
13
+ let sum = 0;
14
+ // Older Firefoxes see https://github.com/sitespeedio/sitespeed.io/issues/3944#issuecomment-1871090793
15
+ if (counter.sample_groups) {
16
+ for (const groups of counter.sample_groups) {
17
+ const countIndex = groups.samples.schema.count;
18
+ for (const sample of groups.samples.data) {
19
+ sum += sample[countIndex];
20
+ }
21
+ }
22
+ } else {
23
+ const countIndex = counter.samples.schema.count;
24
+ for (const sample of counter.samples.data) {
25
+ sum += sample[countIndex];
26
+ }
27
+ }
28
+ return sum * 1e-12;
29
+ }
30
+
11
31
  /**
12
32
  * Timeout a promise after ms. Use promise.race to compete
13
33
  * about the timeout and the promise.
@@ -130,7 +150,7 @@ export class GeckoProfiler {
130
150
  return delay(firefoxConfig.geckoProfilerSettleTime || 3000);
131
151
  }
132
152
 
133
- async stop(index, url) {
153
+ async stop(index, url, result) {
134
154
  const runner = this.runner;
135
155
  const storageManager = this.storageManager;
136
156
  const options = this.options;
@@ -183,6 +203,34 @@ export class GeckoProfiler {
183
203
  await android._downloadFile(deviceProfileFilename, destinationFilename);
184
204
  }
185
205
 
206
+ if (this.firefoxConfig.powerConsumption === true) {
207
+ const chosenFeatures = get(
208
+ this.firefoxConfig,
209
+ 'geckoProfilerParams.features',
210
+ geckoProfilerDefaults.features
211
+ );
212
+ if (chosenFeatures.includes('power')) {
213
+ log.info('Collecting CPU power consumtion');
214
+ const profile = JSON.parse(
215
+ await storageManager.readData(
216
+ `geckoProfile-${index}.json`,
217
+ join(pathToFolder(url, options))
218
+ )
219
+ );
220
+ let power = 0;
221
+ for (const counter of profile.counters) {
222
+ if (counter.category === 'power') {
223
+ power += computePowerSum(counter);
224
+ }
225
+ }
226
+ result.powerConsumption = Number(power);
227
+ } else {
228
+ log.warning(
229
+ 'Missing power setting in geckoProfilerParams.features so power will not be collected'
230
+ );
231
+ }
232
+ }
233
+
186
234
  // GZIP the profile and remove the old file
187
235
  log.info('Gzip file the profile.');
188
236
  const name = this.options.enableProfileRun
@@ -55,15 +55,10 @@ export async function configureBuilder(builder, baseDir, options) {
55
55
 
56
56
  const ffOptions = new Options();
57
57
 
58
- const profileTemplatePath = resolve(
59
- moduleRootPath,
60
- 'browsersupport',
61
- 'firefox-profile'
62
- );
63
-
64
- ffOptions.setProfile(
65
- get(firefoxConfig, 'profileTemplate') || profileTemplatePath
66
- );
58
+ const profileTemplate = get(firefoxConfig, 'profileTemplate');
59
+ if (profileTemplate) {
60
+ ffOptions.setProfile(get(firefoxConfig, 'profileTemplate'));
61
+ }
67
62
 
68
63
  if (options.userAgent) {
69
64
  ffOptions.setPreference('general.useragent.override', options.userAgent);
@@ -140,7 +140,7 @@ export class Firefox {
140
140
  this.firefoxConfig.geckoProfiler &&
141
141
  this.firefoxConfig.geckoProfilerRecordingType !== 'custom'
142
142
  ) {
143
- await this.geckoProfiler.stop(index, url);
143
+ await this.geckoProfiler.stop(index, url, result);
144
144
  }
145
145
 
146
146
  if (this.firefoxConfig.perfStats) {
@@ -537,6 +537,13 @@ export function parseCommandLine() {
537
537
  'need to specify the logs you wish to gather.',
538
538
  group: 'firefox'
539
539
  })
540
+ .option('firefox.powerConsumption', {
541
+ type: 'boolean',
542
+ default: false,
543
+ describe:
544
+ 'Enable power consumption collection (in Wh). To get the consumption you also need to set firefox.geckoProfilerParams.features to include power.',
545
+ group: 'firefox'
546
+ })
540
547
  .option('firefox.setMozLog', {
541
548
  describe:
542
549
  'Use in conjunction with firefox.collectMozLog to set MOZ_LOG to something ' +
@@ -21,12 +21,17 @@ const sizeMap = {
21
21
  'Pixel 2': '412x732',
22
22
  'Pixel 2 XL': '412x824',
23
23
  iPad: '768x1024',
24
+ 'iPad Mini': '768x1024',
25
+ 'iPad Air': '820x1180',
24
26
  'iPad Pro': '1024x1366',
25
27
  'iPhone XR': '414x896',
26
28
  'iPhone SE': '377x668',
27
29
  'iPhone 12 Pro': '390x844',
30
+ 'iPhone 14 Pro': '430x932',
28
31
  'Pixel 5': '394x852',
29
- 'Samsung Galaxy S8+': '412x846'
32
+ 'Pixel 7': '412x916',
33
+ 'Samsung Galaxy S8+': '412x846',
34
+ 'Samsung Galaxy A51/71': '412x914'
30
35
  };
31
36
 
32
37
  export function getViewPort(options) {