1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. describe('Store', () => {
    
  11.   let React;
    
  12.   let ReactDOM;
    
  13.   let ReactDOMClient;
    
  14.   let agent;
    
  15.   let act;
    
  16.   let actAsync;
    
  17.   let bridge;
    
  18.   let getRendererID;
    
  19.   let legacyRender;
    
  20.   let store;
    
  21.   let withErrorsOrWarningsIgnored;
    
  22. 
    
  23.   beforeEach(() => {
    
  24.     agent = global.agent;
    
  25.     bridge = global.bridge;
    
  26.     store = global.store;
    
  27. 
    
  28.     React = require('react');
    
  29.     ReactDOM = require('react-dom');
    
  30.     ReactDOMClient = require('react-dom/client');
    
  31. 
    
  32.     const utils = require('./utils');
    
  33.     act = utils.act;
    
  34.     actAsync = utils.actAsync;
    
  35.     getRendererID = utils.getRendererID;
    
  36.     legacyRender = utils.legacyRender;
    
  37.     withErrorsOrWarningsIgnored = utils.withErrorsOrWarningsIgnored;
    
  38.   });
    
  39. 
    
  40.   // @reactVersion >= 18.0
    
  41.   it('should not allow a root node to be collapsed', () => {
    
  42.     const Component = () => <div>Hi</div>;
    
  43. 
    
  44.     act(() =>
    
  45.       legacyRender(<Component count={4} />, document.createElement('div')),
    
  46.     );
    
  47.     expect(store).toMatchInlineSnapshot(`
    
  48.       [root]
    
  49.           <Component>
    
  50.     `);
    
  51. 
    
  52.     expect(store.roots).toHaveLength(1);
    
  53. 
    
  54.     const rootID = store.roots[0];
    
  55. 
    
  56.     expect(() => store.toggleIsCollapsed(rootID, true)).toThrow(
    
  57.       'Root nodes cannot be collapsed',
    
  58.     );
    
  59.   });
    
  60. 
    
  61.   // @reactVersion >= 18.0
    
  62.   it('should properly handle a root with no visible nodes', () => {
    
  63.     const Root = ({children}) => children;
    
  64. 
    
  65.     const container = document.createElement('div');
    
  66. 
    
  67.     act(() => legacyRender(<Root>{null}</Root>, container));
    
  68.     expect(store).toMatchInlineSnapshot(`
    
  69.       [root]
    
  70.           <Root>
    
  71.     `);
    
  72. 
    
  73.     act(() => legacyRender(<div />, container));
    
  74.     expect(store).toMatchInlineSnapshot(`[root]`);
    
  75.   });
    
  76. 
    
  77.   // This test is not the same cause as what's reported on GitHub,
    
  78.   // but the resulting behavior (owner mounting after descendant) is the same.
    
  79.   // Thec ase below is admittedly contrived and relies on side effects.
    
  80.   // I'mnot yet sure of how to reduce the GitHub reported production case to a test though.
    
  81.   // See https://github.com/facebook/react/issues/21445
    
  82.   // @reactVersion >= 18.0
    
  83.   it('should handle when a component mounts before its owner', () => {
    
  84.     const promise = new Promise(resolve => {});
    
  85. 
    
  86.     let Dynamic = null;
    
  87.     const Owner = () => {
    
  88.       Dynamic = <Child />;
    
  89.       throw promise;
    
  90.     };
    
  91.     const Parent = () => {
    
  92.       return Dynamic;
    
  93.     };
    
  94.     const Child = () => null;
    
  95. 
    
  96.     const container = document.createElement('div');
    
  97. 
    
  98.     act(() =>
    
  99.       legacyRender(
    
  100.         <>
    
  101.           <React.Suspense fallback="Loading...">
    
  102.             <Owner />
    
  103.           </React.Suspense>
    
  104.           <Parent />
    
  105.         </>,
    
  106.         container,
    
  107.       ),
    
  108.     );
    
  109.     expect(store).toMatchInlineSnapshot(`
    
  110.       [root]
    
  111.           <Suspense>
    
  112.         ▾ <Parent>
    
  113.             <Child>
    
  114.     `);
    
  115.   });
    
  116. 
    
  117.   // @reactVersion >= 18.0
    
  118.   it('should handle multibyte character strings', () => {
    
  119.     const Component = () => null;
    
  120.     Component.displayName = '🟩💜🔵';
    
  121. 
    
  122.     const container = document.createElement('div');
    
  123. 
    
  124.     act(() => legacyRender(<Component />, container));
    
  125.     expect(store).toMatchInlineSnapshot(`
    
  126.       [root]
    
  127.           <🟩💜🔵>
    
  128.     `);
    
  129.   });
    
  130. 
    
  131.   describe('StrictMode compliance', () => {
    
  132.     it('should mark strict root elements as strict', () => {
    
  133.       const App = () => <Component />;
    
  134.       const Component = () => null;
    
  135. 
    
  136.       const container = document.createElement('div');
    
  137.       const root = ReactDOMClient.createRoot(container, {
    
  138.         unstable_strictMode: true,
    
  139.       });
    
  140.       act(() => {
    
  141.         root.render(<App />);
    
  142.       });
    
  143. 
    
  144.       expect(store.getElementAtIndex(0).isStrictModeNonCompliant).toBe(false);
    
  145.       expect(store.getElementAtIndex(1).isStrictModeNonCompliant).toBe(false);
    
  146.     });
    
  147. 
    
  148.     // @reactVersion >= 18.0
    
  149.     it('should mark non strict root elements as not strict', () => {
    
  150.       const App = () => <Component />;
    
  151.       const Component = () => null;
    
  152. 
    
  153.       const container = document.createElement('div');
    
  154.       const root = ReactDOMClient.createRoot(container);
    
  155.       act(() => {
    
  156.         root.render(<App />);
    
  157.       });
    
  158. 
    
  159.       expect(store.getElementAtIndex(0).isStrictModeNonCompliant).toBe(true);
    
  160.       expect(store.getElementAtIndex(1).isStrictModeNonCompliant).toBe(true);
    
  161.     });
    
  162. 
    
  163.     it('should mark StrictMode subtree elements as strict', () => {
    
  164.       const App = () => (
    
  165.         <React.StrictMode>
    
  166.           <Component />
    
  167.         </React.StrictMode>
    
  168.       );
    
  169.       const Component = () => null;
    
  170. 
    
  171.       const container = document.createElement('div');
    
  172.       const root = ReactDOMClient.createRoot(container);
    
  173.       act(() => {
    
  174.         root.render(<App />);
    
  175.       });
    
  176. 
    
  177.       expect(store.getElementAtIndex(0).isStrictModeNonCompliant).toBe(true);
    
  178.       expect(store.getElementAtIndex(1).isStrictModeNonCompliant).toBe(false);
    
  179.     });
    
  180.   });
    
  181. 
    
  182.   describe('collapseNodesByDefault:false', () => {
    
  183.     beforeEach(() => {
    
  184.       store.collapseNodesByDefault = false;
    
  185.     });
    
  186. 
    
  187.     // @reactVersion >= 18.0
    
  188.     it('should support mount and update operations', () => {
    
  189.       const Grandparent = ({count}) => (
    
  190.         <React.Fragment>
    
  191.           <Parent count={count} />
    
  192.           <Parent count={count} />
    
  193.         </React.Fragment>
    
  194.       );
    
  195.       const Parent = ({count}) =>
    
  196.         new Array(count).fill(true).map((_, index) => <Child key={index} />);
    
  197.       const Child = () => <div>Hi!</div>;
    
  198. 
    
  199.       const container = document.createElement('div');
    
  200. 
    
  201.       act(() => legacyRender(<Grandparent count={4} />, container));
    
  202.       expect(store).toMatchInlineSnapshot(`
    
  203.         [root]
    
  204.           ▾ <Grandparent>
    
  205.             ▾ <Parent>
    
  206.                 <Child key="0">
    
  207.                 <Child key="1">
    
  208.                 <Child key="2">
    
  209.                 <Child key="3">
    
  210.             ▾ <Parent>
    
  211.                 <Child key="0">
    
  212.                 <Child key="1">
    
  213.                 <Child key="2">
    
  214.                 <Child key="3">
    
  215.       `);
    
  216. 
    
  217.       act(() => legacyRender(<Grandparent count={2} />, container));
    
  218.       expect(store).toMatchInlineSnapshot(`
    
  219.         [root]
    
  220.           ▾ <Grandparent>
    
  221.             ▾ <Parent>
    
  222.                 <Child key="0">
    
  223.                 <Child key="1">
    
  224.             ▾ <Parent>
    
  225.                 <Child key="0">
    
  226.                 <Child key="1">
    
  227.       `);
    
  228. 
    
  229.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  230.       expect(store).toMatchInlineSnapshot(``);
    
  231.     });
    
  232. 
    
  233.     // @reactVersion >= 18.0
    
  234.     it('should support mount and update operations for multiple roots', () => {
    
  235.       const Parent = ({count}) =>
    
  236.         new Array(count).fill(true).map((_, index) => <Child key={index} />);
    
  237.       const Child = () => <div>Hi!</div>;
    
  238. 
    
  239.       const containerA = document.createElement('div');
    
  240.       const containerB = document.createElement('div');
    
  241. 
    
  242.       act(() => {
    
  243.         legacyRender(<Parent key="A" count={3} />, containerA);
    
  244.         legacyRender(<Parent key="B" count={2} />, containerB);
    
  245.       });
    
  246.       expect(store).toMatchInlineSnapshot(`
    
  247.         [root]
    
  248.           ▾ <Parent key="A">
    
  249.               <Child key="0">
    
  250.               <Child key="1">
    
  251.               <Child key="2">
    
  252.         [root]
    
  253.           ▾ <Parent key="B">
    
  254.               <Child key="0">
    
  255.               <Child key="1">
    
  256.       `);
    
  257. 
    
  258.       act(() => {
    
  259.         legacyRender(<Parent key="A" count={4} />, containerA);
    
  260.         legacyRender(<Parent key="B" count={1} />, containerB);
    
  261.       });
    
  262.       expect(store).toMatchInlineSnapshot(`
    
  263.         [root]
    
  264.           ▾ <Parent key="A">
    
  265.               <Child key="0">
    
  266.               <Child key="1">
    
  267.               <Child key="2">
    
  268.               <Child key="3">
    
  269.         [root]
    
  270.           ▾ <Parent key="B">
    
  271.               <Child key="0">
    
  272.       `);
    
  273. 
    
  274.       act(() => ReactDOM.unmountComponentAtNode(containerB));
    
  275.       expect(store).toMatchInlineSnapshot(`
    
  276.         [root]
    
  277.           ▾ <Parent key="A">
    
  278.               <Child key="0">
    
  279.               <Child key="1">
    
  280.               <Child key="2">
    
  281.               <Child key="3">
    
  282.       `);
    
  283. 
    
  284.       act(() => ReactDOM.unmountComponentAtNode(containerA));
    
  285.       expect(store).toMatchInlineSnapshot(``);
    
  286.     });
    
  287. 
    
  288.     // @reactVersion >= 18.0
    
  289.     it('should filter DOM nodes from the store tree', () => {
    
  290.       const Grandparent = () => (
    
  291.         <div>
    
  292.           <div>
    
  293.             <Parent />
    
  294.           </div>
    
  295.           <Parent />
    
  296.         </div>
    
  297.       );
    
  298.       const Parent = () => (
    
  299.         <div>
    
  300.           <Child />
    
  301.         </div>
    
  302.       );
    
  303.       const Child = () => <div>Hi!</div>;
    
  304. 
    
  305.       act(() =>
    
  306.         legacyRender(<Grandparent count={4} />, document.createElement('div')),
    
  307.       );
    
  308.       expect(store).toMatchInlineSnapshot(`
    
  309.         [root]
    
  310.           ▾ <Grandparent>
    
  311.             ▾ <Parent>
    
  312.                 <Child>
    
  313.             ▾ <Parent>
    
  314.                 <Child>
    
  315.       `);
    
  316.     });
    
  317. 
    
  318.     // @reactVersion >= 18.0
    
  319.     it('should display Suspense nodes properly in various states', () => {
    
  320.       const Loading = () => <div>Loading...</div>;
    
  321.       const SuspendingComponent = () => {
    
  322.         throw new Promise(() => {});
    
  323.       };
    
  324.       const Component = () => {
    
  325.         return <div>Hello</div>;
    
  326.       };
    
  327.       const Wrapper = ({shouldSuspense}) => (
    
  328.         <React.Fragment>
    
  329.           <Component key="Outside" />
    
  330.           <React.Suspense fallback={<Loading />}>
    
  331.             {shouldSuspense ? (
    
  332.               <SuspendingComponent />
    
  333.             ) : (
    
  334.               <Component key="Inside" />
    
  335.             )}
    
  336.           </React.Suspense>
    
  337.         </React.Fragment>
    
  338.       );
    
  339. 
    
  340.       const container = document.createElement('div');
    
  341.       act(() => legacyRender(<Wrapper shouldSuspense={true} />, container));
    
  342.       expect(store).toMatchInlineSnapshot(`
    
  343.         [root]
    
  344.           ▾ <Wrapper>
    
  345.               <Component key="Outside">
    
  346.             ▾ <Suspense>
    
  347.                 <Loading>
    
  348.       `);
    
  349. 
    
  350.       act(() => {
    
  351.         legacyRender(<Wrapper shouldSuspense={false} />, container);
    
  352.       });
    
  353.       expect(store).toMatchInlineSnapshot(`
    
  354.         [root]
    
  355.           ▾ <Wrapper>
    
  356.               <Component key="Outside">
    
  357.             ▾ <Suspense>
    
  358.                 <Component key="Inside">
    
  359.       `);
    
  360.     });
    
  361. 
    
  362.     // @reactVersion >= 18.0
    
  363.     it('should support nested Suspense nodes', () => {
    
  364.       const Component = () => null;
    
  365.       const Loading = () => <div>Loading...</div>;
    
  366.       const Never = () => {
    
  367.         throw new Promise(() => {});
    
  368.       };
    
  369. 
    
  370.       const Wrapper = ({
    
  371.         suspendFirst = false,
    
  372.         suspendSecond = false,
    
  373.         suspendParent = false,
    
  374.       }) => (
    
  375.         <React.Fragment>
    
  376.           <Component key="Outside" />
    
  377.           <React.Suspense fallback={<Loading key="Parent Fallback" />}>
    
  378.             <Component key="Unrelated at Start" />
    
  379.             <React.Suspense fallback={<Loading key="Suspense 1 Fallback" />}>
    
  380.               {suspendFirst ? (
    
  381.                 <Never />
    
  382.               ) : (
    
  383.                 <Component key="Suspense 1 Content" />
    
  384.               )}
    
  385.             </React.Suspense>
    
  386.             <React.Suspense fallback={<Loading key="Suspense 2 Fallback" />}>
    
  387.               {suspendSecond ? (
    
  388.                 <Never />
    
  389.               ) : (
    
  390.                 <Component key="Suspense 2 Content" />
    
  391.               )}
    
  392.             </React.Suspense>
    
  393.             <React.Suspense fallback={<Loading key="Suspense 3 Fallback" />}>
    
  394.               <Never />
    
  395.             </React.Suspense>
    
  396.             {suspendParent && <Never />}
    
  397.             <Component key="Unrelated at End" />
    
  398.           </React.Suspense>
    
  399.         </React.Fragment>
    
  400.       );
    
  401. 
    
  402.       const container = document.createElement('div');
    
  403.       act(() =>
    
  404.         legacyRender(
    
  405.           <Wrapper
    
  406.             suspendParent={false}
    
  407.             suspendFirst={false}
    
  408.             suspendSecond={false}
    
  409.           />,
    
  410.           container,
    
  411.         ),
    
  412.       );
    
  413.       expect(store).toMatchInlineSnapshot(`
    
  414.         [root]
    
  415.           ▾ <Wrapper>
    
  416.               <Component key="Outside">
    
  417.             ▾ <Suspense>
    
  418.                 <Component key="Unrelated at Start">
    
  419.               ▾ <Suspense>
    
  420.                   <Component key="Suspense 1 Content">
    
  421.               ▾ <Suspense>
    
  422.                   <Component key="Suspense 2 Content">
    
  423.               ▾ <Suspense>
    
  424.                   <Loading key="Suspense 3 Fallback">
    
  425.                 <Component key="Unrelated at End">
    
  426.       `);
    
  427.       act(() =>
    
  428.         legacyRender(
    
  429.           <Wrapper
    
  430.             suspendParent={false}
    
  431.             suspendFirst={true}
    
  432.             suspendSecond={false}
    
  433.           />,
    
  434.           container,
    
  435.         ),
    
  436.       );
    
  437.       expect(store).toMatchInlineSnapshot(`
    
  438.         [root]
    
  439.           ▾ <Wrapper>
    
  440.               <Component key="Outside">
    
  441.             ▾ <Suspense>
    
  442.                 <Component key="Unrelated at Start">
    
  443.               ▾ <Suspense>
    
  444.                   <Loading key="Suspense 1 Fallback">
    
  445.               ▾ <Suspense>
    
  446.                   <Component key="Suspense 2 Content">
    
  447.               ▾ <Suspense>
    
  448.                   <Loading key="Suspense 3 Fallback">
    
  449.                 <Component key="Unrelated at End">
    
  450.       `);
    
  451.       act(() =>
    
  452.         legacyRender(
    
  453.           <Wrapper
    
  454.             suspendParent={false}
    
  455.             suspendFirst={false}
    
  456.             suspendSecond={true}
    
  457.           />,
    
  458.           container,
    
  459.         ),
    
  460.       );
    
  461.       expect(store).toMatchInlineSnapshot(`
    
  462.         [root]
    
  463.           ▾ <Wrapper>
    
  464.               <Component key="Outside">
    
  465.             ▾ <Suspense>
    
  466.                 <Component key="Unrelated at Start">
    
  467.               ▾ <Suspense>
    
  468.                   <Component key="Suspense 1 Content">
    
  469.               ▾ <Suspense>
    
  470.                   <Loading key="Suspense 2 Fallback">
    
  471.               ▾ <Suspense>
    
  472.                   <Loading key="Suspense 3 Fallback">
    
  473.                 <Component key="Unrelated at End">
    
  474.       `);
    
  475.       act(() =>
    
  476.         legacyRender(
    
  477.           <Wrapper
    
  478.             suspendParent={false}
    
  479.             suspendFirst={true}
    
  480.             suspendSecond={false}
    
  481.           />,
    
  482.           container,
    
  483.         ),
    
  484.       );
    
  485.       expect(store).toMatchInlineSnapshot(`
    
  486.         [root]
    
  487.           ▾ <Wrapper>
    
  488.               <Component key="Outside">
    
  489.             ▾ <Suspense>
    
  490.                 <Component key="Unrelated at Start">
    
  491.               ▾ <Suspense>
    
  492.                   <Loading key="Suspense 1 Fallback">
    
  493.               ▾ <Suspense>
    
  494.                   <Component key="Suspense 2 Content">
    
  495.               ▾ <Suspense>
    
  496.                   <Loading key="Suspense 3 Fallback">
    
  497.                 <Component key="Unrelated at End">
    
  498.       `);
    
  499.       act(() =>
    
  500.         legacyRender(
    
  501.           <Wrapper
    
  502.             suspendParent={true}
    
  503.             suspendFirst={true}
    
  504.             suspendSecond={false}
    
  505.           />,
    
  506.           container,
    
  507.         ),
    
  508.       );
    
  509.       expect(store).toMatchInlineSnapshot(`
    
  510.         [root]
    
  511.           ▾ <Wrapper>
    
  512.               <Component key="Outside">
    
  513.             ▾ <Suspense>
    
  514.                 <Loading key="Parent Fallback">
    
  515.       `);
    
  516.       act(() =>
    
  517.         legacyRender(
    
  518.           <Wrapper
    
  519.             suspendParent={false}
    
  520.             suspendFirst={true}
    
  521.             suspendSecond={true}
    
  522.           />,
    
  523.           container,
    
  524.         ),
    
  525.       );
    
  526.       expect(store).toMatchInlineSnapshot(`
    
  527.         [root]
    
  528.           ▾ <Wrapper>
    
  529.               <Component key="Outside">
    
  530.             ▾ <Suspense>
    
  531.                 <Component key="Unrelated at Start">
    
  532.               ▾ <Suspense>
    
  533.                   <Loading key="Suspense 1 Fallback">
    
  534.               ▾ <Suspense>
    
  535.                   <Loading key="Suspense 2 Fallback">
    
  536.               ▾ <Suspense>
    
  537.                   <Loading key="Suspense 3 Fallback">
    
  538.                 <Component key="Unrelated at End">
    
  539.       `);
    
  540.       act(() =>
    
  541.         legacyRender(
    
  542.           <Wrapper
    
  543.             suspendParent={false}
    
  544.             suspendFirst={false}
    
  545.             suspendSecond={false}
    
  546.           />,
    
  547.           container,
    
  548.         ),
    
  549.       );
    
  550.       expect(store).toMatchInlineSnapshot(`
    
  551.         [root]
    
  552.           ▾ <Wrapper>
    
  553.               <Component key="Outside">
    
  554.             ▾ <Suspense>
    
  555.                 <Component key="Unrelated at Start">
    
  556.               ▾ <Suspense>
    
  557.                   <Component key="Suspense 1 Content">
    
  558.               ▾ <Suspense>
    
  559.                   <Component key="Suspense 2 Content">
    
  560.               ▾ <Suspense>
    
  561.                   <Loading key="Suspense 3 Fallback">
    
  562.                 <Component key="Unrelated at End">
    
  563.       `);
    
  564. 
    
  565.       const rendererID = getRendererID();
    
  566.       act(() =>
    
  567.         agent.overrideSuspense({
    
  568.           id: store.getElementIDAtIndex(4),
    
  569.           rendererID,
    
  570.           forceFallback: true,
    
  571.         }),
    
  572.       );
    
  573.       expect(store).toMatchInlineSnapshot(`
    
  574.         [root]
    
  575.           ▾ <Wrapper>
    
  576.               <Component key="Outside">
    
  577.             ▾ <Suspense>
    
  578.                 <Component key="Unrelated at Start">
    
  579.               ▾ <Suspense>
    
  580.                   <Loading key="Suspense 1 Fallback">
    
  581.               ▾ <Suspense>
    
  582.                   <Component key="Suspense 2 Content">
    
  583.               ▾ <Suspense>
    
  584.                   <Loading key="Suspense 3 Fallback">
    
  585.                 <Component key="Unrelated at End">
    
  586.       `);
    
  587.       act(() =>
    
  588.         agent.overrideSuspense({
    
  589.           id: store.getElementIDAtIndex(2),
    
  590.           rendererID,
    
  591.           forceFallback: true,
    
  592.         }),
    
  593.       );
    
  594.       expect(store).toMatchInlineSnapshot(`
    
  595.         [root]
    
  596.           ▾ <Wrapper>
    
  597.               <Component key="Outside">
    
  598.             ▾ <Suspense>
    
  599.                 <Loading key="Parent Fallback">
    
  600.       `);
    
  601.       act(() =>
    
  602.         legacyRender(
    
  603.           <Wrapper
    
  604.             suspendParent={false}
    
  605.             suspendFirst={true}
    
  606.             suspendSecond={true}
    
  607.           />,
    
  608.           container,
    
  609.         ),
    
  610.       );
    
  611.       expect(store).toMatchInlineSnapshot(`
    
  612.         [root]
    
  613.           ▾ <Wrapper>
    
  614.               <Component key="Outside">
    
  615.             ▾ <Suspense>
    
  616.                 <Loading key="Parent Fallback">
    
  617.       `);
    
  618.       act(() =>
    
  619.         agent.overrideSuspense({
    
  620.           id: store.getElementIDAtIndex(2),
    
  621.           rendererID,
    
  622.           forceFallback: false,
    
  623.         }),
    
  624.       );
    
  625.       expect(store).toMatchInlineSnapshot(`
    
  626.         [root]
    
  627.           ▾ <Wrapper>
    
  628.               <Component key="Outside">
    
  629.             ▾ <Suspense>
    
  630.                 <Component key="Unrelated at Start">
    
  631.               ▾ <Suspense>
    
  632.                   <Loading key="Suspense 1 Fallback">
    
  633.               ▾ <Suspense>
    
  634.                   <Loading key="Suspense 2 Fallback">
    
  635.               ▾ <Suspense>
    
  636.                   <Loading key="Suspense 3 Fallback">
    
  637.                 <Component key="Unrelated at End">
    
  638.       `);
    
  639.       act(() =>
    
  640.         agent.overrideSuspense({
    
  641.           id: store.getElementIDAtIndex(4),
    
  642.           rendererID,
    
  643.           forceFallback: false,
    
  644.         }),
    
  645.       );
    
  646.       expect(store).toMatchInlineSnapshot(`
    
  647.         [root]
    
  648.           ▾ <Wrapper>
    
  649.               <Component key="Outside">
    
  650.             ▾ <Suspense>
    
  651.                 <Component key="Unrelated at Start">
    
  652.               ▾ <Suspense>
    
  653.                   <Loading key="Suspense 1 Fallback">
    
  654.               ▾ <Suspense>
    
  655.                   <Loading key="Suspense 2 Fallback">
    
  656.               ▾ <Suspense>
    
  657.                   <Loading key="Suspense 3 Fallback">
    
  658.                 <Component key="Unrelated at End">
    
  659.       `);
    
  660.       act(() =>
    
  661.         legacyRender(
    
  662.           <Wrapper
    
  663.             suspendParent={false}
    
  664.             suspendFirst={false}
    
  665.             suspendSecond={false}
    
  666.           />,
    
  667.           container,
    
  668.         ),
    
  669.       );
    
  670.       expect(store).toMatchInlineSnapshot(`
    
  671.         [root]
    
  672.           ▾ <Wrapper>
    
  673.               <Component key="Outside">
    
  674.             ▾ <Suspense>
    
  675.                 <Component key="Unrelated at Start">
    
  676.               ▾ <Suspense>
    
  677.                   <Component key="Suspense 1 Content">
    
  678.               ▾ <Suspense>
    
  679.                   <Component key="Suspense 2 Content">
    
  680.               ▾ <Suspense>
    
  681.                   <Loading key="Suspense 3 Fallback">
    
  682.                 <Component key="Unrelated at End">
    
  683.       `);
    
  684.     });
    
  685. 
    
  686.     it('should display a partially rendered SuspenseList', () => {
    
  687.       const Loading = () => <div>Loading...</div>;
    
  688.       const SuspendingComponent = () => {
    
  689.         throw new Promise(() => {});
    
  690.       };
    
  691.       const Component = () => {
    
  692.         return <div>Hello</div>;
    
  693.       };
    
  694.       const Wrapper = ({shouldSuspense}) => (
    
  695.         <React.Fragment>
    
  696.           <React.unstable_SuspenseList revealOrder="forwards" tail="collapsed">
    
  697.             <Component key="A" />
    
  698.             <React.Suspense fallback={<Loading />}>
    
  699.               {shouldSuspense ? <SuspendingComponent /> : <Component key="B" />}
    
  700.             </React.Suspense>
    
  701.             <Component key="C" />
    
  702.           </React.unstable_SuspenseList>
    
  703.         </React.Fragment>
    
  704.       );
    
  705. 
    
  706.       const container = document.createElement('div');
    
  707.       const root = ReactDOMClient.createRoot(container);
    
  708.       act(() => {
    
  709.         root.render(<Wrapper shouldSuspense={true} />);
    
  710.       });
    
  711.       expect(store).toMatchInlineSnapshot(`
    
  712.         [root]
    
  713.           ▾ <Wrapper>
    
  714.             ▾ <SuspenseList>
    
  715.                 <Component key="A">
    
  716.               ▾ <Suspense>
    
  717.                   <Loading>
    
  718.       `);
    
  719. 
    
  720.       act(() => {
    
  721.         root.render(<Wrapper shouldSuspense={false} />);
    
  722.       });
    
  723.       expect(store).toMatchInlineSnapshot(`
    
  724.         [root]
    
  725.           ▾ <Wrapper>
    
  726.             ▾ <SuspenseList>
    
  727.                 <Component key="A">
    
  728.               ▾ <Suspense>
    
  729.                   <Component key="B">
    
  730.                 <Component key="C">
    
  731.       `);
    
  732.     });
    
  733. 
    
  734.     // @reactVersion >= 18.0
    
  735.     it('should support collapsing parts of the tree', () => {
    
  736.       const Grandparent = ({count}) => (
    
  737.         <React.Fragment>
    
  738.           <Parent count={count} />
    
  739.           <Parent count={count} />
    
  740.         </React.Fragment>
    
  741.       );
    
  742.       const Parent = ({count}) =>
    
  743.         new Array(count).fill(true).map((_, index) => <Child key={index} />);
    
  744.       const Child = () => <div>Hi!</div>;
    
  745. 
    
  746.       act(() =>
    
  747.         legacyRender(<Grandparent count={2} />, document.createElement('div')),
    
  748.       );
    
  749.       expect(store).toMatchInlineSnapshot(`
    
  750.         [root]
    
  751.           ▾ <Grandparent>
    
  752.             ▾ <Parent>
    
  753.                 <Child key="0">
    
  754.                 <Child key="1">
    
  755.             ▾ <Parent>
    
  756.                 <Child key="0">
    
  757.                 <Child key="1">
    
  758.       `);
    
  759. 
    
  760.       const grandparentID = store.getElementIDAtIndex(0);
    
  761.       const parentOneID = store.getElementIDAtIndex(1);
    
  762.       const parentTwoID = store.getElementIDAtIndex(4);
    
  763. 
    
  764.       act(() => store.toggleIsCollapsed(parentOneID, true));
    
  765.       expect(store).toMatchInlineSnapshot(`
    
  766.         [root]
    
  767.           ▾ <Grandparent>
    
  768.             ▸ <Parent>
    
  769.             ▾ <Parent>
    
  770.                 <Child key="0">
    
  771.                 <Child key="1">
    
  772.       `);
    
  773. 
    
  774.       act(() => store.toggleIsCollapsed(parentTwoID, true));
    
  775.       expect(store).toMatchInlineSnapshot(`
    
  776.         [root]
    
  777.           ▾ <Grandparent>
    
  778.             ▸ <Parent>
    
  779.             ▸ <Parent>
    
  780.       `);
    
  781. 
    
  782.       act(() => store.toggleIsCollapsed(parentOneID, false));
    
  783.       expect(store).toMatchInlineSnapshot(`
    
  784.         [root]
    
  785.           ▾ <Grandparent>
    
  786.             ▾ <Parent>
    
  787.                 <Child key="0">
    
  788.                 <Child key="1">
    
  789.             ▸ <Parent>
    
  790.       `);
    
  791. 
    
  792.       act(() => store.toggleIsCollapsed(grandparentID, true));
    
  793.       expect(store).toMatchInlineSnapshot(`
    
  794.         [root]
    
  795.           ▸ <Grandparent>
    
  796.       `);
    
  797. 
    
  798.       act(() => store.toggleIsCollapsed(grandparentID, false));
    
  799.       expect(store).toMatchInlineSnapshot(`
    
  800.         [root]
    
  801.           ▾ <Grandparent>
    
  802.             ▾ <Parent>
    
  803.                 <Child key="0">
    
  804.                 <Child key="1">
    
  805.             ▸ <Parent>
    
  806.       `);
    
  807.     });
    
  808. 
    
  809.     // @reactVersion >= 18.0
    
  810.     it('should support reordering of children', () => {
    
  811.       const Root = ({children}) => children;
    
  812.       const Component = () => null;
    
  813. 
    
  814.       const Foo = () => [<Component key="0" />];
    
  815.       const Bar = () => [<Component key="0" />, <Component key="1" />];
    
  816.       const foo = <Foo key="foo" />;
    
  817.       const bar = <Bar key="bar" />;
    
  818. 
    
  819.       const container = document.createElement('div');
    
  820. 
    
  821.       act(() => legacyRender(<Root>{[foo, bar]}</Root>, container));
    
  822.       expect(store).toMatchInlineSnapshot(`
    
  823.         [root]
    
  824.           ▾ <Root>
    
  825.             ▾ <Foo key="foo">
    
  826.                 <Component key="0">
    
  827.             ▾ <Bar key="bar">
    
  828.                 <Component key="0">
    
  829.                 <Component key="1">
    
  830.       `);
    
  831. 
    
  832.       act(() => legacyRender(<Root>{[bar, foo]}</Root>, container));
    
  833.       expect(store).toMatchInlineSnapshot(`
    
  834.         [root]
    
  835.           ▾ <Root>
    
  836.             ▾ <Bar key="bar">
    
  837.                 <Component key="0">
    
  838.                 <Component key="1">
    
  839.             ▾ <Foo key="foo">
    
  840.                 <Component key="0">
    
  841.       `);
    
  842. 
    
  843.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), true));
    
  844.       expect(store).toMatchInlineSnapshot(`
    
  845.         [root]
    
  846.           ▸ <Root>
    
  847.       `);
    
  848. 
    
  849.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
    
  850.       expect(store).toMatchInlineSnapshot(`
    
  851.         [root]
    
  852.           ▾ <Root>
    
  853.             ▾ <Bar key="bar">
    
  854.                 <Component key="0">
    
  855.                 <Component key="1">
    
  856.             ▾ <Foo key="foo">
    
  857.                 <Component key="0">
    
  858.       `);
    
  859.     });
    
  860.   });
    
  861. 
    
  862.   describe('collapseNodesByDefault:true', () => {
    
  863.     beforeEach(() => {
    
  864.       store.collapseNodesByDefault = true;
    
  865.     });
    
  866. 
    
  867.     // @reactVersion >= 18.0
    
  868.     it('should support mount and update operations', () => {
    
  869.       const Parent = ({count}) =>
    
  870.         new Array(count).fill(true).map((_, index) => <Child key={index} />);
    
  871.       const Child = () => <div>Hi!</div>;
    
  872. 
    
  873.       const container = document.createElement('div');
    
  874. 
    
  875.       act(() =>
    
  876.         legacyRender(
    
  877.           <React.Fragment>
    
  878.             <Parent count={1} />
    
  879.             <Parent count={3} />
    
  880.           </React.Fragment>,
    
  881.           container,
    
  882.         ),
    
  883.       );
    
  884.       expect(store).toMatchInlineSnapshot(`
    
  885.         [root]
    
  886.           ▸ <Parent>
    
  887.           ▸ <Parent>
    
  888.       `);
    
  889. 
    
  890.       act(() =>
    
  891.         legacyRender(
    
  892.           <React.Fragment>
    
  893.             <Parent count={2} />
    
  894.             <Parent count={1} />
    
  895.           </React.Fragment>,
    
  896.           container,
    
  897.         ),
    
  898.       );
    
  899.       expect(store).toMatchInlineSnapshot(`
    
  900.         [root]
    
  901.           ▸ <Parent>
    
  902.           ▸ <Parent>
    
  903.       `);
    
  904. 
    
  905.       act(() => ReactDOM.unmountComponentAtNode(container));
    
  906.       expect(store).toMatchInlineSnapshot(``);
    
  907.     });
    
  908. 
    
  909.     // @reactVersion >= 18.0
    
  910.     it('should support mount and update operations for multiple roots', () => {
    
  911.       const Parent = ({count}) =>
    
  912.         new Array(count).fill(true).map((_, index) => <Child key={index} />);
    
  913.       const Child = () => <div>Hi!</div>;
    
  914. 
    
  915.       const containerA = document.createElement('div');
    
  916.       const containerB = document.createElement('div');
    
  917. 
    
  918.       act(() => {
    
  919.         legacyRender(<Parent key="A" count={3} />, containerA);
    
  920.         legacyRender(<Parent key="B" count={2} />, containerB);
    
  921.       });
    
  922.       expect(store).toMatchInlineSnapshot(`
    
  923.         [root]
    
  924.           ▸ <Parent key="A">
    
  925.         [root]
    
  926.           ▸ <Parent key="B">
    
  927.       `);
    
  928. 
    
  929.       act(() => {
    
  930.         legacyRender(<Parent key="A" count={4} />, containerA);
    
  931.         legacyRender(<Parent key="B" count={1} />, containerB);
    
  932.       });
    
  933.       expect(store).toMatchInlineSnapshot(`
    
  934.         [root]
    
  935.           ▸ <Parent key="A">
    
  936.         [root]
    
  937.           ▸ <Parent key="B">
    
  938.       `);
    
  939. 
    
  940.       act(() => ReactDOM.unmountComponentAtNode(containerB));
    
  941.       expect(store).toMatchInlineSnapshot(`
    
  942.         [root]
    
  943.           ▸ <Parent key="A">
    
  944.       `);
    
  945. 
    
  946.       act(() => ReactDOM.unmountComponentAtNode(containerA));
    
  947.       expect(store).toMatchInlineSnapshot(``);
    
  948.     });
    
  949. 
    
  950.     // @reactVersion >= 18.0
    
  951.     it('should filter DOM nodes from the store tree', () => {
    
  952.       const Grandparent = () => (
    
  953.         <div>
    
  954.           <div>
    
  955.             <Parent />
    
  956.           </div>
    
  957.           <Parent />
    
  958.         </div>
    
  959.       );
    
  960.       const Parent = () => (
    
  961.         <div>
    
  962.           <Child />
    
  963.         </div>
    
  964.       );
    
  965.       const Child = () => <div>Hi!</div>;
    
  966. 
    
  967.       act(() =>
    
  968.         legacyRender(<Grandparent count={4} />, document.createElement('div')),
    
  969.       );
    
  970.       expect(store).toMatchInlineSnapshot(`
    
  971.         [root]
    
  972.           ▸ <Grandparent>
    
  973.       `);
    
  974. 
    
  975.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
    
  976.       expect(store).toMatchInlineSnapshot(`
    
  977.         [root]
    
  978.           ▾ <Grandparent>
    
  979.             ▸ <Parent>
    
  980.             ▸ <Parent>
    
  981.       `);
    
  982. 
    
  983.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(1), false));
    
  984.       expect(store).toMatchInlineSnapshot(`
    
  985.         [root]
    
  986.           ▾ <Grandparent>
    
  987.             ▾ <Parent>
    
  988.                 <Child>
    
  989.             ▸ <Parent>
    
  990.       `);
    
  991.     });
    
  992. 
    
  993.     // @reactVersion >= 18.0
    
  994.     it('should display Suspense nodes properly in various states', () => {
    
  995.       const Loading = () => <div>Loading...</div>;
    
  996.       const SuspendingComponent = () => {
    
  997.         throw new Promise(() => {});
    
  998.       };
    
  999.       const Component = () => {
    
  1000.         return <div>Hello</div>;
    
  1001.       };
    
  1002.       const Wrapper = ({shouldSuspense}) => (
    
  1003.         <React.Fragment>
    
  1004.           <Component key="Outside" />
    
  1005.           <React.Suspense fallback={<Loading />}>
    
  1006.             {shouldSuspense ? (
    
  1007.               <SuspendingComponent />
    
  1008.             ) : (
    
  1009.               <Component key="Inside" />
    
  1010.             )}
    
  1011.           </React.Suspense>
    
  1012.         </React.Fragment>
    
  1013.       );
    
  1014. 
    
  1015.       const container = document.createElement('div');
    
  1016.       act(() => legacyRender(<Wrapper shouldSuspense={true} />, container));
    
  1017.       expect(store).toMatchInlineSnapshot(`
    
  1018.         [root]
    
  1019.           ▸ <Wrapper>
    
  1020.       `);
    
  1021. 
    
  1022.       // This test isn't meaningful unless we expand the suspended tree
    
  1023.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
    
  1024.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(2), false));
    
  1025.       expect(store).toMatchInlineSnapshot(`
    
  1026.         [root]
    
  1027.           ▾ <Wrapper>
    
  1028.               <Component key="Outside">
    
  1029.             ▾ <Suspense>
    
  1030.                 <Loading>
    
  1031.       `);
    
  1032. 
    
  1033.       act(() => {
    
  1034.         legacyRender(<Wrapper shouldSuspense={false} />, container);
    
  1035.       });
    
  1036.       expect(store).toMatchInlineSnapshot(`
    
  1037.         [root]
    
  1038.           ▾ <Wrapper>
    
  1039.               <Component key="Outside">
    
  1040.             ▾ <Suspense>
    
  1041.                 <Component key="Inside">
    
  1042.       `);
    
  1043.     });
    
  1044. 
    
  1045.     // @reactVersion >= 18.0
    
  1046.     it('should support expanding parts of the tree', () => {
    
  1047.       const Grandparent = ({count}) => (
    
  1048.         <React.Fragment>
    
  1049.           <Parent count={count} />
    
  1050.           <Parent count={count} />
    
  1051.         </React.Fragment>
    
  1052.       );
    
  1053.       const Parent = ({count}) =>
    
  1054.         new Array(count).fill(true).map((_, index) => <Child key={index} />);
    
  1055.       const Child = () => <div>Hi!</div>;
    
  1056. 
    
  1057.       act(() =>
    
  1058.         legacyRender(<Grandparent count={2} />, document.createElement('div')),
    
  1059.       );
    
  1060.       expect(store).toMatchInlineSnapshot(`
    
  1061.         [root]
    
  1062.           ▸ <Grandparent>
    
  1063.       `);
    
  1064. 
    
  1065.       const grandparentID = store.getElementIDAtIndex(0);
    
  1066. 
    
  1067.       act(() => store.toggleIsCollapsed(grandparentID, false));
    
  1068.       expect(store).toMatchInlineSnapshot(`
    
  1069.         [root]
    
  1070.           ▾ <Grandparent>
    
  1071.             ▸ <Parent>
    
  1072.             ▸ <Parent>
    
  1073.       `);
    
  1074. 
    
  1075.       const parentOneID = store.getElementIDAtIndex(1);
    
  1076.       const parentTwoID = store.getElementIDAtIndex(2);
    
  1077. 
    
  1078.       act(() => store.toggleIsCollapsed(parentOneID, false));
    
  1079.       expect(store).toMatchInlineSnapshot(`
    
  1080.         [root]
    
  1081.           ▾ <Grandparent>
    
  1082.             ▾ <Parent>
    
  1083.                 <Child key="0">
    
  1084.                 <Child key="1">
    
  1085.             ▸ <Parent>
    
  1086.       `);
    
  1087. 
    
  1088.       act(() => store.toggleIsCollapsed(parentTwoID, false));
    
  1089.       expect(store).toMatchInlineSnapshot(`
    
  1090.         [root]
    
  1091.           ▾ <Grandparent>
    
  1092.             ▾ <Parent>
    
  1093.                 <Child key="0">
    
  1094.                 <Child key="1">
    
  1095.             ▾ <Parent>
    
  1096.                 <Child key="0">
    
  1097.                 <Child key="1">
    
  1098.       `);
    
  1099. 
    
  1100.       act(() => store.toggleIsCollapsed(parentOneID, true));
    
  1101.       expect(store).toMatchInlineSnapshot(`
    
  1102.         [root]
    
  1103.           ▾ <Grandparent>
    
  1104.             ▸ <Parent>
    
  1105.             ▾ <Parent>
    
  1106.                 <Child key="0">
    
  1107.                 <Child key="1">
    
  1108.       `);
    
  1109. 
    
  1110.       act(() => store.toggleIsCollapsed(parentTwoID, true));
    
  1111.       expect(store).toMatchInlineSnapshot(`
    
  1112.         [root]
    
  1113.           ▾ <Grandparent>
    
  1114.             ▸ <Parent>
    
  1115.             ▸ <Parent>
    
  1116.       `);
    
  1117. 
    
  1118.       act(() => store.toggleIsCollapsed(grandparentID, true));
    
  1119.       expect(store).toMatchInlineSnapshot(`
    
  1120.         [root]
    
  1121.           ▸ <Grandparent>
    
  1122.       `);
    
  1123.     });
    
  1124. 
    
  1125.     // @reactVersion >= 18.0
    
  1126.     it('should support expanding deep parts of the tree', () => {
    
  1127.       const Wrapper = ({forwardedRef}) => (
    
  1128.         <Nested depth={3} forwardedRef={forwardedRef} />
    
  1129.       );
    
  1130.       const Nested = ({depth, forwardedRef}) =>
    
  1131.         depth > 0 ? (
    
  1132.           <Nested depth={depth - 1} forwardedRef={forwardedRef} />
    
  1133.         ) : (
    
  1134.           <div ref={forwardedRef} />
    
  1135.         );
    
  1136. 
    
  1137.       const ref = React.createRef();
    
  1138. 
    
  1139.       act(() =>
    
  1140.         legacyRender(
    
  1141.           <Wrapper forwardedRef={ref} />,
    
  1142.           document.createElement('div'),
    
  1143.         ),
    
  1144.       );
    
  1145.       expect(store).toMatchInlineSnapshot(`
    
  1146.         [root]
    
  1147.           ▸ <Wrapper>
    
  1148.       `);
    
  1149. 
    
  1150.       const deepestedNodeID = agent.getIDForNode(ref.current);
    
  1151. 
    
  1152.       act(() => store.toggleIsCollapsed(deepestedNodeID, false));
    
  1153.       expect(store).toMatchInlineSnapshot(`
    
  1154.         [root]
    
  1155.           ▾ <Wrapper>
    
  1156.             ▾ <Nested>
    
  1157.               ▾ <Nested>
    
  1158.                 ▾ <Nested>
    
  1159.                     <Nested>
    
  1160.       `);
    
  1161. 
    
  1162.       const rootID = store.getElementIDAtIndex(0);
    
  1163. 
    
  1164.       act(() => store.toggleIsCollapsed(rootID, true));
    
  1165.       expect(store).toMatchInlineSnapshot(`
    
  1166.         [root]
    
  1167.           ▸ <Wrapper>
    
  1168.       `);
    
  1169. 
    
  1170.       act(() => store.toggleIsCollapsed(rootID, false));
    
  1171.       expect(store).toMatchInlineSnapshot(`
    
  1172.         [root]
    
  1173.           ▾ <Wrapper>
    
  1174.             ▾ <Nested>
    
  1175.               ▾ <Nested>
    
  1176.                 ▾ <Nested>
    
  1177.                     <Nested>
    
  1178.       `);
    
  1179. 
    
  1180.       const id = store.getElementIDAtIndex(1);
    
  1181. 
    
  1182.       act(() => store.toggleIsCollapsed(id, true));
    
  1183.       expect(store).toMatchInlineSnapshot(`
    
  1184.         [root]
    
  1185.           ▾ <Wrapper>
    
  1186.             ▸ <Nested>
    
  1187.       `);
    
  1188. 
    
  1189.       act(() => store.toggleIsCollapsed(id, false));
    
  1190.       expect(store).toMatchInlineSnapshot(`
    
  1191.         [root]
    
  1192.           ▾ <Wrapper>
    
  1193.             ▾ <Nested>
    
  1194.               ▾ <Nested>
    
  1195.                 ▾ <Nested>
    
  1196.                     <Nested>
    
  1197.       `);
    
  1198.     });
    
  1199. 
    
  1200.     // @reactVersion >= 18.0
    
  1201.     it('should support reordering of children', () => {
    
  1202.       const Root = ({children}) => children;
    
  1203.       const Component = () => null;
    
  1204. 
    
  1205.       const Foo = () => [<Component key="0" />];
    
  1206.       const Bar = () => [<Component key="0" />, <Component key="1" />];
    
  1207.       const foo = <Foo key="foo" />;
    
  1208.       const bar = <Bar key="bar" />;
    
  1209. 
    
  1210.       const container = document.createElement('div');
    
  1211. 
    
  1212.       act(() => legacyRender(<Root>{[foo, bar]}</Root>, container));
    
  1213.       expect(store).toMatchInlineSnapshot(`
    
  1214.         [root]
    
  1215.           ▸ <Root>
    
  1216.       `);
    
  1217. 
    
  1218.       act(() => legacyRender(<Root>{[bar, foo]}</Root>, container));
    
  1219.       expect(store).toMatchInlineSnapshot(`
    
  1220.         [root]
    
  1221.           ▸ <Root>
    
  1222.       `);
    
  1223. 
    
  1224.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
    
  1225.       expect(store).toMatchInlineSnapshot(`
    
  1226.         [root]
    
  1227.           ▾ <Root>
    
  1228.             ▸ <Bar key="bar">
    
  1229.             ▸ <Foo key="foo">
    
  1230.       `);
    
  1231. 
    
  1232.       act(() => {
    
  1233.         store.toggleIsCollapsed(store.getElementIDAtIndex(2), false);
    
  1234.         store.toggleIsCollapsed(store.getElementIDAtIndex(1), false);
    
  1235.       });
    
  1236.       expect(store).toMatchInlineSnapshot(`
    
  1237.         [root]
    
  1238.           ▾ <Root>
    
  1239.             ▾ <Bar key="bar">
    
  1240.                 <Component key="0">
    
  1241.                 <Component key="1">
    
  1242.             ▾ <Foo key="foo">
    
  1243.                 <Component key="0">
    
  1244.       `);
    
  1245. 
    
  1246.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), true));
    
  1247.       expect(store).toMatchInlineSnapshot(`
    
  1248.         [root]
    
  1249.           ▸ <Root>
    
  1250.       `);
    
  1251.     });
    
  1252. 
    
  1253.     // @reactVersion >= 18.0
    
  1254.     it('should not add new nodes when suspense is toggled', () => {
    
  1255.       const SuspenseTree = () => {
    
  1256.         return (
    
  1257.           <React.Suspense fallback={<Fallback>Loading outer</Fallback>}>
    
  1258.             <Parent />
    
  1259.           </React.Suspense>
    
  1260.         );
    
  1261.       };
    
  1262. 
    
  1263.       const Fallback = () => null;
    
  1264.       const Parent = () => <Child />;
    
  1265.       const Child = () => null;
    
  1266. 
    
  1267.       act(() => legacyRender(<SuspenseTree />, document.createElement('div')));
    
  1268.       expect(store).toMatchInlineSnapshot(`
    
  1269.         [root]
    
  1270.           ▸ <SuspenseTree>
    
  1271.       `);
    
  1272. 
    
  1273.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(0), false));
    
  1274.       act(() => store.toggleIsCollapsed(store.getElementIDAtIndex(1), false));
    
  1275.       expect(store).toMatchInlineSnapshot(`
    
  1276.         [root]
    
  1277.           ▾ <SuspenseTree>
    
  1278.             ▾ <Suspense>
    
  1279.               ▸ <Parent>
    
  1280.       `);
    
  1281. 
    
  1282.       const rendererID = getRendererID();
    
  1283.       const suspenseID = store.getElementIDAtIndex(1);
    
  1284. 
    
  1285.       act(() =>
    
  1286.         agent.overrideSuspense({
    
  1287.           id: suspenseID,
    
  1288.           rendererID,
    
  1289.           forceFallback: true,
    
  1290.         }),
    
  1291.       );
    
  1292.       expect(store).toMatchInlineSnapshot(`
    
  1293.         [root]
    
  1294.           ▾ <SuspenseTree>
    
  1295.             ▾ <Suspense>
    
  1296.                 <Fallback>
    
  1297.       `);
    
  1298. 
    
  1299.       act(() =>
    
  1300.         agent.overrideSuspense({
    
  1301.           id: suspenseID,
    
  1302.           rendererID,
    
  1303.           forceFallback: false,
    
  1304.         }),
    
  1305.       );
    
  1306.       expect(store).toMatchInlineSnapshot(`
    
  1307.         [root]
    
  1308.           ▾ <SuspenseTree>
    
  1309.             ▾ <Suspense>
    
  1310.               ▸ <Parent>
    
  1311.       `);
    
  1312.     });
    
  1313.   });
    
  1314. 
    
  1315.   describe('getIndexOfElementID', () => {
    
  1316.     beforeEach(() => {
    
  1317.       store.collapseNodesByDefault = false;
    
  1318.     });
    
  1319. 
    
  1320.     // @reactVersion >= 18.0
    
  1321.     it('should support a single root with a single child', () => {
    
  1322.       const Grandparent = () => (
    
  1323.         <React.Fragment>
    
  1324.           <Parent />
    
  1325.           <Parent />
    
  1326.         </React.Fragment>
    
  1327.       );
    
  1328.       const Parent = () => <Child />;
    
  1329.       const Child = () => null;
    
  1330. 
    
  1331.       act(() => legacyRender(<Grandparent />, document.createElement('div')));
    
  1332. 
    
  1333.       for (let i = 0; i < store.numElements; i++) {
    
  1334.         expect(store.getIndexOfElementID(store.getElementIDAtIndex(i))).toBe(i);
    
  1335.       }
    
  1336.     });
    
  1337. 
    
  1338.     // @reactVersion >= 18.0
    
  1339.     it('should support multiple roots with one children each', () => {
    
  1340.       const Grandparent = () => <Parent />;
    
  1341.       const Parent = () => <Child />;
    
  1342.       const Child = () => null;
    
  1343. 
    
  1344.       act(() => {
    
  1345.         legacyRender(<Grandparent />, document.createElement('div'));
    
  1346.         legacyRender(<Grandparent />, document.createElement('div'));
    
  1347.       });
    
  1348. 
    
  1349.       for (let i = 0; i < store.numElements; i++) {
    
  1350.         expect(store.getIndexOfElementID(store.getElementIDAtIndex(i))).toBe(i);
    
  1351.       }
    
  1352.     });
    
  1353. 
    
  1354.     // @reactVersion >= 18.0
    
  1355.     it('should support a single root with multiple top level children', () => {
    
  1356.       const Grandparent = () => <Parent />;
    
  1357.       const Parent = () => <Child />;
    
  1358.       const Child = () => null;
    
  1359. 
    
  1360.       act(() =>
    
  1361.         legacyRender(
    
  1362.           <React.Fragment>
    
  1363.             <Grandparent />
    
  1364.             <Grandparent />
    
  1365.           </React.Fragment>,
    
  1366.           document.createElement('div'),
    
  1367.         ),
    
  1368.       );
    
  1369. 
    
  1370.       for (let i = 0; i < store.numElements; i++) {
    
  1371.         expect(store.getIndexOfElementID(store.getElementIDAtIndex(i))).toBe(i);
    
  1372.       }
    
  1373.     });
    
  1374. 
    
  1375.     // @reactVersion >= 18.0
    
  1376.     it('should support multiple roots with multiple top level children', () => {
    
  1377.       const Grandparent = () => <Parent />;
    
  1378.       const Parent = () => <Child />;
    
  1379.       const Child = () => null;
    
  1380. 
    
  1381.       act(() => {
    
  1382.         legacyRender(
    
  1383.           <React.Fragment>
    
  1384.             <Grandparent />
    
  1385.             <Grandparent />
    
  1386.           </React.Fragment>,
    
  1387.           document.createElement('div'),
    
  1388.         );
    
  1389.         legacyRender(
    
  1390.           <React.Fragment>
    
  1391.             <Grandparent />
    
  1392.             <Grandparent />
    
  1393.           </React.Fragment>,
    
  1394.           document.createElement('div'),
    
  1395.         );
    
  1396.       });
    
  1397. 
    
  1398.       for (let i = 0; i < store.numElements; i++) {
    
  1399.         expect(store.getIndexOfElementID(store.getElementIDAtIndex(i))).toBe(i);
    
  1400.       }
    
  1401.     });
    
  1402.   });
    
  1403. 
    
  1404.   // @reactVersion >= 18.0
    
  1405.   it('detects and updates profiling support based on the attached roots', () => {
    
  1406.     const Component = () => null;
    
  1407. 
    
  1408.     const containerA = document.createElement('div');
    
  1409.     const containerB = document.createElement('div');
    
  1410. 
    
  1411.     expect(store.rootSupportsBasicProfiling).toBe(false);
    
  1412. 
    
  1413.     act(() => legacyRender(<Component />, containerA));
    
  1414.     expect(store.rootSupportsBasicProfiling).toBe(true);
    
  1415. 
    
  1416.     act(() => legacyRender(<Component />, containerB));
    
  1417.     act(() => ReactDOM.unmountComponentAtNode(containerA));
    
  1418.     expect(store.rootSupportsBasicProfiling).toBe(true);
    
  1419. 
    
  1420.     act(() => ReactDOM.unmountComponentAtNode(containerB));
    
  1421.     expect(store.rootSupportsBasicProfiling).toBe(false);
    
  1422.   });
    
  1423. 
    
  1424.   // @reactVersion >= 18.0
    
  1425.   it('should properly serialize non-string key values', () => {
    
  1426.     const Child = () => null;
    
  1427. 
    
  1428.     // Bypass React element's automatic stringifying of keys intentionally.
    
  1429.     // This is pretty hacky.
    
  1430.     const fauxElement = Object.assign({}, <Child />, {key: 123});
    
  1431. 
    
  1432.     act(() => legacyRender([fauxElement], document.createElement('div')));
    
  1433.     expect(store).toMatchInlineSnapshot(`
    
  1434.       [root]
    
  1435.           <Child key="123">
    
  1436.     `);
    
  1437.   });
    
  1438. 
    
  1439.   it('should show the right display names for special component types', async () => {
    
  1440.     const MyComponent = (props, ref) => null;
    
  1441.     const ForwardRefComponent = React.forwardRef(MyComponent);
    
  1442.     const MyComponent2 = (props, ref) => null;
    
  1443.     const ForwardRefComponentWithAnonymousFunction = React.forwardRef(() => (
    
  1444.       <MyComponent2 />
    
  1445.     ));
    
  1446.     const MyComponent3 = (props, ref) => null;
    
  1447.     const ForwardRefComponentWithCustomDisplayName =
    
  1448.       React.forwardRef(MyComponent3);
    
  1449.     ForwardRefComponentWithCustomDisplayName.displayName = 'Custom';
    
  1450.     const MyComponent4 = (props, ref) => null;
    
  1451.     const MemoComponent = React.memo(MyComponent4);
    
  1452.     const MemoForwardRefComponent = React.memo(ForwardRefComponent);
    
  1453. 
    
  1454.     const FakeHigherOrderComponent = () => null;
    
  1455.     FakeHigherOrderComponent.displayName = 'withFoo(withBar(Baz))';
    
  1456. 
    
  1457.     const MemoizedFakeHigherOrderComponent = React.memo(
    
  1458.       FakeHigherOrderComponent,
    
  1459.     );
    
  1460.     const ForwardRefFakeHigherOrderComponent = React.forwardRef(
    
  1461.       FakeHigherOrderComponent,
    
  1462.     );
    
  1463. 
    
  1464.     const MemoizedFakeHigherOrderComponentWithDisplayNameOverride = React.memo(
    
  1465.       FakeHigherOrderComponent,
    
  1466.     );
    
  1467.     MemoizedFakeHigherOrderComponentWithDisplayNameOverride.displayName =
    
  1468.       'memoRefOverride';
    
  1469.     const ForwardRefFakeHigherOrderComponentWithDisplayNameOverride =
    
  1470.       React.forwardRef(FakeHigherOrderComponent);
    
  1471.     ForwardRefFakeHigherOrderComponentWithDisplayNameOverride.displayName =
    
  1472.       'forwardRefOverride';
    
  1473. 
    
  1474.     const App = () => (
    
  1475.       <React.Fragment>
    
  1476.         <MyComponent />
    
  1477.         <ForwardRefComponent />
    
  1478.         <ForwardRefComponentWithAnonymousFunction />
    
  1479.         <ForwardRefComponentWithCustomDisplayName />
    
  1480.         <MemoComponent />
    
  1481.         <MemoForwardRefComponent />
    
  1482.         <FakeHigherOrderComponent />
    
  1483.         <MemoizedFakeHigherOrderComponent />
    
  1484.         <ForwardRefFakeHigherOrderComponent />
    
  1485.         <React.unstable_Cache />
    
  1486.         <MemoizedFakeHigherOrderComponentWithDisplayNameOverride />
    
  1487.         <ForwardRefFakeHigherOrderComponentWithDisplayNameOverride />
    
  1488.       </React.Fragment>
    
  1489.     );
    
  1490. 
    
  1491.     const container = document.createElement('div');
    
  1492. 
    
  1493.     // Render once to start fetching the lazy component
    
  1494.     act(() => legacyRender(<App />, container));
    
  1495. 
    
  1496.     await Promise.resolve();
    
  1497. 
    
  1498.     // Render again after it resolves
    
  1499.     act(() => legacyRender(<App />, container));
    
  1500. 
    
  1501.     expect(store).toMatchInlineSnapshot(`
    
  1502.       [root]
    
  1503.         ▾ <App>
    
  1504.             <MyComponent>
    
  1505.             <MyComponent> [ForwardRef]
    
  1506.           ▾ <Anonymous> [ForwardRef]
    
  1507.               <MyComponent2>
    
  1508.             <Custom>
    
  1509.             <MyComponent4> [Memo]
    
  1510.           ▾ <MyComponent> [Memo]
    
  1511.               <MyComponent> [ForwardRef]
    
  1512.             <Baz> [withFoo][withBar]
    
  1513.             <Baz> [Memo][withFoo][withBar]
    
  1514.             <Baz> [ForwardRef][withFoo][withBar]
    
  1515.             <Cache>
    
  1516.             <memoRefOverride>
    
  1517.             <forwardRefOverride>
    
  1518.     `);
    
  1519.   });
    
  1520. 
    
  1521.   describe('Lazy', () => {
    
  1522.     async function fakeImport(result) {
    
  1523.       return {default: result};
    
  1524.     }
    
  1525. 
    
  1526.     const LazyInnerComponent = () => null;
    
  1527. 
    
  1528.     const App = ({renderChildren}) => {
    
  1529.       if (renderChildren) {
    
  1530.         return (
    
  1531.           <React.Suspense fallback="Loading...">
    
  1532.             <LazyComponent />
    
  1533.           </React.Suspense>
    
  1534.         );
    
  1535.       } else {
    
  1536.         return null;
    
  1537.       }
    
  1538.     };
    
  1539. 
    
  1540.     let LazyComponent;
    
  1541.     beforeEach(() => {
    
  1542.       LazyComponent = React.lazy(() => fakeImport(LazyInnerComponent));
    
  1543.     });
    
  1544. 
    
  1545.     // @reactVersion >= 18.0
    
  1546.     it('should support Lazy components (legacy render)', async () => {
    
  1547.       const container = document.createElement('div');
    
  1548. 
    
  1549.       // Render once to start fetching the lazy component
    
  1550.       act(() => legacyRender(<App renderChildren={true} />, container));
    
  1551. 
    
  1552.       expect(store).toMatchInlineSnapshot(`
    
  1553.         [root]
    
  1554.           ▾ <App>
    
  1555.               <Suspense>
    
  1556.       `);
    
  1557. 
    
  1558.       await Promise.resolve();
    
  1559. 
    
  1560.       // Render again after it resolves
    
  1561.       act(() => legacyRender(<App renderChildren={true} />, container));
    
  1562. 
    
  1563.       expect(store).toMatchInlineSnapshot(`
    
  1564.         [root]
    
  1565.           ▾ <App>
    
  1566.             ▾ <Suspense>
    
  1567.                 <LazyInnerComponent>
    
  1568.       `);
    
  1569. 
    
  1570.       // Render again to unmount it
    
  1571.       act(() => legacyRender(<App renderChildren={false} />, container));
    
  1572. 
    
  1573.       expect(store).toMatchInlineSnapshot(`
    
  1574.         [root]
    
  1575.             <App>
    
  1576.       `);
    
  1577.     });
    
  1578. 
    
  1579.     // @reactVersion >= 18.0
    
  1580.     it('should support Lazy components in (createRoot)', async () => {
    
  1581.       const container = document.createElement('div');
    
  1582.       const root = ReactDOMClient.createRoot(container);
    
  1583. 
    
  1584.       // Render once to start fetching the lazy component
    
  1585.       act(() => root.render(<App renderChildren={true} />));
    
  1586. 
    
  1587.       expect(store).toMatchInlineSnapshot(`
    
  1588.         [root]
    
  1589.           ▾ <App>
    
  1590.               <Suspense>
    
  1591.       `);
    
  1592. 
    
  1593.       await Promise.resolve();
    
  1594. 
    
  1595.       // Render again after it resolves
    
  1596.       act(() => root.render(<App renderChildren={true} />));
    
  1597. 
    
  1598.       expect(store).toMatchInlineSnapshot(`
    
  1599.         [root]
    
  1600.           ▾ <App>
    
  1601.             ▾ <Suspense>
    
  1602.                 <LazyInnerComponent>
    
  1603.       `);
    
  1604. 
    
  1605.       // Render again to unmount it
    
  1606.       act(() => root.render(<App renderChildren={false} />));
    
  1607. 
    
  1608.       expect(store).toMatchInlineSnapshot(`
    
  1609.         [root]
    
  1610.             <App>
    
  1611.       `);
    
  1612.     });
    
  1613. 
    
  1614.     // @reactVersion >= 18.0
    
  1615.     it('should support Lazy components that are unmounted before they finish loading (legacy render)', async () => {
    
  1616.       const container = document.createElement('div');
    
  1617. 
    
  1618.       // Render once to start fetching the lazy component
    
  1619.       act(() => legacyRender(<App renderChildren={true} />, container));
    
  1620. 
    
  1621.       expect(store).toMatchInlineSnapshot(`
    
  1622.         [root]
    
  1623.           ▾ <App>
    
  1624.               <Suspense>
    
  1625.       `);
    
  1626. 
    
  1627.       // Render again to unmount it before it finishes loading
    
  1628.       act(() => legacyRender(<App renderChildren={false} />, container));
    
  1629. 
    
  1630.       expect(store).toMatchInlineSnapshot(`
    
  1631.         [root]
    
  1632.             <App>
    
  1633.       `);
    
  1634.     });
    
  1635. 
    
  1636.     // @reactVersion >= 18.0
    
  1637.     it('should support Lazy components that are unmounted before they finish loading in (createRoot)', async () => {
    
  1638.       const container = document.createElement('div');
    
  1639.       const root = ReactDOMClient.createRoot(container);
    
  1640. 
    
  1641.       // Render once to start fetching the lazy component
    
  1642.       act(() => root.render(<App renderChildren={true} />));
    
  1643. 
    
  1644.       expect(store).toMatchInlineSnapshot(`
    
  1645.         [root]
    
  1646.           ▾ <App>
    
  1647.               <Suspense>
    
  1648.       `);
    
  1649. 
    
  1650.       // Render again to unmount it before it finishes loading
    
  1651.       act(() => root.render(<App renderChildren={false} />));
    
  1652. 
    
  1653.       expect(store).toMatchInlineSnapshot(`
    
  1654.         [root]
    
  1655.             <App>
    
  1656.       `);
    
  1657.     });
    
  1658.   });
    
  1659. 
    
  1660.   describe('inline errors and warnings', () => {
    
  1661.     // @reactVersion >= 18.0
    
  1662.     it('during render are counted', () => {
    
  1663.       function Example() {
    
  1664.         console.error('test-only: render error');
    
  1665.         console.warn('test-only: render warning');
    
  1666.         return null;
    
  1667.       }
    
  1668.       const container = document.createElement('div');
    
  1669. 
    
  1670.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1671.         act(() => legacyRender(<Example />, container));
    
  1672.       });
    
  1673. 
    
  1674.       expect(store).toMatchInlineSnapshot(`
    
  1675.         ✕ 1, ⚠ 1
    
  1676.         [root]
    
  1677.             <Example> ✕⚠
    
  1678.       `);
    
  1679. 
    
  1680.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1681.         act(() => legacyRender(<Example rerender={1} />, container));
    
  1682.       });
    
  1683. 
    
  1684.       expect(store).toMatchInlineSnapshot(`
    
  1685.         ✕ 2, ⚠ 2
    
  1686.         [root]
    
  1687.             <Example> ✕⚠
    
  1688.       `);
    
  1689.     });
    
  1690. 
    
  1691.     // @reactVersion >= 18.0
    
  1692.     it('during layout get counted', () => {
    
  1693.       function Example() {
    
  1694.         React.useLayoutEffect(() => {
    
  1695.           console.error('test-only: layout error');
    
  1696.           console.warn('test-only: layout warning');
    
  1697.         });
    
  1698.         return null;
    
  1699.       }
    
  1700.       const container = document.createElement('div');
    
  1701. 
    
  1702.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1703.         act(() => legacyRender(<Example />, container));
    
  1704.       });
    
  1705. 
    
  1706.       expect(store).toMatchInlineSnapshot(`
    
  1707.         ✕ 1, ⚠ 1
    
  1708.         [root]
    
  1709.             <Example> ✕⚠
    
  1710.       `);
    
  1711. 
    
  1712.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1713.         act(() => legacyRender(<Example rerender={1} />, container));
    
  1714.       });
    
  1715. 
    
  1716.       expect(store).toMatchInlineSnapshot(`
    
  1717.         ✕ 2, ⚠ 2
    
  1718.         [root]
    
  1719.             <Example> ✕⚠
    
  1720.       `);
    
  1721.     });
    
  1722. 
    
  1723.     describe('during passive effects', () => {
    
  1724.       function flushPendingBridgeOperations() {
    
  1725.         jest.runOnlyPendingTimers();
    
  1726.       }
    
  1727. 
    
  1728.       // Gross abstraction around pending passive warning/error delay.
    
  1729.       function flushPendingPassiveErrorAndWarningCounts() {
    
  1730.         jest.advanceTimersByTime(1000);
    
  1731.       }
    
  1732. 
    
  1733.       // @reactVersion >= 18.0
    
  1734.       it('are counted (after a delay)', () => {
    
  1735.         function Example() {
    
  1736.           React.useEffect(() => {
    
  1737.             console.error('test-only: passive error');
    
  1738.             console.warn('test-only: passive warning');
    
  1739.           });
    
  1740.           return null;
    
  1741.         }
    
  1742.         const container = document.createElement('div');
    
  1743. 
    
  1744.         withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1745.           act(() => {
    
  1746.             legacyRender(<Example />, container);
    
  1747.           }, false);
    
  1748.         });
    
  1749.         flushPendingBridgeOperations();
    
  1750.         expect(store).toMatchInlineSnapshot(`
    
  1751.           [root]
    
  1752.               <Example>
    
  1753.         `);
    
  1754. 
    
  1755.         // After a delay, passive effects should be committed as well
    
  1756.         act(flushPendingPassiveErrorAndWarningCounts, false);
    
  1757.         expect(store).toMatchInlineSnapshot(`
    
  1758.           ✕ 1, ⚠ 1
    
  1759.           [root]
    
  1760.               <Example> ✕⚠
    
  1761.         `);
    
  1762. 
    
  1763.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  1764.         expect(store).toMatchInlineSnapshot(``);
    
  1765.       });
    
  1766. 
    
  1767.       // @reactVersion >= 18.0
    
  1768.       it('are flushed early when there is a new commit', () => {
    
  1769.         function Example() {
    
  1770.           React.useEffect(() => {
    
  1771.             console.error('test-only: passive error');
    
  1772.             console.warn('test-only: passive warning');
    
  1773.           });
    
  1774.           return null;
    
  1775.         }
    
  1776. 
    
  1777.         function Noop() {
    
  1778.           return null;
    
  1779.         }
    
  1780. 
    
  1781.         const container = document.createElement('div');
    
  1782. 
    
  1783.         withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1784.           act(() => {
    
  1785.             legacyRender(
    
  1786.               <>
    
  1787.                 <Example />
    
  1788.               </>,
    
  1789.               container,
    
  1790.             );
    
  1791.           }, false);
    
  1792.           flushPendingBridgeOperations();
    
  1793.           expect(store).toMatchInlineSnapshot(`
    
  1794.             [root]
    
  1795.                 <Example>
    
  1796.           `);
    
  1797. 
    
  1798.           // Before warnings and errors have flushed, flush another commit.
    
  1799.           act(() => {
    
  1800.             legacyRender(
    
  1801.               <>
    
  1802.                 <Example />
    
  1803.                 <Noop />
    
  1804.               </>,
    
  1805.               container,
    
  1806.             );
    
  1807.           }, false);
    
  1808.           flushPendingBridgeOperations();
    
  1809.           expect(store).toMatchInlineSnapshot(`
    
  1810.             ✕ 1, ⚠ 1
    
  1811.             [root]
    
  1812.                 <Example> ✕⚠
    
  1813.                 <Noop>
    
  1814.           `);
    
  1815.         });
    
  1816. 
    
  1817.         // After a delay, passive effects should be committed as well
    
  1818.         act(flushPendingPassiveErrorAndWarningCounts, false);
    
  1819.         expect(store).toMatchInlineSnapshot(`
    
  1820.           ✕ 2, ⚠ 2
    
  1821.           [root]
    
  1822.               <Example> ✕⚠
    
  1823.               <Noop>
    
  1824.         `);
    
  1825. 
    
  1826.         act(() => ReactDOM.unmountComponentAtNode(container));
    
  1827.         expect(store).toMatchInlineSnapshot(``);
    
  1828.       });
    
  1829.     });
    
  1830. 
    
  1831.     // @reactVersion >= 18.0
    
  1832.     it('from react get counted', () => {
    
  1833.       const container = document.createElement('div');
    
  1834.       function Example() {
    
  1835.         return [<Child />];
    
  1836.       }
    
  1837.       function Child() {
    
  1838.         return null;
    
  1839.       }
    
  1840. 
    
  1841.       withErrorsOrWarningsIgnored(
    
  1842.         ['Warning: Each child in a list should have a unique "key" prop'],
    
  1843.         () => {
    
  1844.           act(() => legacyRender(<Example />, container));
    
  1845.         },
    
  1846.       );
    
  1847. 
    
  1848.       expect(store).toMatchInlineSnapshot(`
    
  1849.         ✕ 1, ⚠ 0
    
  1850.         [root]
    
  1851.           ▾ <Example> ✕
    
  1852.               <Child>
    
  1853.       `);
    
  1854.     });
    
  1855. 
    
  1856.     // @reactVersion >= 18.0
    
  1857.     it('can be cleared for the whole app', () => {
    
  1858.       function Example() {
    
  1859.         console.error('test-only: render error');
    
  1860.         console.warn('test-only: render warning');
    
  1861.         return null;
    
  1862.       }
    
  1863.       const container = document.createElement('div');
    
  1864.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1865.         act(() =>
    
  1866.           legacyRender(
    
  1867.             <React.Fragment>
    
  1868.               <Example />
    
  1869.               <Example />
    
  1870.             </React.Fragment>,
    
  1871.             container,
    
  1872.           ),
    
  1873.         );
    
  1874.       });
    
  1875. 
    
  1876.       expect(store).toMatchInlineSnapshot(`
    
  1877.         ✕ 2, ⚠ 2
    
  1878.         [root]
    
  1879.             <Example> ✕⚠
    
  1880.             <Example> ✕⚠
    
  1881.       `);
    
  1882. 
    
  1883.       const {
    
  1884.         clearErrorsAndWarnings,
    
  1885.       } = require('react-devtools-shared/src/backendAPI');
    
  1886.       clearErrorsAndWarnings({bridge, store});
    
  1887. 
    
  1888.       // flush events to the renderer
    
  1889.       jest.runAllTimers();
    
  1890. 
    
  1891.       expect(store).toMatchInlineSnapshot(`
    
  1892.         [root]
    
  1893.             <Example>
    
  1894.             <Example>
    
  1895.       `);
    
  1896.     });
    
  1897. 
    
  1898.     // @reactVersion >= 18.0
    
  1899.     it('can be cleared for particular Fiber (only warnings)', () => {
    
  1900.       function Example() {
    
  1901.         console.error('test-only: render error');
    
  1902.         console.warn('test-only: render warning');
    
  1903.         return null;
    
  1904.       }
    
  1905.       const container = document.createElement('div');
    
  1906.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1907.         act(() =>
    
  1908.           legacyRender(
    
  1909.             <React.Fragment>
    
  1910.               <Example />
    
  1911.               <Example />
    
  1912.             </React.Fragment>,
    
  1913.             container,
    
  1914.           ),
    
  1915.         );
    
  1916.       });
    
  1917. 
    
  1918.       expect(store).toMatchInlineSnapshot(`
    
  1919.         ✕ 2, ⚠ 2
    
  1920.         [root]
    
  1921.             <Example> ✕⚠
    
  1922.             <Example> ✕⚠
    
  1923.       `);
    
  1924. 
    
  1925.       const id = ((store.getElementIDAtIndex(1): any): number);
    
  1926.       const rendererID = store.getRendererIDForElement(id);
    
  1927. 
    
  1928.       const {
    
  1929.         clearWarningsForElement,
    
  1930.       } = require('react-devtools-shared/src/backendAPI');
    
  1931.       clearWarningsForElement({bridge, id, rendererID});
    
  1932. 
    
  1933.       // Flush events to the renderer.
    
  1934.       jest.runAllTimers();
    
  1935. 
    
  1936.       expect(store).toMatchInlineSnapshot(`
    
  1937.         ✕ 2, ⚠ 1
    
  1938.         [root]
    
  1939.             <Example> ✕⚠
    
  1940.             <Example> ✕
    
  1941.       `);
    
  1942.     });
    
  1943. 
    
  1944.     // @reactVersion >= 18.0
    
  1945.     it('can be cleared for a particular Fiber (only errors)', () => {
    
  1946.       function Example() {
    
  1947.         console.error('test-only: render error');
    
  1948.         console.warn('test-only: render warning');
    
  1949.         return null;
    
  1950.       }
    
  1951.       const container = document.createElement('div');
    
  1952.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  1953.         act(() =>
    
  1954.           legacyRender(
    
  1955.             <React.Fragment>
    
  1956.               <Example />
    
  1957.               <Example />
    
  1958.             </React.Fragment>,
    
  1959.             container,
    
  1960.           ),
    
  1961.         );
    
  1962.       });
    
  1963. 
    
  1964.       expect(store).toMatchInlineSnapshot(`
    
  1965.         ✕ 2, ⚠ 2
    
  1966.         [root]
    
  1967.             <Example> ✕⚠
    
  1968.             <Example> ✕⚠
    
  1969.       `);
    
  1970. 
    
  1971.       const id = ((store.getElementIDAtIndex(1): any): number);
    
  1972.       const rendererID = store.getRendererIDForElement(id);
    
  1973. 
    
  1974.       const {
    
  1975.         clearErrorsForElement,
    
  1976.       } = require('react-devtools-shared/src/backendAPI');
    
  1977.       clearErrorsForElement({bridge, id, rendererID});
    
  1978. 
    
  1979.       // Flush events to the renderer.
    
  1980.       jest.runAllTimers();
    
  1981. 
    
  1982.       expect(store).toMatchInlineSnapshot(`
    
  1983.         ✕ 1, ⚠ 2
    
  1984.         [root]
    
  1985.             <Example> ✕⚠
    
  1986.             <Example> ⚠
    
  1987.       `);
    
  1988.     });
    
  1989. 
    
  1990.     // @reactVersion >= 18.0
    
  1991.     it('are updated when fibers are removed from the tree', () => {
    
  1992.       function ComponentWithWarning() {
    
  1993.         console.warn('test-only: render warning');
    
  1994.         return null;
    
  1995.       }
    
  1996.       function ComponentWithError() {
    
  1997.         console.error('test-only: render error');
    
  1998.         return null;
    
  1999.       }
    
  2000.       function ComponentWithWarningAndError() {
    
  2001.         console.error('test-only: render error');
    
  2002.         console.warn('test-only: render warning');
    
  2003.         return null;
    
  2004.       }
    
  2005.       const container = document.createElement('div');
    
  2006.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  2007.         act(() =>
    
  2008.           legacyRender(
    
  2009.             <React.Fragment>
    
  2010.               <ComponentWithError />
    
  2011.               <ComponentWithWarning />
    
  2012.               <ComponentWithWarningAndError />
    
  2013.             </React.Fragment>,
    
  2014.             container,
    
  2015.           ),
    
  2016.         );
    
  2017.       });
    
  2018.       expect(store).toMatchInlineSnapshot(`
    
  2019.         ✕ 2, ⚠ 2
    
  2020.         [root]
    
  2021.             <ComponentWithError> ✕
    
  2022.             <ComponentWithWarning> ⚠
    
  2023.             <ComponentWithWarningAndError> ✕⚠
    
  2024.       `);
    
  2025. 
    
  2026.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  2027.         act(() =>
    
  2028.           legacyRender(
    
  2029.             <React.Fragment>
    
  2030.               <ComponentWithWarning />
    
  2031.               <ComponentWithWarningAndError />
    
  2032.             </React.Fragment>,
    
  2033.             container,
    
  2034.           ),
    
  2035.         );
    
  2036.       });
    
  2037.       expect(store).toMatchInlineSnapshot(`
    
  2038.         ✕ 1, ⚠ 2
    
  2039.         [root]
    
  2040.             <ComponentWithWarning> ⚠
    
  2041.             <ComponentWithWarningAndError> ✕⚠
    
  2042.       `);
    
  2043. 
    
  2044.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  2045.         act(() =>
    
  2046.           legacyRender(
    
  2047.             <React.Fragment>
    
  2048.               <ComponentWithWarning />
    
  2049.             </React.Fragment>,
    
  2050.             container,
    
  2051.           ),
    
  2052.         );
    
  2053.       });
    
  2054.       expect(store).toMatchInlineSnapshot(`
    
  2055.         ✕ 0, ⚠ 2
    
  2056.         [root]
    
  2057.             <ComponentWithWarning> ⚠
    
  2058.       `);
    
  2059. 
    
  2060.       withErrorsOrWarningsIgnored(['test-only:'], () => {
    
  2061.         act(() => legacyRender(<React.Fragment />, container));
    
  2062.       });
    
  2063.       expect(store).toMatchInlineSnapshot(`[root]`);
    
  2064.       expect(store.errorCount).toBe(0);
    
  2065.       expect(store.warningCount).toBe(0);
    
  2066.     });
    
  2067. 
    
  2068.     // Regression test for https://github.com/facebook/react/issues/23202
    
  2069.     // @reactVersion >= 18.0
    
  2070.     it('suspense boundary children should not double unmount and error', async () => {
    
  2071.       async function fakeImport(result) {
    
  2072.         return {default: result};
    
  2073.       }
    
  2074. 
    
  2075.       const ChildA = () => null;
    
  2076.       const ChildB = () => null;
    
  2077. 
    
  2078.       const LazyChildA = React.lazy(() => fakeImport(ChildA));
    
  2079.       const LazyChildB = React.lazy(() => fakeImport(ChildB));
    
  2080. 
    
  2081.       function App({renderA}) {
    
  2082.         return (
    
  2083.           <React.Suspense>
    
  2084.             {renderA ? <LazyChildA /> : <LazyChildB />}
    
  2085.           </React.Suspense>
    
  2086.         );
    
  2087.       }
    
  2088. 
    
  2089.       const container = document.createElement('div');
    
  2090.       const root = ReactDOMClient.createRoot(container);
    
  2091.       await actAsync(() => root.render(<App renderA={true} />));
    
  2092. 
    
  2093.       expect(store).toMatchInlineSnapshot(`
    
  2094.           [root]
    
  2095.             ▾ <App>
    
  2096.               ▾ <Suspense>
    
  2097.                   <ChildA>
    
  2098.         `);
    
  2099. 
    
  2100.       await actAsync(() => root.render(<App renderA={false} />));
    
  2101. 
    
  2102.       expect(store).toMatchInlineSnapshot(`
    
  2103.           [root]
    
  2104.             ▾ <App>
    
  2105.               ▾ <Suspense>
    
  2106.                   <ChildB>
    
  2107.         `);
    
  2108.     });
    
  2109.   });
    
  2110. });