Skip to content
Merged
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
135 changes: 125 additions & 10 deletions packages/react-reconciler/src/__tests__/ReactPerformanceTrack-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,20 @@ let act;
let useEffect;

describe('ReactPerformanceTracks', () => {
const performanceMeasureCalls = [];

beforeEach(() => {
performanceMeasureCalls.length = 0;
Object.defineProperty(performance, 'measure', {
value: jest.fn(),
value: jest.fn((measureName, reusableOptions) => {
performanceMeasureCalls.push([
measureName,
{
// React will mutate the options it passes to performance.measure.
...reusableOptions,
},
]);
}),
configurable: true,
});
console.timeStamp = () => {};
Expand All @@ -32,6 +43,19 @@ describe('ReactPerformanceTracks', () => {
useEffect = React.useEffect;
});

function getConsoleTimestampEntries() {
try {
return console.timeStamp.mock.calls.filter(call => {
const [, startTime, endTime] = call;

const isRegisterTrackCall = startTime !== 0.003 && endTime !== 0.003;
return isRegisterTrackCall;
});
} finally {
console.timeStamp.mockClear();
}
}

// @gate __DEV__ && enableComponentPerformanceTrack
it('shows a hint if an update is triggered by a deeply equal object', async () => {
const App = function App({items}) {
Expand All @@ -45,7 +69,7 @@ describe('ReactPerformanceTracks', () => {
ReactNoop.render(<App items={items} />);
});

expect(performance.measure.mock.calls).toEqual([
expect(performanceMeasureCalls).toEqual([
[
'Mount',
{
Expand All @@ -62,14 +86,14 @@ describe('ReactPerformanceTracks', () => {
},
],
]);
performance.measure.mockClear();
performanceMeasureCalls.length = 0;

Scheduler.unstable_advanceTime(10);
await act(() => {
ReactNoop.render(<App items={items.concat('4')} />);
});

expect(performance.measure.mock.calls).toEqual([
expect(performanceMeasureCalls).toEqual([
[
'​App',
{
Expand Down Expand Up @@ -105,7 +129,7 @@ describe('ReactPerformanceTracks', () => {
ReactNoop.render(<App items={items} />);
});

expect(performance.measure.mock.calls).toEqual([
expect(performanceMeasureCalls).toEqual([
[
'Mount',
{
Expand All @@ -122,14 +146,14 @@ describe('ReactPerformanceTracks', () => {
},
],
]);
performance.measure.mockClear();
performanceMeasureCalls.length = 0;

Scheduler.unstable_advanceTime(10);
await act(() => {
ReactNoop.render(<App items={items.concat('-1')} />);
});

expect(performance.measure.mock.calls).toEqual([
expect(performanceMeasureCalls).toEqual([
[
'​App',
{
Expand Down Expand Up @@ -171,7 +195,7 @@ describe('ReactPerformanceTracks', () => {
ReactNoop.render(<App data={{buffer: null}} />);
});

expect(performance.measure.mock.calls).toEqual([
expect(performanceMeasureCalls).toEqual([
[
'Mount',
{
Expand All @@ -188,7 +212,7 @@ describe('ReactPerformanceTracks', () => {
},
],
]);
performance.measure.mockClear();
performanceMeasureCalls.length = 0;

Scheduler.unstable_advanceTime(10);

Expand All @@ -197,7 +221,7 @@ describe('ReactPerformanceTracks', () => {
ReactNoop.render(<App data={{buffer: bigData}} />);
});

expect(performance.measure.mock.calls).toEqual([
expect(performanceMeasureCalls).toEqual([
[
'​App',
{
Expand Down Expand Up @@ -324,4 +348,95 @@ describe('ReactPerformanceTracks', () => {
],
]);
});

// @gate __DEV__ && enableComponentPerformanceTrack
it('includes spans for Components with no prop changes', async () => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually doesn't at the moment but prob should?

function Left({value}) {
Scheduler.unstable_advanceTime(5000);
}
function Right() {
Scheduler.unstable_advanceTime(10000);
}

await act(() => {
ReactNoop.render(
<>
<Left value={1} />
<Right />
</>,
);
});

expect(performanceMeasureCalls).toEqual([
[
'Mount',
{
detail: {
devtools: {
color: 'warning',
properties: null,
tooltipText: 'Mount',
track: 'Components ⚛',
},
},
end: 5000,
start: 0,
},
],
[
'Mount',
{
detail: {
devtools: {
color: 'warning',
properties: null,
tooltipText: 'Mount',
track: 'Components ⚛',
},
},
end: 15000,
start: 5000,
},
],
]);
performanceMeasureCalls.length = 0;
getConsoleTimestampEntries();

Scheduler.unstable_advanceTime(1000);

await act(() => {
ReactNoop.render(
<>
<Left value={2} />
<Right />
</>,
);
});

expect(performanceMeasureCalls).toEqual([
[
'​Left',
{
detail: {
devtools: {
color: 'error',
properties: [
['Changed Props', ''],
['– value', '1'],
['+ value', '2'],
],
tooltipText: 'Left',
track: 'Components ⚛',
},
},
end: 21000,
start: 16000,
},
],
]);
expect(getConsoleTimestampEntries()).toEqual([
['Render', 16000, 31000, 'Blocking', 'Scheduler ⚛', 'primary-dark'],
Comment on lines +431 to +438
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

15s in the Scheduler track but only 5s are accounted for (in <Left> where props changed). The other 10s of <Right> are omitted. Ideally they would show with a hint that no props changed and the Component should be memoized. Or refactored since a large amount of time spent in a Component with no props changed hints at some expensive work in its impl that couldn't be memoized.

]);
performanceMeasureCalls.length = 0;
});
});
Loading