Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/test/unit/__snapshots__/window-console.test.js.snap
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing

exports[`console-accessible values on the window object logs a friendly message 1`] = `
Array [
Expand Down Expand Up @@ -28,6 +28,7 @@ Array [
%cwindow.filteredMarkers%c - The current filtered and processed markers
%cwindow.selectedMarker%c - The selected processed marker in the current thread
%cwindow.callTree%c - The call tree of the current filtered thread
%cwindow.totalMarkerDuration%c - Calculate total duration of a marker array (e.g., totalMarkerDuration(filteredMarkers))
%cwindow.getState%c - The function that returns the current Redux state.
%cwindow.selectors%c - All the selectors that are used to get data from the Redux state.
%cwindow.dispatch%c - The function to dispatch a Redux action to change the state.
Expand Down Expand Up @@ -76,6 +77,8 @@ The CallTree class's source code is available here:
"",
"font-weight: bold;",
"",
"font-weight: bold;",
"",
"font-style: italic; text-decoration: underline;",
"",
"font-style: italic; text-decoration: underline;",
Expand Down
122 changes: 122 additions & 0 deletions src/test/unit/window-console.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,126 @@ describe('console-accessible values on the window object', function () {
1970-01-01 00:00:00.190000000 UTC - [Unknown Process 0: Empty]: D/nsJarProtocol nsJARChannel::nsJARChannel [this=0x87f1ec80]
`);
});

describe('totalMarkerDuration', function () {
function setup() {
jest.spyOn(console, 'log').mockImplementation(() => {});

const store = storeWithSimpleProfile();
const target = {};
addDataToWindowObject(store.getState, store.dispatch, target);

return target;
}
beforeEach(function () {});

it('returns 0 for empty array', function () {
const target = setup();
const result = target.totalMarkerDuration([]);
expect(result).toBe(0);
});

it('returns 0 and logs error for non-array input', function () {
const target = setup();
const consoleErrorSpy = jest
.spyOn(console, 'error')
.mockImplementation(() => {});
const result = target.totalMarkerDuration('not an array');
expect(result).toBe(0);
expect(consoleErrorSpy).toHaveBeenCalledWith(
'totalMarkerDuration expects an array of markers'
);
consoleErrorSpy.mockRestore();
});

it('calculates duration for interval markers', function () {
const target = setup();
const markers = [
{
start: 100,
end: 200,
name: 'marker1',
category: 0,
data: null,
},
{
start: 150,
end: 250,
name: 'marker2',
category: 0,
data: null,
},
];
const result = target.totalMarkerDuration(markers);
expect(result).toBe(200); // (200-100) + (250-150) = 100 + 100 = 200

// Make sure that we print a formatted log for the duration.
expect(console.log).toHaveBeenCalledWith('Total marker duration: 200ms');
});

it('skips instant markers with null end times', function () {
const target = setup();
const markers = [
{
start: 100,
end: 200,
name: 'interval',
category: 0,
threadId: null,
data: null,
},
{
start: 150,
end: null,
name: 'instant',
category: 0,
threadId: null,
data: null,
},
{
start: 300,
end: 400,
name: 'interval2',
category: 0,
threadId: null,
data: null,
},
];
const result = target.totalMarkerDuration(markers);
expect(result).toBe(200); // (200-100) + (400-300) = 100 + 100 = 200
});

it('handles mixed valid and invalid markers', function () {
const target = setup();
const markers = [
{
start: 100,
end: 200,
name: 'valid',
category: 0,
threadId: null,
data: null,
},
null,
{
start: 'invalid',
end: 300,
name: 'invalid',
category: 0,
threadId: null,
data: null,
},
{
start: 400,
end: 500,
name: 'valid2',
category: 0,
threadId: null,
data: null,
},
];
const result = target.totalMarkerDuration(markers);
expect(result).toBe(200); // (200-100) + (500-400) = 100 + 100 = 200
});
});
});
27 changes: 27 additions & 0 deletions src/utils/window-console.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { selectorsForConsole } from 'firefox-profiler/selectors';
import actions from 'firefox-profiler/actions';
import { shortenUrl } from 'firefox-profiler/utils/shorten-url';
import { createBrowserConnection } from 'firefox-profiler/app-logic/browser-connection';
import { formatTimestamp } from 'firefox-profiler/utils/format-numbers';

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

target.totalMarkerDuration = function (markers) {
if (!Array.isArray(markers)) {
console.error('totalMarkerDuration expects an array of markers');
return 0;
}

let totalDuration = 0;
for (const marker of markers) {
if (
marker &&
typeof marker.start === 'number' &&
typeof marker.end === 'number'
) {
totalDuration += marker.end - marker.start;
}
// Skip markers with null end times (instant markers have no duration)
}

console.log(`Total marker duration: ${formatTimestamp(totalDuration)}`);
return totalDuration;
};

target.shortenUrl = shortenUrl;
target.getState = getState;
target.selectors = selectorsForConsole;
Expand Down Expand Up @@ -315,6 +338,7 @@ export function logFriendlyPreamble() {
%cwindow.filteredMarkers%c - The current filtered and processed markers
%cwindow.selectedMarker%c - The selected processed marker in the current thread
%cwindow.callTree%c - The call tree of the current filtered thread
%cwindow.totalMarkerDuration%c - Calculate total duration of a marker array (e.g., totalMarkerDuration(filteredMarkers))
%cwindow.getState%c - The function that returns the current Redux state.
%cwindow.selectors%c - All the selectors that are used to get data from the Redux state.
%cwindow.dispatch%c - The function to dispatch a Redux action to change the state.
Expand Down Expand Up @@ -350,6 +374,9 @@ export function logFriendlyPreamble() {
// "window.callTree"
bold,
reset,
// "window.totalMarkerDuration"
bold,
reset,
// "window.getState"
bold,
reset,
Expand Down