diff --git a/packages/react-devtools-shared/src/__tests__/store-test.js b/packages/react-devtools-shared/src/__tests__/store-test.js
index c277f6f167d06..dec3c41c8f1b6 100644
--- a/packages/react-devtools-shared/src/__tests__/store-test.js
+++ b/packages/react-devtools-shared/src/__tests__/store-test.js
@@ -7,6 +7,8 @@
* @flow
*/
+import {getVersionedRenderImplementation} from './utils';
+
describe('Store', () => {
let React;
let ReactDOM;
@@ -37,13 +39,13 @@ describe('Store', () => {
withErrorsOrWarningsIgnored = utils.withErrorsOrWarningsIgnored;
});
+ const {render, unmount, createContainer} = getVersionedRenderImplementation();
+
// @reactVersion >= 18.0
it('should not allow a root node to be collapsed', () => {
const Component = () =>
Hi
;
- act(() =>
- legacyRender(, document.createElement('div')),
- );
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
@@ -62,15 +64,13 @@ describe('Store', () => {
it('should properly handle a root with no visible nodes', () => {
const Root = ({children}) => children;
- const container = document.createElement('div');
-
- act(() => legacyRender({null}, container));
+ act(() => render({null}));
expect(store).toMatchInlineSnapshot(`
[root]
`);
- act(() => legacyRender(, container));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`[root]`);
});
@@ -93,17 +93,14 @@ describe('Store', () => {
};
const Child = () => null;
- const container = document.createElement('div');
-
act(() =>
- legacyRender(
+ render(
<>
>,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -119,9 +116,7 @@ describe('Store', () => {
const Component = () => null;
Component.displayName = '🟩💜🔵';
- const container = document.createElement('div');
-
- act(() => legacyRender(, container));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
<🟩💜🔵>
@@ -196,9 +191,7 @@ describe('Store', () => {
new Array(count).fill(true).map((_, index) => );
const Child = () => Hi!
;
- const container = document.createElement('div');
-
- act(() => legacyRender(, container));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¾
@@ -214,7 +207,7 @@ describe('Store', () => {
`);
- act(() => legacyRender(, container));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¾
@@ -226,12 +219,13 @@ describe('Store', () => {
`);
- act(() => ReactDOM.unmountComponentAtNode(container));
+ act(() => unmount());
expect(store).toMatchInlineSnapshot(``);
});
// @reactVersion >= 18.0
- it('should support mount and update operations for multiple roots', () => {
+ // @reactVersion < 19
+ it('should support mount and update operations for multiple roots (legacy render)', () => {
const Parent = ({count}) =>
new Array(count).fill(true).map((_, index) => );
const Child = () => Hi!
;
@@ -285,6 +279,64 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(``);
});
+ // @reactVersion >= 18.0
+ it('should support mount and update operations for multiple roots (createRoot)', () => {
+ const Parent = ({count}) =>
+ new Array(count).fill(true).map((_, index) => );
+ const Child = () => Hi!
;
+
+ const containerA = document.createElement('div');
+ const containerB = document.createElement('div');
+
+ const rootA = ReactDOMClient.createRoot(containerA);
+ const rootB = ReactDOMClient.createRoot(containerB);
+
+ act(() => {
+ rootA.render();
+ rootB.render();
+ });
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ â–¾
+
+
+
+ [root]
+ â–¾
+
+
+ `);
+
+ act(() => {
+ rootA.render();
+ rootB.render();
+ });
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ â–¾
+
+
+
+
+ [root]
+ â–¾
+
+ `);
+
+ act(() => rootB.unmount());
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ â–¾
+
+
+
+
+ `);
+
+ act(() => rootA.unmount());
+ expect(store).toMatchInlineSnapshot(``);
+ });
+
// @reactVersion >= 18.0
it('should filter DOM nodes from the store tree', () => {
const Grandparent = () => (
@@ -302,9 +354,7 @@ describe('Store', () => {
);
const Child = () => Hi!
;
- act(() =>
- legacyRender(, document.createElement('div')),
- );
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¾
@@ -337,8 +387,7 @@ describe('Store', () => {
);
- const container = document.createElement('div');
- act(() => legacyRender(, container));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¾
@@ -348,7 +397,7 @@ describe('Store', () => {
`);
act(() => {
- legacyRender(, container);
+ render();
});
expect(store).toMatchInlineSnapshot(`
[root]
@@ -399,15 +448,13 @@ describe('Store', () => {
);
- const container = document.createElement('div');
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -425,13 +472,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -449,13 +495,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -473,13 +518,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -497,13 +541,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -514,13 +557,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -538,13 +580,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -599,13 +640,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -658,13 +698,12 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -743,9 +782,7 @@ describe('Store', () => {
new Array(count).fill(true).map((_, index) => );
const Child = () => Hi!
;
- act(() =>
- legacyRender(, document.createElement('div')),
- );
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¾
@@ -816,9 +853,7 @@ describe('Store', () => {
const foo = ;
const bar = ;
- const container = document.createElement('div');
-
- act(() => legacyRender({[foo, bar]}, container));
+ act(() => render({[foo, bar]}));
expect(store).toMatchInlineSnapshot(`
[root]
â–¾
@@ -829,7 +864,7 @@ describe('Store', () => {
`);
- act(() => legacyRender({[bar, foo]}, container));
+ act(() => render({[bar, foo]}));
expect(store).toMatchInlineSnapshot(`
[root]
â–¾
@@ -870,15 +905,12 @@ describe('Store', () => {
new Array(count).fill(true).map((_, index) => );
const Child = () => Hi!
;
- const container = document.createElement('div');
-
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -888,12 +920,11 @@ describe('Store', () => {
`);
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
expect(store).toMatchInlineSnapshot(`
@@ -902,12 +933,13 @@ describe('Store', () => {
â–¸
`);
- act(() => ReactDOM.unmountComponentAtNode(container));
+ act(() => unmount());
expect(store).toMatchInlineSnapshot(``);
});
// @reactVersion >= 18.0
- it('should support mount and update operations for multiple roots', () => {
+ // @reactVersion < 19
+ it('should support mount and update operations for multiple roots (legacy render)', () => {
const Parent = ({count}) =>
new Array(count).fill(true).map((_, index) => );
const Child = () => Hi!
;
@@ -947,6 +979,50 @@ describe('Store', () => {
expect(store).toMatchInlineSnapshot(``);
});
+ // @reactVersion >= 18.0
+ it('should support mount and update operations for multiple roots (createRoot)', () => {
+ const Parent = ({count}) =>
+ new Array(count).fill(true).map((_, index) => );
+ const Child = () => Hi!
;
+
+ const containerA = document.createElement('div');
+ const containerB = document.createElement('div');
+
+ const rootA = ReactDOMClient.createRoot(containerA);
+ const rootB = ReactDOMClient.createRoot(containerB);
+
+ act(() => {
+ rootA.render();
+ rootB.render();
+ });
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ â–¸
+ [root]
+ â–¸
+ `);
+
+ act(() => {
+ rootA.render();
+ rootB.render();
+ });
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ â–¸
+ [root]
+ â–¸
+ `);
+
+ act(() => rootB.unmount());
+ expect(store).toMatchInlineSnapshot(`
+ [root]
+ â–¸
+ `);
+
+ act(() => rootA.unmount());
+ expect(store).toMatchInlineSnapshot(``);
+ });
+
// @reactVersion >= 18.0
it('should filter DOM nodes from the store tree', () => {
const Grandparent = () => (
@@ -964,9 +1040,7 @@ describe('Store', () => {
);
const Child = () => Hi!
;
- act(() =>
- legacyRender(, document.createElement('div')),
- );
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¸
@@ -1012,8 +1086,7 @@ describe('Store', () => {
);
- const container = document.createElement('div');
- act(() => legacyRender(, container));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¸
@@ -1031,7 +1104,7 @@ describe('Store', () => {
`);
act(() => {
- legacyRender(, container);
+ render();
});
expect(store).toMatchInlineSnapshot(`
[root]
@@ -1054,9 +1127,7 @@ describe('Store', () => {
new Array(count).fill(true).map((_, index) => );
const Child = () => Hi!
;
- act(() =>
- legacyRender(, document.createElement('div')),
- );
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¸
@@ -1136,12 +1207,7 @@ describe('Store', () => {
const ref = React.createRef();
- act(() =>
- legacyRender(
- ,
- document.createElement('div'),
- ),
- );
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¸
@@ -1207,15 +1273,13 @@ describe('Store', () => {
const foo = ;
const bar = ;
- const container = document.createElement('div');
-
- act(() => legacyRender({[foo, bar]}, container));
+ act(() => render({[foo, bar]}));
expect(store).toMatchInlineSnapshot(`
[root]
â–¸
`);
- act(() => legacyRender({[bar, foo]}, container));
+ act(() => render({[bar, foo]}));
expect(store).toMatchInlineSnapshot(`
[root]
â–¸
@@ -1264,7 +1328,7 @@ describe('Store', () => {
const Parent = () => ;
const Child = () => null;
- act(() => legacyRender(, document.createElement('div')));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
â–¸
@@ -1328,7 +1392,7 @@ describe('Store', () => {
const Parent = () => ;
const Child = () => null;
- act(() => legacyRender(, document.createElement('div')));
+ act(() => render());
for (let i = 0; i < store.numElements; i++) {
expect(store.getIndexOfElementID(store.getElementIDAtIndex(i))).toBe(i);
@@ -1342,8 +1406,8 @@ describe('Store', () => {
const Child = () => null;
act(() => {
- legacyRender(, document.createElement('div'));
- legacyRender(, document.createElement('div'));
+ render();
+ render();
});
for (let i = 0; i < store.numElements; i++) {
@@ -1358,12 +1422,11 @@ describe('Store', () => {
const Child = () => null;
act(() =>
- legacyRender(
+ render(
,
- document.createElement('div'),
),
);
@@ -1379,19 +1442,20 @@ describe('Store', () => {
const Child = () => null;
act(() => {
- legacyRender(
+ render(
,
- document.createElement('div'),
);
- legacyRender(
+
+ createContainer();
+
+ render(
,
- document.createElement('div'),
);
});
@@ -1402,7 +1466,8 @@ describe('Store', () => {
});
// @reactVersion >= 18.0
- it('detects and updates profiling support based on the attached roots', () => {
+ // @reactVersion < 19
+ it('detects and updates profiling support based on the attached roots (legacy render)', () => {
const Component = () => null;
const containerA = document.createElement('div');
@@ -1421,6 +1486,29 @@ describe('Store', () => {
expect(store.rootSupportsBasicProfiling).toBe(false);
});
+ // @reactVersion >= 18
+ it('detects and updates profiling support based on the attached roots (createRoot)', () => {
+ const Component = () => null;
+
+ const containerA = document.createElement('div');
+ const containerB = document.createElement('div');
+
+ const rootA = ReactDOMClient.createRoot(containerA);
+ const rootB = ReactDOMClient.createRoot(containerB);
+
+ expect(store.rootSupportsBasicProfiling).toBe(false);
+
+ act(() => rootA.render());
+ expect(store.rootSupportsBasicProfiling).toBe(true);
+
+ act(() => rootB.render());
+ act(() => rootA.unmount());
+ expect(store.rootSupportsBasicProfiling).toBe(true);
+
+ act(() => rootB.unmount());
+ expect(store.rootSupportsBasicProfiling).toBe(false);
+ });
+
// @reactVersion >= 18.0
it('should properly serialize non-string key values', () => {
const Child = () => null;
@@ -1429,7 +1517,7 @@ describe('Store', () => {
// This is pretty hacky.
const fauxElement = Object.assign({}, , {key: 123});
- act(() => legacyRender([fauxElement], document.createElement('div')));
+ act(() => render([fauxElement]));
expect(store).toMatchInlineSnapshot(`
[root]
@@ -1488,15 +1576,13 @@ describe('Store', () => {
);
- const container = document.createElement('div');
-
// Render once to start fetching the lazy component
- act(() => legacyRender(, container));
+ act(() => render());
await Promise.resolve();
// Render again after it resolves
- act(() => legacyRender(, container));
+ act(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
@@ -1543,6 +1629,7 @@ describe('Store', () => {
});
// @reactVersion >= 18.0
+ // @reactVersion < 19
it('should support Lazy components (legacy render)', async () => {
const container = document.createElement('div');
@@ -1612,6 +1699,7 @@ describe('Store', () => {
});
// @reactVersion >= 18.0
+ // @reactVersion < 19
it('should support Lazy components that are unmounted before they finish loading (legacy render)', async () => {
const container = document.createElement('div');
@@ -1634,6 +1722,7 @@ describe('Store', () => {
});
// @reactVersion >= 18.0
+ // @reactVersion < 19
it('should support Lazy components that are unmounted before they finish loading in (createRoot)', async () => {
const container = document.createElement('div');
const root = ReactDOMClient.createRoot(container);
@@ -1665,10 +1754,9 @@ describe('Store', () => {
console.warn('test-only: render warning');
return null;
}
- const container = document.createElement('div');
withErrorsOrWarningsIgnored(['test-only:'], () => {
- act(() => legacyRender(, container));
+ act(() => render());
});
expect(store).toMatchInlineSnapshot(`
@@ -1678,7 +1766,7 @@ describe('Store', () => {
`);
withErrorsOrWarningsIgnored(['test-only:'], () => {
- act(() => legacyRender(, container));
+ act(() => render());
});
expect(store).toMatchInlineSnapshot(`
@@ -1697,10 +1785,9 @@ describe('Store', () => {
});
return null;
}
- const container = document.createElement('div');
withErrorsOrWarningsIgnored(['test-only:'], () => {
- act(() => legacyRender(, container));
+ act(() => render());
});
expect(store).toMatchInlineSnapshot(`
@@ -1710,7 +1797,7 @@ describe('Store', () => {
`);
withErrorsOrWarningsIgnored(['test-only:'], () => {
- act(() => legacyRender(, container));
+ act(() => render());
});
expect(store).toMatchInlineSnapshot(`
@@ -1739,11 +1826,10 @@ describe('Store', () => {
});
return null;
}
- const container = document.createElement('div');
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() => {
- legacyRender(, container);
+ render();
}, false);
});
flushPendingBridgeOperations();
@@ -1760,7 +1846,7 @@ describe('Store', () => {
✕âš
`);
- act(() => ReactDOM.unmountComponentAtNode(container));
+ act(() => unmount());
expect(store).toMatchInlineSnapshot(``);
});
@@ -1778,15 +1864,12 @@ describe('Store', () => {
return null;
}
- const container = document.createElement('div');
-
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() => {
- legacyRender(
+ render(
<>
>,
- container,
);
}, false);
flushPendingBridgeOperations();
@@ -1797,12 +1880,11 @@ describe('Store', () => {
// Before warnings and errors have flushed, flush another commit.
act(() => {
- legacyRender(
+ render(
<>
>,
- container,
);
}, false);
flushPendingBridgeOperations();
@@ -1823,14 +1905,13 @@ describe('Store', () => {
`);
- act(() => ReactDOM.unmountComponentAtNode(container));
+ act(() => unmount());
expect(store).toMatchInlineSnapshot(``);
});
});
// @reactVersion >= 18.0
it('from react get counted', () => {
- const container = document.createElement('div');
function Example() {
return [];
}
@@ -1841,7 +1922,7 @@ describe('Store', () => {
withErrorsOrWarningsIgnored(
['Warning: Each child in a list should have a unique "key" prop'],
() => {
- act(() => legacyRender(, container));
+ act(() => render());
},
);
@@ -1860,15 +1941,14 @@ describe('Store', () => {
console.warn('test-only: render warning');
return null;
}
- const container = document.createElement('div');
+
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
});
@@ -1902,15 +1982,14 @@ describe('Store', () => {
console.warn('test-only: render warning');
return null;
}
- const container = document.createElement('div');
+
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
});
@@ -1948,15 +2027,14 @@ describe('Store', () => {
console.warn('test-only: render warning');
return null;
}
- const container = document.createElement('div');
+
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
});
@@ -2002,16 +2080,15 @@ describe('Store', () => {
console.warn('test-only: render warning');
return null;
}
- const container = document.createElement('div');
+
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
});
@@ -2025,12 +2102,11 @@ describe('Store', () => {
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
});
@@ -2043,11 +2119,10 @@ describe('Store', () => {
withErrorsOrWarningsIgnored(['test-only:'], () => {
act(() =>
- legacyRender(
+ render(
,
- container,
),
);
});
@@ -2058,7 +2133,7 @@ describe('Store', () => {
`);
withErrorsOrWarningsIgnored(['test-only:'], () => {
- act(() => legacyRender(, container));
+ act(() => render());
});
expect(store).toMatchInlineSnapshot(`[root]`);
expect(store.errorCount).toBe(0);
@@ -2086,9 +2161,7 @@ describe('Store', () => {
);
}
- const container = document.createElement('div');
- const root = ReactDOMClient.createRoot(container);
- await actAsync(() => root.render());
+ await actAsync(() => render());
expect(store).toMatchInlineSnapshot(`
[root]
@@ -2097,7 +2170,7 @@ describe('Store', () => {
`);
- await actAsync(() => root.render());
+ await actAsync(() => render());
expect(store).toMatchInlineSnapshot(`
[root]