Skip to content

Commit 4d22357

Browse files
authored
Expose a totalMarkerDuration function in console (#5507)
2 parents 6169e49 + ddf6ac3 commit 4d22357

File tree

3 files changed

+153
-1
lines changed

3 files changed

+153
-1
lines changed

src/test/unit/__snapshots__/window-console.test.js.snap

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Jest Snapshot v1, https://goo.gl/fbAQLP
1+
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
22

33
exports[`console-accessible values on the window object logs a friendly message 1`] = `
44
Array [
@@ -28,6 +28,7 @@ Array [
2828
%cwindow.filteredMarkers%c - The current filtered and processed markers
2929
%cwindow.selectedMarker%c - The selected processed marker in the current thread
3030
%cwindow.callTree%c - The call tree of the current filtered thread
31+
%cwindow.totalMarkerDuration%c - Calculate total duration of a marker array (e.g., totalMarkerDuration(filteredMarkers))
3132
%cwindow.getState%c - The function that returns the current Redux state.
3233
%cwindow.selectors%c - All the selectors that are used to get data from the Redux state.
3334
%cwindow.dispatch%c - The function to dispatch a Redux action to change the state.
@@ -76,6 +77,8 @@ The CallTree class's source code is available here:
7677
"",
7778
"font-weight: bold;",
7879
"",
80+
"font-weight: bold;",
81+
"",
7982
"font-style: italic; text-decoration: underline;",
8083
"",
8184
"font-style: italic; text-decoration: underline;",

src/test/unit/window-console.test.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,126 @@ describe('console-accessible values on the window object', function () {
7373
1970-01-01 00:00:00.190000000 UTC - [Unknown Process 0: Empty]: D/nsJarProtocol nsJARChannel::nsJARChannel [this=0x87f1ec80]
7474
`);
7575
});
76+
77+
describe('totalMarkerDuration', function () {
78+
function setup() {
79+
jest.spyOn(console, 'log').mockImplementation(() => {});
80+
81+
const store = storeWithSimpleProfile();
82+
const target = {};
83+
addDataToWindowObject(store.getState, store.dispatch, target);
84+
85+
return target;
86+
}
87+
beforeEach(function () {});
88+
89+
it('returns 0 for empty array', function () {
90+
const target = setup();
91+
const result = target.totalMarkerDuration([]);
92+
expect(result).toBe(0);
93+
});
94+
95+
it('returns 0 and logs error for non-array input', function () {
96+
const target = setup();
97+
const consoleErrorSpy = jest
98+
.spyOn(console, 'error')
99+
.mockImplementation(() => {});
100+
const result = target.totalMarkerDuration('not an array');
101+
expect(result).toBe(0);
102+
expect(consoleErrorSpy).toHaveBeenCalledWith(
103+
'totalMarkerDuration expects an array of markers'
104+
);
105+
consoleErrorSpy.mockRestore();
106+
});
107+
108+
it('calculates duration for interval markers', function () {
109+
const target = setup();
110+
const markers = [
111+
{
112+
start: 100,
113+
end: 200,
114+
name: 'marker1',
115+
category: 0,
116+
data: null,
117+
},
118+
{
119+
start: 150,
120+
end: 250,
121+
name: 'marker2',
122+
category: 0,
123+
data: null,
124+
},
125+
];
126+
const result = target.totalMarkerDuration(markers);
127+
expect(result).toBe(200); // (200-100) + (250-150) = 100 + 100 = 200
128+
129+
// Make sure that we print a formatted log for the duration.
130+
expect(console.log).toHaveBeenCalledWith('Total marker duration: 200ms');
131+
});
132+
133+
it('skips instant markers with null end times', function () {
134+
const target = setup();
135+
const markers = [
136+
{
137+
start: 100,
138+
end: 200,
139+
name: 'interval',
140+
category: 0,
141+
threadId: null,
142+
data: null,
143+
},
144+
{
145+
start: 150,
146+
end: null,
147+
name: 'instant',
148+
category: 0,
149+
threadId: null,
150+
data: null,
151+
},
152+
{
153+
start: 300,
154+
end: 400,
155+
name: 'interval2',
156+
category: 0,
157+
threadId: null,
158+
data: null,
159+
},
160+
];
161+
const result = target.totalMarkerDuration(markers);
162+
expect(result).toBe(200); // (200-100) + (400-300) = 100 + 100 = 200
163+
});
164+
165+
it('handles mixed valid and invalid markers', function () {
166+
const target = setup();
167+
const markers = [
168+
{
169+
start: 100,
170+
end: 200,
171+
name: 'valid',
172+
category: 0,
173+
threadId: null,
174+
data: null,
175+
},
176+
null,
177+
{
178+
start: 'invalid',
179+
end: 300,
180+
name: 'invalid',
181+
category: 0,
182+
threadId: null,
183+
data: null,
184+
},
185+
{
186+
start: 400,
187+
end: 500,
188+
name: 'valid2',
189+
category: 0,
190+
threadId: null,
191+
data: null,
192+
},
193+
];
194+
const result = target.totalMarkerDuration(markers);
195+
expect(result).toBe(200); // (200-100) + (500-400) = 100 + 100 = 200
196+
});
197+
});
76198
});

