diff --git a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js
index aefc8d5e078bc..01d4c9104b025 100644
--- a/packages/react-devtools-shared/src/__tests__/profilingCache-test.js
+++ b/packages/react-devtools-shared/src/__tests__/profilingCache-test.js
@@ -10,6 +10,8 @@
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
import type Store from 'react-devtools-shared/src/devtools/store';
+import {getVersionedRenderImplementation} from './utils';
+
describe('ProfilingCache', () => {
let PropTypes;
let React;
@@ -39,8 +41,11 @@ describe('ProfilingCache', () => {
Scheduler = require('scheduler');
});
+ const {render, getContainer} = getVersionedRenderImplementation();
+
// @reactVersion >= 16.9
- it('should collect data for each root (including ones added or mounted after profiling started)', () => {
+ // @reactVersion < 19
+ it('should collect data for each root (including ones added or mounted after profiling started) (legacy render)', () => {
const Parent = ({count}) => {
Scheduler.unstable_advanceTime(10);
const children = new Array(count)
@@ -151,6 +156,116 @@ describe('ProfilingCache', () => {
});
});
+ // @reactVersion >= 18
+ it('should collect data for each root (including ones added or mounted after profiling started) (createRoot)', () => {
+ const Parent = ({count}) => {
+ Scheduler.unstable_advanceTime(10);
+ const children = new Array(count)
+ .fill(true)
+ .map((_, index) => );
+ return (
+
+ {children}
+
+
+ );
+ };
+ const Child = ({duration}) => {
+ Scheduler.unstable_advanceTime(duration);
+ return null;
+ };
+ const MemoizedChild = React.memo(Child);
+
+ const RootA = ({children}) => children;
+ const RootB = ({children}) => children;
+ const RootC = ({children}) => children;
+
+ const containerA = document.createElement('div');
+ const containerB = document.createElement('div');
+ const containerC = document.createElement('div');
+
+ const rootA = ReactDOMClient.createRoot(containerA);
+ const rootB = ReactDOMClient.createRoot(containerB);
+ const rootC = ReactDOMClient.createRoot(containerC);
+
+ utils.act(() =>
+ rootA.render(
+
+
+ ,
+ ),
+ );
+ utils.act(() =>
+ rootB.render(
+
+
+ ,
+ ),
+ );
+ utils.act(() => store.profilerStore.startProfiling());
+ utils.act(() =>
+ rootA.render(
+
+
+ ,
+ ),
+ );
+ utils.act(() =>
+ rootC.render(
+
+
+ ,
+ ),
+ );
+ utils.act(() =>
+ rootA.render(
+
+
+ ,
+ ),
+ );
+ utils.act(() => rootB.unmount());
+ utils.act(() =>
+ rootA.render(
+
+
+ ,
+ ),
+ );
+ utils.act(() => store.profilerStore.stopProfiling());
+ utils.act(() => rootA.unmount());
+
+ const rootIDs = Array.from(
+ store.profilerStore.profilingData.dataForRoots.values(),
+ ).map(({rootID}) => rootID);
+ expect(rootIDs).toHaveLength(3);
+
+ const originalProfilingDataForRoot = [];
+
+ let data = store.profilerStore.getDataForRoot(rootIDs[0]);
+ expect(data.displayName).toMatchInlineSnapshot(`"RootA"`);
+ expect(data.commitData).toHaveLength(3);
+ originalProfilingDataForRoot.push(data);
+
+ data = store.profilerStore.getDataForRoot(rootIDs[1]);
+ expect(data.displayName).toMatchInlineSnapshot(`"RootC"`);
+ expect(data.commitData).toHaveLength(1);
+ originalProfilingDataForRoot.push(data);
+
+ data = store.profilerStore.getDataForRoot(rootIDs[2]);
+ expect(data.displayName).toMatchInlineSnapshot(`"RootB"`);
+ expect(data.commitData).toHaveLength(1);
+ originalProfilingDataForRoot.push(data);
+
+ utils.exportImportHelper(bridge, store);
+
+ rootIDs.forEach((rootID, index) => {
+ const current = store.profilerStore.getDataForRoot(rootID);
+ const prev = originalProfilingDataForRoot[index];
+ expect(current).toEqual(prev);
+ });
+ });
+
// @reactVersion >= 16.9
it('should collect data for each commit', () => {
const Parent = ({count}) => {
@@ -171,13 +286,11 @@ describe('ProfilingCache', () => {
};
const MemoizedChild = React.memo(Child);
- const container = document.createElement('div');
-
utils.act(() => store.profilerStore.startProfiling());
- utils.act(() => legacyRender(, container));
- utils.act(() => legacyRender(, container));
- utils.act(() => legacyRender(, container));
- utils.act(() => legacyRender(, container));
+ utils.act(() => render());
+ utils.act(() => render());
+ utils.act(() => render());
+ utils.act(() => render());
utils.act(() => store.profilerStore.stopProfiling());
const rootID = store.roots[0];
@@ -244,19 +357,13 @@ describe('ProfilingCache', () => {
}
}
- const container = document.createElement('div');
-
utils.act(() => store.profilerStore.startProfiling());
- utils.act(() => legacyRender(, container));
+ utils.act(() => render());
expect(instance).not.toBeNull();
utils.act(() => (instance: any).setState({count: 1}));
- utils.act(() =>
- legacyRender(, container),
- );
- utils.act(() =>
- legacyRender(, container),
- );
- utils.act(() => legacyRender(, container));
+ utils.act(() => render());
+ utils.act(() => render());
+ utils.act(() => render());
utils.act(() => store.profilerStore.stopProfiling());
const rootID = store.roots[0];
@@ -574,25 +681,21 @@ describe('ProfilingCache', () => {
return null;
};
- const container = document.createElement('div');
-
utils.act(() => store.profilerStore.startProfiling());
utils.act(() =>
- legacyRender(
+ render(
,
- container,
),
);
// Second render has no changed hooks, only changed props.
utils.act(() =>
- legacyRender(
+ render(
,
- container,
),
);
@@ -604,11 +707,10 @@ describe('ProfilingCache', () => {
// Fifth render has a changed context value, but no changed hook.
utils.act(() =>
- legacyRender(
+ render(
,
- container,
),
);
@@ -754,9 +856,7 @@ describe('ProfilingCache', () => {
};
utils.act(() => store.profilerStore.startProfiling());
- utils.act(() =>
- legacyRender(, document.createElement('div')),
- );
+ utils.act(() => render());
utils.act(() => store.profilerStore.stopProfiling());
expect(store).toMatchInlineSnapshot(`
@@ -822,9 +922,7 @@ describe('ProfilingCache', () => {
};
utils.act(() => store.profilerStore.startProfiling());
- await utils.actAsync(() =>
- legacyRender(, document.createElement('div')),
- );
+ await utils.actAsync(() => render());
utils.act(() => store.profilerStore.stopProfiling());
const rootID = store.roots[0];
@@ -880,12 +978,10 @@ describe('ProfilingCache', () => {
};
const MemoizedChild = React.memo(Child);
- const container = document.createElement('div');
-
utils.act(() => store.profilerStore.startProfiling());
- utils.act(() => legacyRender(, container));
- utils.act(() => legacyRender(, container));
- utils.act(() => legacyRender(, container));
+ utils.act(() => render());
+ utils.act(() => render());
+ utils.act(() => render());
utils.act(() => store.profilerStore.stopProfiling());
const rootID = store.roots[0];
@@ -941,10 +1037,8 @@ describe('ProfilingCache', () => {
// @reactVersion >= 18.0.0
// @reactVersion <= 18.2.0
it('should handle unexpectedly shallow suspense trees for react v[18.0.0 - 18.2.0]', () => {
- const container = document.createElement('div');
-
utils.act(() => store.profilerStore.startProfiling());
- utils.act(() => legacyRender(, container));
+ utils.act(() => render());
utils.act(() => store.profilerStore.stopProfiling());
const rootID = store.roots[0];
@@ -969,7 +1063,7 @@ describe('ProfilingCache', () => {
"updaters": [
{
"compiledWithForget": false,
- "displayName": "render()",
+ "displayName": "createRoot()",
"hocDisplayNames": null,
"id": 1,
"key": null,
@@ -981,13 +1075,10 @@ describe('ProfilingCache', () => {
`);
});
- // This test is not gated.
- // For this test we use the current version of react, built from source.
+ // @reactVersion > 18.2.0
it('should handle unexpectedly shallow suspense trees', () => {
- const container = document.createElement('div');
-
utils.act(() => store.profilerStore.startProfiling());
- utils.act(() => legacyRender(, container));
+ utils.act(() => render());
utils.act(() => store.profilerStore.stopProfiling());
const rootID = store.roots[0];
@@ -1012,7 +1103,7 @@ describe('ProfilingCache', () => {
"updaters": [
{
"compiledWithForget": false,
- "displayName": "render()",
+ "displayName": "createRoot()",
"hocDisplayNames": null,
"id": 1,
"key": null,
@@ -1105,13 +1196,12 @@ describe('ProfilingCache', () => {
const {Simulate} = require('react-dom/test-utils');
- const container = document.createElement('div');
- utils.act(() => legacyRender(, container));
- expect(container.textContent).toBe('Home');
+ utils.act(() => render());
+ expect(getContainer().textContent).toBe('Home');
utils.act(() => store.profilerStore.startProfiling());
utils.act(() => Simulate.click(linkRef.current));
utils.act(() => store.profilerStore.stopProfiling());
- expect(container.textContent).toBe('About');
+ expect(getContainer().textContent).toBe('About');
});
// @reactVersion >= 18.0