src/utils/window-console.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { selectorsForConsole } from 'firefox-profiler/selectors';
88
import actions from 'firefox-profiler/actions';
99
import { shortenUrl } from 'firefox-profiler/utils/shorten-url';
1010
import { createBrowserConnection } from 'firefox-profiler/app-logic/browser-connection';
11+
import { formatTimestamp } from 'firefox-profiler/utils/format-numbers';
1112

1213
// Despite providing a good libdef for Object.defineProperty, Flow still
1314
// special-cases the `value` property: if it's missing it throws an error. Using
@@ -263,6 +264,28 @@ export function addDataToWindowObject(
263264
return logs.sort().join('\n');
264265
};
265266

267+
target.totalMarkerDuration = function (markers) {
268+
if (!Array.isArray(markers)) {
269+
console.error('totalMarkerDuration expects an array of markers');
270+
return 0;
271+
}
272+
273+
let totalDuration = 0;
274+
for (const marker of markers) {
275+
if (
276+
marker &&
277+
typeof marker.start === 'number' &&
278+
typeof marker.end === 'number'
279+
) {
280+
totalDuration += marker.end - marker.start;
281+
}
282+
// Skip markers with null end times (instant markers have no duration)
283+
}
284+
285+
console.log(`Total marker duration: ${formatTimestamp(totalDuration)}`);
286+
return totalDuration;
287+
};
288+
266289
target.shortenUrl = shortenUrl;
267290
target.getState = getState;
268291
target.selectors = selectorsForConsole;
@@ -315,6 +338,7 @@ export function logFriendlyPreamble() {
315338
%cwindow.filteredMarkers%c - The current filtered and processed markers
316339
%cwindow.selectedMarker%c - The selected processed marker in the current thread
317340
%cwindow.callTree%c - The call tree of the current filtered thread
341+
%cwindow.totalMarkerDuration%c - Calculate total duration of a marker array (e.g., totalMarkerDuration(filteredMarkers))
318342
%cwindow.getState%c - The function that returns the current Redux state.
319343
%cwindow.selectors%c - All the selectors that are used to get data from the Redux state.
320344
%cwindow.dispatch%c - The function to dispatch a Redux action to change the state.
@@ -350,6 +374,9 @@ export function logFriendlyPreamble() {
350374
// "window.callTree"
351375
bold,
352376
reset,
377+
// "window.totalMarkerDuration"
378+
bold,
379+
reset,
353380
// "window.getState"
354381
bold,
355382
reset,

0 commit comments

Comments
 (0)