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.  * @emails react-core
    
  8.  */
    
  9. 
    
  10. /* eslint-disable no-for-of-loops/no-for-of-loops */
    
  11. 
    
  12. 'use strict';
    
  13. 
    
  14. let React;
    
  15. let ReactDOM;
    
  16. let ReactDOMClient;
    
  17. let ReactFreshRuntime;
    
  18. let Scheduler;
    
  19. let act;
    
  20. let internalAct;
    
  21. let createReactClass;
    
  22. let waitFor;
    
  23. let assertLog;
    
  24. 
    
  25. describe('ReactFresh', () => {
    
  26.   let container;
    
  27. 
    
  28.   beforeEach(() => {
    
  29.     if (__DEV__) {
    
  30.       jest.resetModules();
    
  31.       React = require('react');
    
  32.       ReactFreshRuntime = require('react-refresh/runtime');
    
  33.       ReactFreshRuntime.injectIntoGlobalHook(global);
    
  34.       ReactDOM = require('react-dom');
    
  35.       ReactDOMClient = require('react-dom/client');
    
  36.       Scheduler = require('scheduler');
    
  37.       act = require('react-dom/test-utils').act;
    
  38.       internalAct = require('internal-test-utils').act;
    
  39. 
    
  40.       const InternalTestUtils = require('internal-test-utils');
    
  41.       waitFor = InternalTestUtils.waitFor;
    
  42.       assertLog = InternalTestUtils.assertLog;
    
  43. 
    
  44.       createReactClass = require('create-react-class/factory')(
    
  45.         React.Component,
    
  46.         React.isValidElement,
    
  47.         new React.Component().updater,
    
  48.       );
    
  49.       container = document.createElement('div');
    
  50.       document.body.appendChild(container);
    
  51.     }
    
  52.   });
    
  53. 
    
  54.   afterEach(() => {
    
  55.     if (__DEV__) {
    
  56.       delete global.__REACT_DEVTOOLS_GLOBAL_HOOK__;
    
  57.       document.body.removeChild(container);
    
  58.     }
    
  59.   });
    
  60. 
    
  61.   function prepare(version) {
    
  62.     const Component = version();
    
  63.     return Component;
    
  64.   }
    
  65. 
    
  66.   function render(version, props) {
    
  67.     const Component = version();
    
  68.     act(() => {
    
  69.       ReactDOM.render(<Component {...props} />, container);
    
  70.     });
    
  71.     return Component;
    
  72.   }
    
  73. 
    
  74.   function patch(version) {
    
  75.     const Component = version();
    
  76.     ReactFreshRuntime.performReactRefresh();
    
  77.     return Component;
    
  78.   }
    
  79. 
    
  80.   function $RefreshReg$(type, id) {
    
  81.     ReactFreshRuntime.register(type, id);
    
  82.   }
    
  83. 
    
  84.   function $RefreshSig$(type, key, forceReset, getCustomHooks) {
    
  85.     ReactFreshRuntime.setSignature(type, key, forceReset, getCustomHooks);
    
  86.     return type;
    
  87.   }
    
  88. 
    
  89.   // Note: This is based on a similar component we use in www. We can delete
    
  90.   // once the extra div wrapper is no longer necessary.
    
  91.   function LegacyHiddenDiv({children, mode}) {
    
  92.     return (
    
  93.       <div hidden={mode === 'hidden'}>
    
  94.         <React.unstable_LegacyHidden
    
  95.           mode={mode === 'hidden' ? 'unstable-defer-without-hiding' : mode}>
    
  96.           {children}
    
  97.         </React.unstable_LegacyHidden>
    
  98.       </div>
    
  99.     );
    
  100.   }
    
  101. 
    
  102.   it('can preserve state for compatible types', () => {
    
  103.     if (__DEV__) {
    
  104.       const HelloV1 = render(() => {
    
  105.         function Hello() {
    
  106.           const [val, setVal] = React.useState(0);
    
  107.           return (
    
  108.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  109.               {val}
    
  110.             </p>
    
  111.           );
    
  112.         }
    
  113.         $RefreshReg$(Hello, 'Hello');
    
  114.         return Hello;
    
  115.       });
    
  116. 
    
  117.       // Bump the state before patching.
    
  118.       const el = container.firstChild;
    
  119.       expect(el.textContent).toBe('0');
    
  120.       expect(el.style.color).toBe('blue');
    
  121.       act(() => {
    
  122.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  123.       });
    
  124.       expect(el.textContent).toBe('1');
    
  125. 
    
  126.       // Perform a hot update.
    
  127.       const HelloV2 = patch(() => {
    
  128.         function Hello() {
    
  129.           const [val, setVal] = React.useState(0);
    
  130.           return (
    
  131.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  132.               {val}
    
  133.             </p>
    
  134.           );
    
  135.         }
    
  136.         $RefreshReg$(Hello, 'Hello');
    
  137.         return Hello;
    
  138.       });
    
  139. 
    
  140.       // Assert the state was preserved but color changed.
    
  141.       expect(container.firstChild).toBe(el);
    
  142.       expect(el.textContent).toBe('1');
    
  143.       expect(el.style.color).toBe('red');
    
  144. 
    
  145.       // Bump the state again.
    
  146.       act(() => {
    
  147.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  148.       });
    
  149.       expect(container.firstChild).toBe(el);
    
  150.       expect(el.textContent).toBe('2');
    
  151.       expect(el.style.color).toBe('red');
    
  152. 
    
  153.       // Perform top-down renders with both fresh and stale types.
    
  154.       // Neither should change the state or color.
    
  155.       // They should always resolve to the latest version.
    
  156.       render(() => HelloV1);
    
  157.       render(() => HelloV2);
    
  158.       render(() => HelloV1);
    
  159.       expect(container.firstChild).toBe(el);
    
  160.       expect(el.textContent).toBe('2');
    
  161.       expect(el.style.color).toBe('red');
    
  162. 
    
  163.       // Bump the state again.
    
  164.       act(() => {
    
  165.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  166.       });
    
  167.       expect(container.firstChild).toBe(el);
    
  168.       expect(el.textContent).toBe('3');
    
  169.       expect(el.style.color).toBe('red');
    
  170. 
    
  171.       // Finally, a render with incompatible type should reset it.
    
  172.       render(() => {
    
  173.         function Hello() {
    
  174.           const [val, setVal] = React.useState(0);
    
  175.           return (
    
  176.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  177.               {val}
    
  178.             </p>
    
  179.           );
    
  180.         }
    
  181.         // No register call.
    
  182.         // This is considered a new type.
    
  183.         return Hello;
    
  184.       });
    
  185.       expect(container.firstChild).not.toBe(el);
    
  186.       const newEl = container.firstChild;
    
  187.       expect(newEl.textContent).toBe('0');
    
  188.       expect(newEl.style.color).toBe('blue');
    
  189.     }
    
  190.   });
    
  191. 
    
  192.   it('can preserve state for forwardRef', () => {
    
  193.     if (__DEV__) {
    
  194.       const OuterV1 = render(() => {
    
  195.         function Hello() {
    
  196.           const [val, setVal] = React.useState(0);
    
  197.           return (
    
  198.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  199.               {val}
    
  200.             </p>
    
  201.           );
    
  202.         }
    
  203.         $RefreshReg$(Hello, 'Hello');
    
  204. 
    
  205.         const Outer = React.forwardRef(() => <Hello />);
    
  206.         $RefreshReg$(Outer, 'Outer');
    
  207.         return Outer;
    
  208.       });
    
  209. 
    
  210.       // Bump the state before patching.
    
  211.       const el = container.firstChild;
    
  212.       expect(el.textContent).toBe('0');
    
  213.       expect(el.style.color).toBe('blue');
    
  214.       act(() => {
    
  215.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  216.       });
    
  217.       expect(el.textContent).toBe('1');
    
  218. 
    
  219.       // Perform a hot update.
    
  220.       const OuterV2 = patch(() => {
    
  221.         function Hello() {
    
  222.           const [val, setVal] = React.useState(0);
    
  223.           return (
    
  224.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  225.               {val}
    
  226.             </p>
    
  227.           );
    
  228.         }
    
  229.         $RefreshReg$(Hello, 'Hello');
    
  230. 
    
  231.         const Outer = React.forwardRef(() => <Hello />);
    
  232.         $RefreshReg$(Outer, 'Outer');
    
  233.         return Outer;
    
  234.       });
    
  235. 
    
  236.       // Assert the state was preserved but color changed.
    
  237.       expect(container.firstChild).toBe(el);
    
  238.       expect(el.textContent).toBe('1');
    
  239.       expect(el.style.color).toBe('red');
    
  240. 
    
  241.       // Bump the state again.
    
  242.       act(() => {
    
  243.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  244.       });
    
  245.       expect(container.firstChild).toBe(el);
    
  246.       expect(el.textContent).toBe('2');
    
  247.       expect(el.style.color).toBe('red');
    
  248. 
    
  249.       // Perform top-down renders with both fresh and stale types.
    
  250.       // Neither should change the state or color.
    
  251.       // They should always resolve to the latest version.
    
  252.       render(() => OuterV1);
    
  253.       render(() => OuterV2);
    
  254.       render(() => OuterV1);
    
  255.       expect(container.firstChild).toBe(el);
    
  256.       expect(el.textContent).toBe('2');
    
  257.       expect(el.style.color).toBe('red');
    
  258. 
    
  259.       // Finally, a render with incompatible type should reset it.
    
  260.       render(() => {
    
  261.         function Hello() {
    
  262.           const [val, setVal] = React.useState(0);
    
  263.           return (
    
  264.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  265.               {val}
    
  266.             </p>
    
  267.           );
    
  268.         }
    
  269.         $RefreshReg$(Hello, 'Hello');
    
  270. 
    
  271.         // Note: no forwardRef wrapper this time.
    
  272.         return Hello;
    
  273.       });
    
  274. 
    
  275.       expect(container.firstChild).not.toBe(el);
    
  276.       const newEl = container.firstChild;
    
  277.       expect(newEl.textContent).toBe('0');
    
  278.       expect(newEl.style.color).toBe('blue');
    
  279.     }
    
  280.   });
    
  281. 
    
  282.   it('should not consider two forwardRefs around the same type to be equivalent', () => {
    
  283.     if (__DEV__) {
    
  284.       const ParentV1 = render(
    
  285.         () => {
    
  286.           function Hello() {
    
  287.             const [val, setVal] = React.useState(0);
    
  288.             return (
    
  289.               <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  290.                 {val}
    
  291.               </p>
    
  292.             );
    
  293.           }
    
  294.           $RefreshReg$(Hello, 'Hello');
    
  295. 
    
  296.           function renderInner() {
    
  297.             return <Hello />;
    
  298.           }
    
  299.           // Both of these are wrappers around the same inner function.
    
  300.           // They should be treated as distinct types across reloads.
    
  301.           const ForwardRefA = React.forwardRef(renderInner);
    
  302.           $RefreshReg$(ForwardRefA, 'ForwardRefA');
    
  303.           const ForwardRefB = React.forwardRef(renderInner);
    
  304.           $RefreshReg$(ForwardRefB, 'ForwardRefB');
    
  305. 
    
  306.           function Parent({cond}) {
    
  307.             return cond ? <ForwardRefA /> : <ForwardRefB />;
    
  308.           }
    
  309.           $RefreshReg$(Parent, 'Parent');
    
  310. 
    
  311.           return Parent;
    
  312.         },
    
  313.         {cond: true},
    
  314.       );
    
  315. 
    
  316.       // Bump the state before switching up types.
    
  317.       let el = container.firstChild;
    
  318.       expect(el.textContent).toBe('0');
    
  319.       expect(el.style.color).toBe('blue');
    
  320.       act(() => {
    
  321.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  322.       });
    
  323.       expect(el.textContent).toBe('1');
    
  324. 
    
  325.       // Switching up the inner types should reset the state.
    
  326.       render(() => ParentV1, {cond: false});
    
  327.       expect(el).not.toBe(container.firstChild);
    
  328.       el = container.firstChild;
    
  329.       expect(el.textContent).toBe('0');
    
  330.       expect(el.style.color).toBe('blue');
    
  331. 
    
  332.       act(() => {
    
  333.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  334.       });
    
  335.       expect(el.textContent).toBe('1');
    
  336. 
    
  337.       // Switch them up back again.
    
  338.       render(() => ParentV1, {cond: true});
    
  339.       expect(el).not.toBe(container.firstChild);
    
  340.       el = container.firstChild;
    
  341.       expect(el.textContent).toBe('0');
    
  342.       expect(el.style.color).toBe('blue');
    
  343. 
    
  344.       // Now bump up the state to prepare for patching.
    
  345.       act(() => {
    
  346.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  347.       });
    
  348.       expect(el.textContent).toBe('1');
    
  349. 
    
  350.       // Patch to change the color.
    
  351.       const ParentV2 = patch(() => {
    
  352.         function Hello() {
    
  353.           const [val, setVal] = React.useState(0);
    
  354.           return (
    
  355.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  356.               {val}
    
  357.             </p>
    
  358.           );
    
  359.         }
    
  360.         $RefreshReg$(Hello, 'Hello');
    
  361. 
    
  362.         function renderInner() {
    
  363.           return <Hello />;
    
  364.         }
    
  365.         // Both of these are wrappers around the same inner function.
    
  366.         // They should be treated as distinct types across reloads.
    
  367.         const ForwardRefA = React.forwardRef(renderInner);
    
  368.         $RefreshReg$(ForwardRefA, 'ForwardRefA');
    
  369.         const ForwardRefB = React.forwardRef(renderInner);
    
  370.         $RefreshReg$(ForwardRefB, 'ForwardRefB');
    
  371. 
    
  372.         function Parent({cond}) {
    
  373.           return cond ? <ForwardRefA /> : <ForwardRefB />;
    
  374.         }
    
  375.         $RefreshReg$(Parent, 'Parent');
    
  376. 
    
  377.         return Parent;
    
  378.       });
    
  379. 
    
  380.       // The state should be intact; the color should change.
    
  381.       expect(el).toBe(container.firstChild);
    
  382.       expect(el.textContent).toBe('1');
    
  383.       expect(el.style.color).toBe('red');
    
  384. 
    
  385.       // Switching up the condition should still reset the state.
    
  386.       render(() => ParentV2, {cond: false});
    
  387.       expect(el).not.toBe(container.firstChild);
    
  388.       el = container.firstChild;
    
  389.       expect(el.textContent).toBe('0');
    
  390.       expect(el.style.color).toBe('red');
    
  391. 
    
  392.       // Now bump up the state to prepare for top-level renders.
    
  393.       act(() => {
    
  394.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  395.       });
    
  396.       expect(el).toBe(container.firstChild);
    
  397.       expect(el.textContent).toBe('1');
    
  398.       expect(el.style.color).toBe('red');
    
  399. 
    
  400.       // Finally, verify using top-level render with stale type keeps state.
    
  401.       render(() => ParentV1);
    
  402.       render(() => ParentV2);
    
  403.       render(() => ParentV1);
    
  404.       expect(container.firstChild).toBe(el);
    
  405.       expect(el.textContent).toBe('1');
    
  406.       expect(el.style.color).toBe('red');
    
  407.     }
    
  408.   });
    
  409. 
    
  410.   it('can update forwardRef render function with its wrapper', () => {
    
  411.     if (__DEV__) {
    
  412.       render(() => {
    
  413.         function Hello({color}) {
    
  414.           const [val, setVal] = React.useState(0);
    
  415.           return (
    
  416.             <p style={{color}} onClick={() => setVal(val + 1)}>
    
  417.               {val}
    
  418.             </p>
    
  419.           );
    
  420.         }
    
  421.         $RefreshReg$(Hello, 'Hello');
    
  422. 
    
  423.         const Outer = React.forwardRef(() => <Hello color="blue" />);
    
  424.         $RefreshReg$(Outer, 'Outer');
    
  425.         return Outer;
    
  426.       });
    
  427. 
    
  428.       // Bump the state before patching.
    
  429.       const el = container.firstChild;
    
  430.       expect(el.textContent).toBe('0');
    
  431.       expect(el.style.color).toBe('blue');
    
  432.       act(() => {
    
  433.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  434.       });
    
  435.       expect(el.textContent).toBe('1');
    
  436. 
    
  437.       // Perform a hot update.
    
  438.       patch(() => {
    
  439.         function Hello({color}) {
    
  440.           const [val, setVal] = React.useState(0);
    
  441.           return (
    
  442.             <p style={{color}} onClick={() => setVal(val + 1)}>
    
  443.               {val}
    
  444.             </p>
    
  445.           );
    
  446.         }
    
  447.         $RefreshReg$(Hello, 'Hello');
    
  448. 
    
  449.         const Outer = React.forwardRef(() => <Hello color="red" />);
    
  450.         $RefreshReg$(Outer, 'Outer');
    
  451.         return Outer;
    
  452.       });
    
  453. 
    
  454.       // Assert the state was preserved but color changed.
    
  455.       expect(container.firstChild).toBe(el);
    
  456.       expect(el.textContent).toBe('1');
    
  457.       expect(el.style.color).toBe('red');
    
  458.     }
    
  459.   });
    
  460. 
    
  461.   it('can update forwardRef render function in isolation', () => {
    
  462.     if (__DEV__) {
    
  463.       render(() => {
    
  464.         function Hello({color}) {
    
  465.           const [val, setVal] = React.useState(0);
    
  466.           return (
    
  467.             <p style={{color}} onClick={() => setVal(val + 1)}>
    
  468.               {val}
    
  469.             </p>
    
  470.           );
    
  471.         }
    
  472.         $RefreshReg$(Hello, 'Hello');
    
  473. 
    
  474.         function renderHello() {
    
  475.           return <Hello color="blue" />;
    
  476.         }
    
  477.         $RefreshReg$(renderHello, 'renderHello');
    
  478. 
    
  479.         return React.forwardRef(renderHello);
    
  480.       });
    
  481. 
    
  482.       // Bump the state before patching.
    
  483.       const el = container.firstChild;
    
  484.       expect(el.textContent).toBe('0');
    
  485.       expect(el.style.color).toBe('blue');
    
  486.       act(() => {
    
  487.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  488.       });
    
  489.       expect(el.textContent).toBe('1');
    
  490. 
    
  491.       // Perform a hot update of just the rendering function.
    
  492.       patch(() => {
    
  493.         function Hello({color}) {
    
  494.           const [val, setVal] = React.useState(0);
    
  495.           return (
    
  496.             <p style={{color}} onClick={() => setVal(val + 1)}>
    
  497.               {val}
    
  498.             </p>
    
  499.           );
    
  500.         }
    
  501.         $RefreshReg$(Hello, 'Hello');
    
  502. 
    
  503.         function renderHello() {
    
  504.           return <Hello color="red" />;
    
  505.         }
    
  506.         $RefreshReg$(renderHello, 'renderHello');
    
  507. 
    
  508.         // Not updating the wrapper.
    
  509.       });
    
  510. 
    
  511.       // Assert the state was preserved but color changed.
    
  512.       expect(container.firstChild).toBe(el);
    
  513.       expect(el.textContent).toBe('1');
    
  514.       expect(el.style.color).toBe('red');
    
  515.     }
    
  516.   });
    
  517. 
    
  518.   it('can preserve state for simple memo', () => {
    
  519.     if (__DEV__) {
    
  520.       const OuterV1 = render(() => {
    
  521.         function Hello() {
    
  522.           const [val, setVal] = React.useState(0);
    
  523.           return (
    
  524.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  525.               {val}
    
  526.             </p>
    
  527.           );
    
  528.         }
    
  529.         $RefreshReg$(Hello, 'Hello');
    
  530. 
    
  531.         const Outer = React.memo(Hello);
    
  532.         $RefreshReg$(Outer, 'Outer');
    
  533.         return Outer;
    
  534.       });
    
  535. 
    
  536.       // Bump the state before patching.
    
  537.       const el = container.firstChild;
    
  538.       expect(el.textContent).toBe('0');
    
  539.       expect(el.style.color).toBe('blue');
    
  540.       act(() => {
    
  541.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  542.       });
    
  543.       expect(el.textContent).toBe('1');
    
  544. 
    
  545.       // Perform a hot update.
    
  546.       const OuterV2 = patch(() => {
    
  547.         function Hello() {
    
  548.           const [val, setVal] = React.useState(0);
    
  549.           return (
    
  550.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  551.               {val}
    
  552.             </p>
    
  553.           );
    
  554.         }
    
  555.         $RefreshReg$(Hello, 'Hello');
    
  556. 
    
  557.         const Outer = React.memo(Hello);
    
  558.         $RefreshReg$(Outer, 'Outer');
    
  559.         return Outer;
    
  560.       });
    
  561. 
    
  562.       // Assert the state was preserved but color changed.
    
  563.       expect(container.firstChild).toBe(el);
    
  564.       expect(el.textContent).toBe('1');
    
  565.       expect(el.style.color).toBe('red');
    
  566. 
    
  567.       // Bump the state again.
    
  568.       act(() => {
    
  569.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  570.       });
    
  571.       expect(container.firstChild).toBe(el);
    
  572.       expect(el.textContent).toBe('2');
    
  573.       expect(el.style.color).toBe('red');
    
  574. 
    
  575.       // Perform top-down renders with both fresh and stale types.
    
  576.       // Neither should change the state or color.
    
  577.       // They should always resolve to the latest version.
    
  578.       render(() => OuterV1);
    
  579.       render(() => OuterV2);
    
  580.       render(() => OuterV1);
    
  581.       expect(container.firstChild).toBe(el);
    
  582.       expect(el.textContent).toBe('2');
    
  583.       expect(el.style.color).toBe('red');
    
  584. 
    
  585.       // Finally, a render with incompatible type should reset it.
    
  586.       render(() => {
    
  587.         function Hello() {
    
  588.           const [val, setVal] = React.useState(0);
    
  589.           return (
    
  590.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  591.               {val}
    
  592.             </p>
    
  593.           );
    
  594.         }
    
  595.         $RefreshReg$(Hello, 'Hello');
    
  596. 
    
  597.         // Note: no wrapper this time.
    
  598.         return Hello;
    
  599.       });
    
  600. 
    
  601.       expect(container.firstChild).not.toBe(el);
    
  602.       const newEl = container.firstChild;
    
  603.       expect(newEl.textContent).toBe('0');
    
  604.       expect(newEl.style.color).toBe('blue');
    
  605.     }
    
  606.   });
    
  607. 
    
  608.   it('can preserve state for memo with custom comparison', () => {
    
  609.     if (__DEV__) {
    
  610.       const OuterV1 = render(() => {
    
  611.         function Hello() {
    
  612.           const [val, setVal] = React.useState(0);
    
  613.           return (
    
  614.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  615.               {val}
    
  616.             </p>
    
  617.           );
    
  618.         }
    
  619. 
    
  620.         const Outer = React.memo(Hello, () => true);
    
  621.         $RefreshReg$(Outer, 'Outer');
    
  622.         return Outer;
    
  623.       });
    
  624. 
    
  625.       // Bump the state before patching.
    
  626.       const el = container.firstChild;
    
  627.       expect(el.textContent).toBe('0');
    
  628.       expect(el.style.color).toBe('blue');
    
  629.       act(() => {
    
  630.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  631.       });
    
  632.       expect(el.textContent).toBe('1');
    
  633. 
    
  634.       // Perform a hot update.
    
  635.       const OuterV2 = patch(() => {
    
  636.         function Hello() {
    
  637.           const [val, setVal] = React.useState(0);
    
  638.           return (
    
  639.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  640.               {val}
    
  641.             </p>
    
  642.           );
    
  643.         }
    
  644. 
    
  645.         const Outer = React.memo(Hello, () => true);
    
  646.         $RefreshReg$(Outer, 'Outer');
    
  647.         return Outer;
    
  648.       });
    
  649. 
    
  650.       // Assert the state was preserved but color changed.
    
  651.       expect(container.firstChild).toBe(el);
    
  652.       expect(el.textContent).toBe('1');
    
  653.       expect(el.style.color).toBe('red');
    
  654. 
    
  655.       // Bump the state again.
    
  656.       act(() => {
    
  657.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  658.       });
    
  659.       expect(container.firstChild).toBe(el);
    
  660.       expect(el.textContent).toBe('2');
    
  661.       expect(el.style.color).toBe('red');
    
  662. 
    
  663.       // Perform top-down renders with both fresh and stale types.
    
  664.       // Neither should change the state or color.
    
  665.       // They should always resolve to the latest version.
    
  666.       render(() => OuterV1);
    
  667.       render(() => OuterV2);
    
  668.       render(() => OuterV1);
    
  669.       expect(container.firstChild).toBe(el);
    
  670.       expect(el.textContent).toBe('2');
    
  671.       expect(el.style.color).toBe('red');
    
  672. 
    
  673.       // Finally, a render with incompatible type should reset it.
    
  674.       render(() => {
    
  675.         function Hello() {
    
  676.           const [val, setVal] = React.useState(0);
    
  677.           return (
    
  678.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  679.               {val}
    
  680.             </p>
    
  681.           );
    
  682.         }
    
  683.         $RefreshReg$(Hello, 'Hello');
    
  684. 
    
  685.         // Note: no wrapper this time.
    
  686.         return Hello;
    
  687.       });
    
  688. 
    
  689.       expect(container.firstChild).not.toBe(el);
    
  690.       const newEl = container.firstChild;
    
  691.       expect(newEl.textContent).toBe('0');
    
  692.       expect(newEl.style.color).toBe('blue');
    
  693.     }
    
  694.   });
    
  695. 
    
  696.   it('can update simple memo function in isolation', () => {
    
  697.     if (__DEV__) {
    
  698.       render(() => {
    
  699.         function Hello() {
    
  700.           const [val, setVal] = React.useState(0);
    
  701.           return (
    
  702.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  703.               {val}
    
  704.             </p>
    
  705.           );
    
  706.         }
    
  707.         $RefreshReg$(Hello, 'Hello');
    
  708. 
    
  709.         return React.memo(Hello);
    
  710.       });
    
  711. 
    
  712.       // Bump the state before patching.
    
  713.       const el = container.firstChild;
    
  714.       expect(el.textContent).toBe('0');
    
  715.       expect(el.style.color).toBe('blue');
    
  716.       act(() => {
    
  717.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  718.       });
    
  719.       expect(el.textContent).toBe('1');
    
  720. 
    
  721.       // Perform a hot update of just the rendering function.
    
  722.       patch(() => {
    
  723.         function Hello() {
    
  724.           const [val, setVal] = React.useState(0);
    
  725.           return (
    
  726.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  727.               {val}
    
  728.             </p>
    
  729.           );
    
  730.         }
    
  731.         $RefreshReg$(Hello, 'Hello');
    
  732. 
    
  733.         // Not updating the wrapper.
    
  734.       });
    
  735. 
    
  736.       // Assert the state was preserved but color changed.
    
  737.       expect(container.firstChild).toBe(el);
    
  738.       expect(el.textContent).toBe('1');
    
  739.       expect(el.style.color).toBe('red');
    
  740.     }
    
  741.   });
    
  742. 
    
  743.   it('can preserve state for memo(forwardRef)', () => {
    
  744.     if (__DEV__) {
    
  745.       const OuterV1 = render(() => {
    
  746.         function Hello() {
    
  747.           const [val, setVal] = React.useState(0);
    
  748.           return (
    
  749.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  750.               {val}
    
  751.             </p>
    
  752.           );
    
  753.         }
    
  754.         $RefreshReg$(Hello, 'Hello');
    
  755. 
    
  756.         const Outer = React.memo(React.forwardRef(() => <Hello />));
    
  757.         $RefreshReg$(Outer, 'Outer');
    
  758.         return Outer;
    
  759.       });
    
  760. 
    
  761.       // Bump the state before patching.
    
  762.       const el = container.firstChild;
    
  763.       expect(el.textContent).toBe('0');
    
  764.       expect(el.style.color).toBe('blue');
    
  765.       act(() => {
    
  766.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  767.       });
    
  768.       expect(el.textContent).toBe('1');
    
  769. 
    
  770.       // Perform a hot update.
    
  771.       const OuterV2 = patch(() => {
    
  772.         function Hello() {
    
  773.           const [val, setVal] = React.useState(0);
    
  774.           return (
    
  775.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  776.               {val}
    
  777.             </p>
    
  778.           );
    
  779.         }
    
  780.         $RefreshReg$(Hello, 'Hello');
    
  781. 
    
  782.         const Outer = React.memo(React.forwardRef(() => <Hello />));
    
  783.         $RefreshReg$(Outer, 'Outer');
    
  784.         return Outer;
    
  785.       });
    
  786. 
    
  787.       // Assert the state was preserved but color changed.
    
  788.       expect(container.firstChild).toBe(el);
    
  789.       expect(el.textContent).toBe('1');
    
  790.       expect(el.style.color).toBe('red');
    
  791. 
    
  792.       // Bump the state again.
    
  793.       act(() => {
    
  794.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  795.       });
    
  796.       expect(container.firstChild).toBe(el);
    
  797.       expect(el.textContent).toBe('2');
    
  798.       expect(el.style.color).toBe('red');
    
  799. 
    
  800.       // Perform top-down renders with both fresh and stale types.
    
  801.       // Neither should change the state or color.
    
  802.       // They should always resolve to the latest version.
    
  803.       render(() => OuterV1);
    
  804.       render(() => OuterV2);
    
  805.       render(() => OuterV1);
    
  806.       expect(container.firstChild).toBe(el);
    
  807.       expect(el.textContent).toBe('2');
    
  808.       expect(el.style.color).toBe('red');
    
  809. 
    
  810.       // Finally, a render with incompatible type should reset it.
    
  811.       render(() => {
    
  812.         function Hello() {
    
  813.           const [val, setVal] = React.useState(0);
    
  814.           return (
    
  815.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  816.               {val}
    
  817.             </p>
    
  818.           );
    
  819.         }
    
  820.         $RefreshReg$(Hello, 'Hello');
    
  821. 
    
  822.         // Note: no wrapper this time.
    
  823.         return Hello;
    
  824.       });
    
  825. 
    
  826.       expect(container.firstChild).not.toBe(el);
    
  827.       const newEl = container.firstChild;
    
  828.       expect(newEl.textContent).toBe('0');
    
  829.       expect(newEl.style.color).toBe('blue');
    
  830.     }
    
  831.   });
    
  832. 
    
  833.   it('can preserve state for lazy after resolution', async () => {
    
  834.     if (__DEV__) {
    
  835.       const AppV1 = render(() => {
    
  836.         function Hello() {
    
  837.           const [val, setVal] = React.useState(0);
    
  838.           return (
    
  839.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  840.               {val}
    
  841.             </p>
    
  842.           );
    
  843.         }
    
  844.         $RefreshReg$(Hello, 'Hello');
    
  845. 
    
  846.         const Outer = React.lazy(
    
  847.           () =>
    
  848.             new Promise(resolve => {
    
  849.               setTimeout(() => resolve({default: Hello}), 100);
    
  850.             }),
    
  851.         );
    
  852.         $RefreshReg$(Outer, 'Outer');
    
  853. 
    
  854.         function App() {
    
  855.           return (
    
  856.             <React.Suspense fallback={<p>Loading</p>}>
    
  857.               <Outer />
    
  858.             </React.Suspense>
    
  859.           );
    
  860.         }
    
  861.         $RefreshReg$(App, 'App');
    
  862. 
    
  863.         return App;
    
  864.       });
    
  865. 
    
  866.       expect(container.textContent).toBe('Loading');
    
  867.       await act(() => {
    
  868.         jest.runAllTimers();
    
  869.       });
    
  870.       expect(container.textContent).toBe('0');
    
  871. 
    
  872.       // Bump the state before patching.
    
  873.       const el = container.firstChild;
    
  874.       expect(el.textContent).toBe('0');
    
  875.       expect(el.style.color).toBe('blue');
    
  876.       act(() => {
    
  877.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  878.       });
    
  879.       expect(el.textContent).toBe('1');
    
  880. 
    
  881.       // Perform a hot update.
    
  882.       const AppV2 = patch(() => {
    
  883.         function Hello() {
    
  884.           const [val, setVal] = React.useState(0);
    
  885.           return (
    
  886.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  887.               {val}
    
  888.             </p>
    
  889.           );
    
  890.         }
    
  891.         $RefreshReg$(Hello, 'Hello');
    
  892. 
    
  893.         const Outer = React.lazy(
    
  894.           () =>
    
  895.             new Promise(resolve => {
    
  896.               setTimeout(() => resolve({default: Hello}), 100);
    
  897.             }),
    
  898.         );
    
  899.         $RefreshReg$(Outer, 'Outer');
    
  900. 
    
  901.         function App() {
    
  902.           return (
    
  903.             <React.Suspense fallback={<p>Loading</p>}>
    
  904.               <Outer />
    
  905.             </React.Suspense>
    
  906.           );
    
  907.         }
    
  908.         $RefreshReg$(App, 'App');
    
  909. 
    
  910.         return App;
    
  911.       });
    
  912. 
    
  913.       // Assert the state was preserved but color changed.
    
  914.       expect(container.firstChild).toBe(el);
    
  915.       expect(el.textContent).toBe('1');
    
  916.       expect(el.style.color).toBe('red');
    
  917. 
    
  918.       // Bump the state again.
    
  919.       act(() => {
    
  920.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  921.       });
    
  922.       expect(container.firstChild).toBe(el);
    
  923.       expect(el.textContent).toBe('2');
    
  924.       expect(el.style.color).toBe('red');
    
  925. 
    
  926.       // Perform top-down renders with both fresh and stale types.
    
  927.       // Neither should change the state or color.
    
  928.       // They should always resolve to the latest version.
    
  929.       render(() => AppV1);
    
  930.       render(() => AppV2);
    
  931.       render(() => AppV1);
    
  932.       expect(container.firstChild).toBe(el);
    
  933.       expect(el.textContent).toBe('2');
    
  934.       expect(el.style.color).toBe('red');
    
  935. 
    
  936.       // Finally, a render with incompatible type should reset it.
    
  937.       render(() => {
    
  938.         function Hello() {
    
  939.           const [val, setVal] = React.useState(0);
    
  940.           return (
    
  941.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  942.               {val}
    
  943.             </p>
    
  944.           );
    
  945.         }
    
  946.         $RefreshReg$(Hello, 'Hello');
    
  947. 
    
  948.         // Note: no lazy wrapper this time.
    
  949. 
    
  950.         function App() {
    
  951.           return (
    
  952.             <React.Suspense fallback={<p>Loading</p>}>
    
  953.               <Hello />
    
  954.             </React.Suspense>
    
  955.           );
    
  956.         }
    
  957.         $RefreshReg$(App, 'App');
    
  958. 
    
  959.         return App;
    
  960.       });
    
  961. 
    
  962.       expect(container.firstChild).not.toBe(el);
    
  963.       const newEl = container.firstChild;
    
  964.       expect(newEl.textContent).toBe('0');
    
  965.       expect(newEl.style.color).toBe('blue');
    
  966.     }
    
  967.   });
    
  968. 
    
  969.   it('can patch lazy before resolution', async () => {
    
  970.     if (__DEV__) {
    
  971.       render(() => {
    
  972.         function Hello() {
    
  973.           const [val, setVal] = React.useState(0);
    
  974.           return (
    
  975.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  976.               {val}
    
  977.             </p>
    
  978.           );
    
  979.         }
    
  980.         $RefreshReg$(Hello, 'Hello');
    
  981. 
    
  982.         const Outer = React.lazy(
    
  983.           () =>
    
  984.             new Promise(resolve => {
    
  985.               setTimeout(() => resolve({default: Hello}), 100);
    
  986.             }),
    
  987.         );
    
  988.         $RefreshReg$(Outer, 'Outer');
    
  989. 
    
  990.         function App() {
    
  991.           return (
    
  992.             <React.Suspense fallback={<p>Loading</p>}>
    
  993.               <Outer />
    
  994.             </React.Suspense>
    
  995.           );
    
  996.         }
    
  997. 
    
  998.         return App;
    
  999.       });
    
  1000. 
    
  1001.       expect(container.textContent).toBe('Loading');
    
  1002. 
    
  1003.       // Perform a hot update.
    
  1004.       patch(() => {
    
  1005.         function Hello() {
    
  1006.           const [val, setVal] = React.useState(0);
    
  1007.           return (
    
  1008.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1009.               {val}
    
  1010.             </p>
    
  1011.           );
    
  1012.         }
    
  1013.         $RefreshReg$(Hello, 'Hello');
    
  1014.       });
    
  1015. 
    
  1016.       await act(() => {
    
  1017.         jest.runAllTimers();
    
  1018.       });
    
  1019. 
    
  1020.       // Expect different color on initial mount.
    
  1021.       const el = container.firstChild;
    
  1022.       expect(el.textContent).toBe('0');
    
  1023.       expect(el.style.color).toBe('red');
    
  1024. 
    
  1025.       // Bump state.
    
  1026.       act(() => {
    
  1027.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1028.       });
    
  1029.       expect(container.firstChild).toBe(el);
    
  1030.       expect(el.textContent).toBe('1');
    
  1031.       expect(el.style.color).toBe('red');
    
  1032. 
    
  1033.       // Test another reload.
    
  1034.       patch(() => {
    
  1035.         function Hello() {
    
  1036.           const [val, setVal] = React.useState(0);
    
  1037.           return (
    
  1038.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  1039.               {val}
    
  1040.             </p>
    
  1041.           );
    
  1042.         }
    
  1043.         $RefreshReg$(Hello, 'Hello');
    
  1044.       });
    
  1045.       expect(container.firstChild).toBe(el);
    
  1046.       expect(el.textContent).toBe('1');
    
  1047.       expect(el.style.color).toBe('orange');
    
  1048.     }
    
  1049.   });
    
  1050. 
    
  1051.   it('can patch lazy(forwardRef) before resolution', async () => {
    
  1052.     if (__DEV__) {
    
  1053.       render(() => {
    
  1054.         function renderHello() {
    
  1055.           const [val, setVal] = React.useState(0);
    
  1056.           return (
    
  1057.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1058.               {val}
    
  1059.             </p>
    
  1060.           );
    
  1061.         }
    
  1062.         const Hello = React.forwardRef(renderHello);
    
  1063.         $RefreshReg$(Hello, 'Hello');
    
  1064. 
    
  1065.         const Outer = React.lazy(
    
  1066.           () =>
    
  1067.             new Promise(resolve => {
    
  1068.               setTimeout(() => resolve({default: Hello}), 100);
    
  1069.             }),
    
  1070.         );
    
  1071.         $RefreshReg$(Outer, 'Outer');
    
  1072. 
    
  1073.         function App() {
    
  1074.           return (
    
  1075.             <React.Suspense fallback={<p>Loading</p>}>
    
  1076.               <Outer />
    
  1077.             </React.Suspense>
    
  1078.           );
    
  1079.         }
    
  1080. 
    
  1081.         return App;
    
  1082.       });
    
  1083. 
    
  1084.       expect(container.textContent).toBe('Loading');
    
  1085. 
    
  1086.       // Perform a hot update.
    
  1087.       patch(() => {
    
  1088.         function renderHello() {
    
  1089.           const [val, setVal] = React.useState(0);
    
  1090.           return (
    
  1091.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1092.               {val}
    
  1093.             </p>
    
  1094.           );
    
  1095.         }
    
  1096.         const Hello = React.forwardRef(renderHello);
    
  1097.         $RefreshReg$(Hello, 'Hello');
    
  1098.       });
    
  1099. 
    
  1100.       await act(() => {
    
  1101.         jest.runAllTimers();
    
  1102.       });
    
  1103. 
    
  1104.       // Expect different color on initial mount.
    
  1105.       const el = container.firstChild;
    
  1106.       expect(el.textContent).toBe('0');
    
  1107.       expect(el.style.color).toBe('red');
    
  1108. 
    
  1109.       // Bump state.
    
  1110.       act(() => {
    
  1111.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1112.       });
    
  1113.       expect(container.firstChild).toBe(el);
    
  1114.       expect(el.textContent).toBe('1');
    
  1115.       expect(el.style.color).toBe('red');
    
  1116. 
    
  1117.       // Test another reload.
    
  1118.       patch(() => {
    
  1119.         function renderHello() {
    
  1120.           const [val, setVal] = React.useState(0);
    
  1121.           return (
    
  1122.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  1123.               {val}
    
  1124.             </p>
    
  1125.           );
    
  1126.         }
    
  1127.         const Hello = React.forwardRef(renderHello);
    
  1128.         $RefreshReg$(Hello, 'Hello');
    
  1129.       });
    
  1130.       expect(container.firstChild).toBe(el);
    
  1131.       expect(el.textContent).toBe('1');
    
  1132.       expect(el.style.color).toBe('orange');
    
  1133.     }
    
  1134.   });
    
  1135. 
    
  1136.   it('can patch lazy(memo) before resolution', async () => {
    
  1137.     if (__DEV__) {
    
  1138.       render(() => {
    
  1139.         function renderHello() {
    
  1140.           const [val, setVal] = React.useState(0);
    
  1141.           return (
    
  1142.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1143.               {val}
    
  1144.             </p>
    
  1145.           );
    
  1146.         }
    
  1147.         const Hello = React.memo(renderHello);
    
  1148.         $RefreshReg$(Hello, 'Hello');
    
  1149. 
    
  1150.         const Outer = React.lazy(
    
  1151.           () =>
    
  1152.             new Promise(resolve => {
    
  1153.               setTimeout(() => resolve({default: Hello}), 100);
    
  1154.             }),
    
  1155.         );
    
  1156.         $RefreshReg$(Outer, 'Outer');
    
  1157. 
    
  1158.         function App() {
    
  1159.           return (
    
  1160.             <React.Suspense fallback={<p>Loading</p>}>
    
  1161.               <Outer />
    
  1162.             </React.Suspense>
    
  1163.           );
    
  1164.         }
    
  1165. 
    
  1166.         return App;
    
  1167.       });
    
  1168. 
    
  1169.       expect(container.textContent).toBe('Loading');
    
  1170. 
    
  1171.       // Perform a hot update.
    
  1172.       patch(() => {
    
  1173.         function renderHello() {
    
  1174.           const [val, setVal] = React.useState(0);
    
  1175.           return (
    
  1176.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1177.               {val}
    
  1178.             </p>
    
  1179.           );
    
  1180.         }
    
  1181.         const Hello = React.memo(renderHello);
    
  1182.         $RefreshReg$(Hello, 'Hello');
    
  1183.       });
    
  1184. 
    
  1185.       await act(() => {
    
  1186.         jest.runAllTimers();
    
  1187.       });
    
  1188. 
    
  1189.       // Expect different color on initial mount.
    
  1190.       const el = container.firstChild;
    
  1191.       expect(el.textContent).toBe('0');
    
  1192.       expect(el.style.color).toBe('red');
    
  1193. 
    
  1194.       // Bump state.
    
  1195.       act(() => {
    
  1196.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1197.       });
    
  1198.       expect(container.firstChild).toBe(el);
    
  1199.       expect(el.textContent).toBe('1');
    
  1200.       expect(el.style.color).toBe('red');
    
  1201. 
    
  1202.       // Test another reload.
    
  1203.       patch(() => {
    
  1204.         function renderHello() {
    
  1205.           const [val, setVal] = React.useState(0);
    
  1206.           return (
    
  1207.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  1208.               {val}
    
  1209.             </p>
    
  1210.           );
    
  1211.         }
    
  1212.         const Hello = React.memo(renderHello);
    
  1213.         $RefreshReg$(Hello, 'Hello');
    
  1214.       });
    
  1215.       expect(container.firstChild).toBe(el);
    
  1216.       expect(el.textContent).toBe('1');
    
  1217.       expect(el.style.color).toBe('orange');
    
  1218.     }
    
  1219.   });
    
  1220. 
    
  1221.   it('can patch lazy(memo(forwardRef)) before resolution', async () => {
    
  1222.     if (__DEV__) {
    
  1223.       render(() => {
    
  1224.         function renderHello() {
    
  1225.           const [val, setVal] = React.useState(0);
    
  1226.           return (
    
  1227.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1228.               {val}
    
  1229.             </p>
    
  1230.           );
    
  1231.         }
    
  1232.         const Hello = React.memo(React.forwardRef(renderHello));
    
  1233.         $RefreshReg$(Hello, 'Hello');
    
  1234. 
    
  1235.         const Outer = React.lazy(
    
  1236.           () =>
    
  1237.             new Promise(resolve => {
    
  1238.               setTimeout(() => resolve({default: Hello}), 100);
    
  1239.             }),
    
  1240.         );
    
  1241.         $RefreshReg$(Outer, 'Outer');
    
  1242. 
    
  1243.         function App() {
    
  1244.           return (
    
  1245.             <React.Suspense fallback={<p>Loading</p>}>
    
  1246.               <Outer />
    
  1247.             </React.Suspense>
    
  1248.           );
    
  1249.         }
    
  1250. 
    
  1251.         return App;
    
  1252.       });
    
  1253. 
    
  1254.       expect(container.textContent).toBe('Loading');
    
  1255. 
    
  1256.       // Perform a hot update.
    
  1257.       patch(() => {
    
  1258.         function renderHello() {
    
  1259.           const [val, setVal] = React.useState(0);
    
  1260.           return (
    
  1261.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1262.               {val}
    
  1263.             </p>
    
  1264.           );
    
  1265.         }
    
  1266.         const Hello = React.memo(React.forwardRef(renderHello));
    
  1267.         $RefreshReg$(Hello, 'Hello');
    
  1268.       });
    
  1269. 
    
  1270.       await act(() => {
    
  1271.         jest.runAllTimers();
    
  1272.       });
    
  1273. 
    
  1274.       // Expect different color on initial mount.
    
  1275.       const el = container.firstChild;
    
  1276.       expect(el.textContent).toBe('0');
    
  1277.       expect(el.style.color).toBe('red');
    
  1278. 
    
  1279.       // Bump state.
    
  1280.       act(() => {
    
  1281.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1282.       });
    
  1283.       expect(container.firstChild).toBe(el);
    
  1284.       expect(el.textContent).toBe('1');
    
  1285.       expect(el.style.color).toBe('red');
    
  1286. 
    
  1287.       // Test another reload.
    
  1288.       patch(() => {
    
  1289.         function renderHello() {
    
  1290.           const [val, setVal] = React.useState(0);
    
  1291.           return (
    
  1292.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  1293.               {val}
    
  1294.             </p>
    
  1295.           );
    
  1296.         }
    
  1297.         const Hello = React.memo(React.forwardRef(renderHello));
    
  1298.         $RefreshReg$(Hello, 'Hello');
    
  1299.       });
    
  1300.       expect(container.firstChild).toBe(el);
    
  1301.       expect(el.textContent).toBe('1');
    
  1302.       expect(el.style.color).toBe('orange');
    
  1303.     }
    
  1304.   });
    
  1305. 
    
  1306.   it('can patch both trees while suspense is displaying the fallback', async () => {
    
  1307.     if (__DEV__) {
    
  1308.       const AppV1 = render(
    
  1309.         () => {
    
  1310.           function Hello({children}) {
    
  1311.             const [val, setVal] = React.useState(0);
    
  1312.             return (
    
  1313.               <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1314.                 {children} {val}
    
  1315.               </p>
    
  1316.             );
    
  1317.           }
    
  1318.           $RefreshReg$(Hello, 'Hello');
    
  1319. 
    
  1320.           function Never() {
    
  1321.             throw new Promise(resolve => {});
    
  1322.           }
    
  1323. 
    
  1324.           function App({shouldSuspend}) {
    
  1325.             return (
    
  1326.               <React.Suspense fallback={<Hello>Fallback</Hello>}>
    
  1327.                 <Hello>Content</Hello>
    
  1328.                 {shouldSuspend && <Never />}
    
  1329.               </React.Suspense>
    
  1330.             );
    
  1331.           }
    
  1332. 
    
  1333.           return App;
    
  1334.         },
    
  1335.         {shouldSuspend: false},
    
  1336.       );
    
  1337. 
    
  1338.       // We start with just the primary tree.
    
  1339.       expect(container.childNodes.length).toBe(1);
    
  1340.       const primaryChild = container.firstChild;
    
  1341.       expect(primaryChild.textContent).toBe('Content 0');
    
  1342.       expect(primaryChild.style.color).toBe('blue');
    
  1343.       expect(primaryChild.style.display).toBe('');
    
  1344. 
    
  1345.       // Bump primary content state.
    
  1346.       act(() => {
    
  1347.         primaryChild.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1348.       });
    
  1349.       expect(container.childNodes.length).toBe(1);
    
  1350.       expect(container.childNodes[0]).toBe(primaryChild);
    
  1351.       expect(primaryChild.textContent).toBe('Content 1');
    
  1352.       expect(primaryChild.style.color).toBe('blue');
    
  1353.       expect(primaryChild.style.display).toBe('');
    
  1354. 
    
  1355.       // Perform a hot update.
    
  1356.       patch(() => {
    
  1357.         function Hello({children}) {
    
  1358.           const [val, setVal] = React.useState(0);
    
  1359.           return (
    
  1360.             <p style={{color: 'green'}} onClick={() => setVal(val + 1)}>
    
  1361.               {children} {val}
    
  1362.             </p>
    
  1363.           );
    
  1364.         }
    
  1365.         $RefreshReg$(Hello, 'Hello');
    
  1366.       });
    
  1367.       expect(container.childNodes.length).toBe(1);
    
  1368.       expect(container.childNodes[0]).toBe(primaryChild);
    
  1369.       expect(primaryChild.textContent).toBe('Content 1');
    
  1370.       expect(primaryChild.style.color).toBe('green');
    
  1371.       expect(primaryChild.style.display).toBe('');
    
  1372. 
    
  1373.       // Now force the tree to suspend.
    
  1374.       render(() => AppV1, {shouldSuspend: true});
    
  1375. 
    
  1376.       // Expect to see two trees, one of them is hidden.
    
  1377.       expect(container.childNodes.length).toBe(2);
    
  1378.       expect(container.childNodes[0]).toBe(primaryChild);
    
  1379.       const fallbackChild = container.childNodes[1];
    
  1380.       expect(primaryChild.textContent).toBe('Content 1');
    
  1381.       expect(primaryChild.style.color).toBe('green');
    
  1382.       expect(primaryChild.style.display).toBe('none');
    
  1383.       expect(fallbackChild.textContent).toBe('Fallback 0');
    
  1384.       expect(fallbackChild.style.color).toBe('green');
    
  1385.       expect(fallbackChild.style.display).toBe('');
    
  1386. 
    
  1387.       // Bump fallback state.
    
  1388.       act(() => {
    
  1389.         fallbackChild.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1390.       });
    
  1391.       expect(container.childNodes.length).toBe(2);
    
  1392.       expect(container.childNodes[0]).toBe(primaryChild);
    
  1393.       expect(container.childNodes[1]).toBe(fallbackChild);
    
  1394.       expect(primaryChild.textContent).toBe('Content 1');
    
  1395.       expect(primaryChild.style.color).toBe('green');
    
  1396.       expect(primaryChild.style.display).toBe('none');
    
  1397.       expect(fallbackChild.textContent).toBe('Fallback 1');
    
  1398.       expect(fallbackChild.style.color).toBe('green');
    
  1399.       expect(fallbackChild.style.display).toBe('');
    
  1400. 
    
  1401.       // Perform a hot update.
    
  1402.       patch(() => {
    
  1403.         function Hello({children}) {
    
  1404.           const [val, setVal] = React.useState(0);
    
  1405.           return (
    
  1406.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1407.               {children} {val}
    
  1408.             </p>
    
  1409.           );
    
  1410.         }
    
  1411.         $RefreshReg$(Hello, 'Hello');
    
  1412.       });
    
  1413. 
    
  1414.       // Colors inside both trees should change:
    
  1415.       expect(container.childNodes.length).toBe(2);
    
  1416.       expect(container.childNodes[0]).toBe(primaryChild);
    
  1417.       expect(container.childNodes[1]).toBe(fallbackChild);
    
  1418.       expect(primaryChild.textContent).toBe('Content 1');
    
  1419.       expect(primaryChild.style.color).toBe('red');
    
  1420.       expect(primaryChild.style.display).toBe('none');
    
  1421.       expect(fallbackChild.textContent).toBe('Fallback 1');
    
  1422.       expect(fallbackChild.style.color).toBe('red');
    
  1423.       expect(fallbackChild.style.display).toBe('');
    
  1424. 
    
  1425.       // Only primary tree should exist now:
    
  1426.       render(() => AppV1, {shouldSuspend: false});
    
  1427.       expect(container.childNodes.length).toBe(1);
    
  1428.       expect(container.childNodes[0]).toBe(primaryChild);
    
  1429.       expect(primaryChild.textContent).toBe('Content 1');
    
  1430.       expect(primaryChild.style.color).toBe('red');
    
  1431.       expect(primaryChild.style.display).toBe('');
    
  1432. 
    
  1433.       // Perform a hot update.
    
  1434.       patch(() => {
    
  1435.         function Hello({children}) {
    
  1436.           const [val, setVal] = React.useState(0);
    
  1437.           return (
    
  1438.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  1439.               {children} {val}
    
  1440.             </p>
    
  1441.           );
    
  1442.         }
    
  1443.         $RefreshReg$(Hello, 'Hello');
    
  1444.       });
    
  1445.       expect(container.childNodes.length).toBe(1);
    
  1446.       expect(container.childNodes[0]).toBe(primaryChild);
    
  1447.       expect(primaryChild.textContent).toBe('Content 1');
    
  1448.       expect(primaryChild.style.color).toBe('orange');
    
  1449.       expect(primaryChild.style.display).toBe('');
    
  1450.     }
    
  1451.   });
    
  1452. 
    
  1453.   it('does not re-render ancestor components unnecessarily during a hot update', () => {
    
  1454.     if (__DEV__) {
    
  1455.       let appRenders = 0;
    
  1456. 
    
  1457.       render(() => {
    
  1458.         function Hello() {
    
  1459.           const [val, setVal] = React.useState(0);
    
  1460.           return (
    
  1461.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1462.               {val}
    
  1463.             </p>
    
  1464.           );
    
  1465.         }
    
  1466.         $RefreshReg$(Hello, 'Hello');
    
  1467.         function App() {
    
  1468.           appRenders++;
    
  1469.           return <Hello />;
    
  1470.         }
    
  1471.         $RefreshReg$(App, 'App');
    
  1472.         return App;
    
  1473.       });
    
  1474. 
    
  1475.       expect(appRenders).toBe(1);
    
  1476. 
    
  1477.       // Bump the state before patching.
    
  1478.       const el = container.firstChild;
    
  1479.       expect(el.textContent).toBe('0');
    
  1480.       expect(el.style.color).toBe('blue');
    
  1481.       act(() => {
    
  1482.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1483.       });
    
  1484.       expect(el.textContent).toBe('1');
    
  1485. 
    
  1486.       // No re-renders from the top.
    
  1487.       expect(appRenders).toBe(1);
    
  1488. 
    
  1489.       // Perform a hot update for Hello only.
    
  1490.       patch(() => {
    
  1491.         function Hello() {
    
  1492.           const [val, setVal] = React.useState(0);
    
  1493.           return (
    
  1494.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1495.               {val}
    
  1496.             </p>
    
  1497.           );
    
  1498.         }
    
  1499.         $RefreshReg$(Hello, 'Hello');
    
  1500.       });
    
  1501. 
    
  1502.       // Assert the state was preserved but color changed.
    
  1503.       expect(container.firstChild).toBe(el);
    
  1504.       expect(el.textContent).toBe('1');
    
  1505.       expect(el.style.color).toBe('red');
    
  1506. 
    
  1507.       // Still no re-renders from the top.
    
  1508.       expect(appRenders).toBe(1);
    
  1509. 
    
  1510.       // Bump the state.
    
  1511.       act(() => {
    
  1512.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1513.       });
    
  1514.       expect(el.textContent).toBe('2');
    
  1515. 
    
  1516.       // Still no re-renders from the top.
    
  1517.       expect(appRenders).toBe(1);
    
  1518.     }
    
  1519.   });
    
  1520. 
    
  1521.   it('batches re-renders during a hot update', () => {
    
  1522.     if (__DEV__) {
    
  1523.       let helloRenders = 0;
    
  1524. 
    
  1525.       render(() => {
    
  1526.         function Hello({children}) {
    
  1527.           helloRenders++;
    
  1528.           return <div>X{children}X</div>;
    
  1529.         }
    
  1530.         $RefreshReg$(Hello, 'Hello');
    
  1531. 
    
  1532.         function App() {
    
  1533.           return (
    
  1534.             <Hello>
    
  1535.               <Hello>
    
  1536.                 <Hello />
    
  1537.               </Hello>
    
  1538.               <Hello>
    
  1539.                 <Hello />
    
  1540.               </Hello>
    
  1541.             </Hello>
    
  1542.           );
    
  1543.         }
    
  1544.         return App;
    
  1545.       });
    
  1546.       expect(helloRenders).toBe(5);
    
  1547.       expect(container.textContent).toBe('XXXXXXXXXX');
    
  1548.       helloRenders = 0;
    
  1549. 
    
  1550.       patch(() => {
    
  1551.         function Hello({children}) {
    
  1552.           helloRenders++;
    
  1553.           return <div>O{children}O</div>;
    
  1554.         }
    
  1555.         $RefreshReg$(Hello, 'Hello');
    
  1556.       });
    
  1557.       expect(helloRenders).toBe(5);
    
  1558.       expect(container.textContent).toBe('OOOOOOOOOO');
    
  1559.     }
    
  1560.   });
    
  1561. 
    
  1562.   it('does not leak state between components', () => {
    
  1563.     if (__DEV__) {
    
  1564.       const AppV1 = render(
    
  1565.         () => {
    
  1566.           function Hello1() {
    
  1567.             const [val, setVal] = React.useState(0);
    
  1568.             return (
    
  1569.               <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1570.                 {val}
    
  1571.               </p>
    
  1572.             );
    
  1573.           }
    
  1574.           $RefreshReg$(Hello1, 'Hello1');
    
  1575.           function Hello2() {
    
  1576.             const [val, setVal] = React.useState(0);
    
  1577.             return (
    
  1578.               <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1579.                 {val}
    
  1580.               </p>
    
  1581.             );
    
  1582.           }
    
  1583.           $RefreshReg$(Hello2, 'Hello2');
    
  1584.           function App({cond}) {
    
  1585.             return cond ? <Hello1 /> : <Hello2 />;
    
  1586.           }
    
  1587.           $RefreshReg$(App, 'App');
    
  1588.           return App;
    
  1589.         },
    
  1590.         {cond: false},
    
  1591.       );
    
  1592. 
    
  1593.       // Bump the state before patching.
    
  1594.       const el = container.firstChild;
    
  1595.       expect(el.textContent).toBe('0');
    
  1596.       expect(el.style.color).toBe('blue');
    
  1597.       act(() => {
    
  1598.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1599.       });
    
  1600.       expect(el.textContent).toBe('1');
    
  1601. 
    
  1602.       // Switch the condition, flipping inner content.
    
  1603.       // This should reset the state.
    
  1604.       render(() => AppV1, {cond: true});
    
  1605.       const el2 = container.firstChild;
    
  1606.       expect(el2).not.toBe(el);
    
  1607.       expect(el2.textContent).toBe('0');
    
  1608.       expect(el2.style.color).toBe('blue');
    
  1609. 
    
  1610.       // Bump it again.
    
  1611.       act(() => {
    
  1612.         el2.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1613.       });
    
  1614.       expect(el2.textContent).toBe('1');
    
  1615. 
    
  1616.       // Perform a hot update for both inner components.
    
  1617.       patch(() => {
    
  1618.         function Hello1() {
    
  1619.           const [val, setVal] = React.useState(0);
    
  1620.           return (
    
  1621.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1622.               {val}
    
  1623.             </p>
    
  1624.           );
    
  1625.         }
    
  1626.         $RefreshReg$(Hello1, 'Hello1');
    
  1627.         function Hello2() {
    
  1628.           const [val, setVal] = React.useState(0);
    
  1629.           return (
    
  1630.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1631.               {val}
    
  1632.             </p>
    
  1633.           );
    
  1634.         }
    
  1635.         $RefreshReg$(Hello2, 'Hello2');
    
  1636.       });
    
  1637. 
    
  1638.       // Assert the state was preserved but color changed.
    
  1639.       expect(container.firstChild).toBe(el2);
    
  1640.       expect(el2.textContent).toBe('1');
    
  1641.       expect(el2.style.color).toBe('red');
    
  1642. 
    
  1643.       // Flip the condition again.
    
  1644.       render(() => AppV1, {cond: false});
    
  1645.       const el3 = container.firstChild;
    
  1646.       expect(el3).not.toBe(el2);
    
  1647.       expect(el3.textContent).toBe('0');
    
  1648.       expect(el3.style.color).toBe('red');
    
  1649.     }
    
  1650.   });
    
  1651. 
    
  1652.   it('can force remount by changing signature', () => {
    
  1653.     if (__DEV__) {
    
  1654.       const HelloV1 = render(() => {
    
  1655.         function Hello() {
    
  1656.           const [val, setVal] = React.useState(0);
    
  1657.           return (
    
  1658.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  1659.               {val}
    
  1660.             </p>
    
  1661.           );
    
  1662.         }
    
  1663.         $RefreshReg$(Hello, 'Hello');
    
  1664.         // When this changes, we'll expect a remount:
    
  1665.         $RefreshSig$(Hello, '1');
    
  1666.         return Hello;
    
  1667.       });
    
  1668. 
    
  1669.       // Bump the state before patching.
    
  1670.       const el = container.firstChild;
    
  1671.       expect(el.textContent).toBe('0');
    
  1672.       expect(el.style.color).toBe('blue');
    
  1673.       act(() => {
    
  1674.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1675.       });
    
  1676.       expect(el.textContent).toBe('1');
    
  1677. 
    
  1678.       // Perform a hot update.
    
  1679.       const HelloV2 = patch(() => {
    
  1680.         function Hello() {
    
  1681.           const [val, setVal] = React.useState(0);
    
  1682.           return (
    
  1683.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  1684.               {val}
    
  1685.             </p>
    
  1686.           );
    
  1687.         }
    
  1688.         $RefreshReg$(Hello, 'Hello');
    
  1689.         // The signature hasn't changed since the last time:
    
  1690.         $RefreshSig$(Hello, '1');
    
  1691.         return Hello;
    
  1692.       });
    
  1693. 
    
  1694.       // Assert the state was preserved but color changed.
    
  1695.       expect(container.firstChild).toBe(el);
    
  1696.       expect(el.textContent).toBe('1');
    
  1697.       expect(el.style.color).toBe('red');
    
  1698. 
    
  1699.       // Perform a hot update.
    
  1700.       const HelloV3 = patch(() => {
    
  1701.         function Hello() {
    
  1702.           const [val, setVal] = React.useState(0);
    
  1703.           return (
    
  1704.             <p style={{color: 'yellow'}} onClick={() => setVal(val + 1)}>
    
  1705.               {val}
    
  1706.             </p>
    
  1707.           );
    
  1708.         }
    
  1709.         // We're changing the signature now so it will remount:
    
  1710.         $RefreshReg$(Hello, 'Hello');
    
  1711.         $RefreshSig$(Hello, '2');
    
  1712.         return Hello;
    
  1713.       });
    
  1714. 
    
  1715.       // Expect a remount.
    
  1716.       expect(container.firstChild).not.toBe(el);
    
  1717.       const newEl = container.firstChild;
    
  1718.       expect(newEl.textContent).toBe('0');
    
  1719.       expect(newEl.style.color).toBe('yellow');
    
  1720. 
    
  1721.       // Bump state again.
    
  1722.       act(() => {
    
  1723.         newEl.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  1724.       });
    
  1725.       expect(newEl.textContent).toBe('1');
    
  1726.       expect(newEl.style.color).toBe('yellow');
    
  1727. 
    
  1728.       // Perform top-down renders with both fresh and stale types.
    
  1729.       // Neither should change the state or color.
    
  1730.       // They should always resolve to the latest version.
    
  1731.       render(() => HelloV1);
    
  1732.       render(() => HelloV2);
    
  1733.       render(() => HelloV3);
    
  1734.       render(() => HelloV2);
    
  1735.       render(() => HelloV1);
    
  1736.       expect(container.firstChild).toBe(newEl);
    
  1737.       expect(newEl.textContent).toBe('1');
    
  1738.       expect(newEl.style.color).toBe('yellow');
    
  1739. 
    
  1740.       // Verify we can patch again while preserving the signature.
    
  1741.       patch(() => {
    
  1742.         function Hello() {
    
  1743.           const [val, setVal] = React.useState(0);
    
  1744.           return (
    
  1745.             <p style={{color: 'purple'}} onClick={() => setVal(val + 1)}>
    
  1746.               {val}
    
  1747.             </p>
    
  1748.           );
    
  1749.         }
    
  1750.         // Same signature as last time.
    
  1751.         $RefreshReg$(Hello, 'Hello');
    
  1752.         $RefreshSig$(Hello, '2');
    
  1753.         return Hello;
    
  1754.       });
    
  1755. 
    
  1756.       expect(container.firstChild).toBe(newEl);
    
  1757.       expect(newEl.textContent).toBe('1');
    
  1758.       expect(newEl.style.color).toBe('purple');
    
  1759. 
    
  1760.       // Check removing the signature also causes a remount.
    
  1761.       patch(() => {
    
  1762.         function Hello() {
    
  1763.           const [val, setVal] = React.useState(0);
    
  1764.           return (
    
  1765.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  1766.               {val}
    
  1767.             </p>
    
  1768.           );
    
  1769.         }
    
  1770.         // No signature this time.
    
  1771.         $RefreshReg$(Hello, 'Hello');
    
  1772.         return Hello;
    
  1773.       });
    
  1774. 
    
  1775.       // Expect a remount.
    
  1776.       expect(container.firstChild).not.toBe(newEl);
    
  1777.       const finalEl = container.firstChild;
    
  1778.       expect(finalEl.textContent).toBe('0');
    
  1779.       expect(finalEl.style.color).toBe('orange');
    
  1780.     }
    
  1781.   });
    
  1782. 
    
  1783.   it('keeps a valid tree when forcing remount', () => {
    
  1784.     if (__DEV__) {
    
  1785.       const HelloV1 = prepare(() => {
    
  1786.         function Hello() {
    
  1787.           return null;
    
  1788.         }
    
  1789.         $RefreshReg$(Hello, 'Hello');
    
  1790.         $RefreshSig$(Hello, '1');
    
  1791.         return Hello;
    
  1792.       });
    
  1793. 
    
  1794.       const Bailout = React.memo(({children}) => {
    
  1795.         return children;
    
  1796.       });
    
  1797. 
    
  1798.       // Each of those renders three instances of HelloV1,
    
  1799.       // but in different ways.
    
  1800.       const trees = [
    
  1801.         <div>
    
  1802.           <HelloV1 />
    
  1803.           <div>
    
  1804.             <HelloV1 />
    
  1805.             <Bailout>
    
  1806.               <HelloV1 />
    
  1807.             </Bailout>
    
  1808.           </div>
    
  1809.         </div>,
    
  1810.         <div>
    
  1811.           <div>
    
  1812.             <HelloV1>
    
  1813.               <HelloV1 />
    
  1814.             </HelloV1>
    
  1815.             <HelloV1 />
    
  1816.           </div>
    
  1817.         </div>,
    
  1818.         <div>
    
  1819.           <span />
    
  1820.           <HelloV1 />
    
  1821.           <HelloV1 />
    
  1822.           <HelloV1 />
    
  1823.         </div>,
    
  1824.         <div>
    
  1825.           <HelloV1 />
    
  1826.           <span />
    
  1827.           <HelloV1 />
    
  1828.           <HelloV1 />
    
  1829.         </div>,
    
  1830.         <div>
    
  1831.           <div>foo</div>
    
  1832.           <HelloV1 />
    
  1833.           <div>
    
  1834.             <HelloV1 />
    
  1835.           </div>
    
  1836.           <HelloV1 />
    
  1837.           <span />
    
  1838.         </div>,
    
  1839.         <div>
    
  1840.           <HelloV1>
    
  1841.             <span />
    
  1842.             Hello
    
  1843.             <span />
    
  1844.           </HelloV1>
    
  1845.           ,
    
  1846.           <HelloV1>
    
  1847.             <>
    
  1848.               <HelloV1 />
    
  1849.             </>
    
  1850.           </HelloV1>
    
  1851.           ,
    
  1852.         </div>,
    
  1853.         <HelloV1>
    
  1854.           <HelloV1>
    
  1855.             <Bailout>
    
  1856.               <span />
    
  1857.               <HelloV1>
    
  1858.                 <span />
    
  1859.               </HelloV1>
    
  1860.               <span />
    
  1861.             </Bailout>
    
  1862.           </HelloV1>
    
  1863.         </HelloV1>,
    
  1864.         <div>
    
  1865.           <span />
    
  1866.           <HelloV1 key="0" />
    
  1867.           <HelloV1 key="1" />
    
  1868.           <HelloV1 key="2" />
    
  1869.           <span />
    
  1870.         </div>,
    
  1871.         <div>
    
  1872.           <span />
    
  1873.           {null}
    
  1874.           <HelloV1 key="1" />
    
  1875.           {null}
    
  1876.           <HelloV1 />
    
  1877.           <HelloV1 />
    
  1878.           <span />
    
  1879.         </div>,
    
  1880.         <div>
    
  1881.           <HelloV1 key="2" />
    
  1882.           <span />
    
  1883.           <HelloV1 key="0" />
    
  1884.           <span />
    
  1885.           <HelloV1 key="1" />
    
  1886.         </div>,
    
  1887.         <div>
    
  1888.           {[[<HelloV1 key="2" />]]}
    
  1889.           <span>
    
  1890.             <HelloV1 key="0" />
    
  1891.             {[null]}
    
  1892.             <HelloV1 key="1" />
    
  1893.           </span>
    
  1894.         </div>,
    
  1895.         <div>
    
  1896.           {['foo', <HelloV1 key="hi" />, null, <HelloV1 key="2" />]}
    
  1897.           <span>
    
  1898.             {[null]}
    
  1899.             <HelloV1 key="x" />
    
  1900.           </span>
    
  1901.         </div>,
    
  1902.         <HelloV1>
    
  1903.           <HelloV1>
    
  1904.             <span />
    
  1905.             <Bailout>
    
  1906.               <HelloV1>hi</HelloV1>
    
  1907.               <span />
    
  1908.             </Bailout>
    
  1909.           </HelloV1>
    
  1910.         </HelloV1>,
    
  1911.       ];
    
  1912. 
    
  1913.       // First, check that each tree handles remounts in isolation.
    
  1914.       ReactDOM.render(null, container);
    
  1915.       for (let i = 0; i < trees.length; i++) {
    
  1916.         runRemountingStressTest(trees[i]);
    
  1917.       }
    
  1918. 
    
  1919.       // Then check that each tree is resilient to updates from another tree.
    
  1920.       for (let i = 0; i < trees.length; i++) {
    
  1921.         for (let j = 0; j < trees.length; j++) {
    
  1922.           ReactDOM.render(null, container);
    
  1923.           // Intentionally don't clean up between the tests:
    
  1924.           runRemountingStressTest(trees[i]);
    
  1925.           runRemountingStressTest(trees[j]);
    
  1926.           runRemountingStressTest(trees[i]);
    
  1927.         }
    
  1928.       }
    
  1929.     }
    
  1930.   });
    
  1931. 
    
  1932.   function runRemountingStressTest(tree) {
    
  1933.     patch(() => {
    
  1934.       function Hello({children}) {
    
  1935.         return <section data-color="blue">{children}</section>;
    
  1936.       }
    
  1937.       $RefreshReg$(Hello, 'Hello');
    
  1938.       $RefreshSig$(Hello, '1');
    
  1939.       return Hello;
    
  1940.     });
    
  1941. 
    
  1942.     ReactDOM.render(tree, container);
    
  1943.     const elements = container.querySelectorAll('section');
    
  1944.     // Each tree above produces exactly three <section> elements:
    
  1945.     expect(elements.length).toBe(3);
    
  1946.     elements.forEach(el => {
    
  1947.       expect(el.dataset.color).toBe('blue');
    
  1948.     });
    
  1949. 
    
  1950.     // Patch color without changing the signature.
    
  1951.     patch(() => {
    
  1952.       function Hello({children}) {
    
  1953.         return <section data-color="red">{children}</section>;
    
  1954.       }
    
  1955.       $RefreshReg$(Hello, 'Hello');
    
  1956.       $RefreshSig$(Hello, '1');
    
  1957.       return Hello;
    
  1958.     });
    
  1959. 
    
  1960.     const elementsAfterPatch = container.querySelectorAll('section');
    
  1961.     expect(elementsAfterPatch.length).toBe(3);
    
  1962.     elementsAfterPatch.forEach((el, index) => {
    
  1963.       // The signature hasn't changed so we expect DOM nodes to stay the same.
    
  1964.       expect(el).toBe(elements[index]);
    
  1965.       // However, the color should have changed:
    
  1966.       expect(el.dataset.color).toBe('red');
    
  1967.     });
    
  1968. 
    
  1969.     // Patch color *and* change the signature.
    
  1970.     patch(() => {
    
  1971.       function Hello({children}) {
    
  1972.         return <section data-color="orange">{children}</section>;
    
  1973.       }
    
  1974.       $RefreshReg$(Hello, 'Hello');
    
  1975.       $RefreshSig$(Hello, '2'); // Remount
    
  1976.       return Hello;
    
  1977.     });
    
  1978. 
    
  1979.     const elementsAfterRemount = container.querySelectorAll('section');
    
  1980.     expect(elementsAfterRemount.length).toBe(3);
    
  1981.     elementsAfterRemount.forEach((el, index) => {
    
  1982.       // The signature changed so we expect DOM nodes to be different.
    
  1983.       expect(el).not.toBe(elements[index]);
    
  1984.       // They should all be using the new color:
    
  1985.       expect(el.dataset.color).toBe('orange');
    
  1986.     });
    
  1987. 
    
  1988.     // Now patch color but *don't* change the signature.
    
  1989.     patch(() => {
    
  1990.       function Hello({children}) {
    
  1991.         return <section data-color="black">{children}</section>;
    
  1992.       }
    
  1993.       $RefreshReg$(Hello, 'Hello');
    
  1994.       $RefreshSig$(Hello, '2'); // Same signature as before
    
  1995.       return Hello;
    
  1996.     });
    
  1997. 
    
  1998.     expect(container.querySelectorAll('section').length).toBe(3);
    
  1999.     container.querySelectorAll('section').forEach((el, index) => {
    
  2000.       // The signature didn't change so DOM nodes should stay the same.
    
  2001.       expect(el).toBe(elementsAfterRemount[index]);
    
  2002.       // They should all be using the new color:
    
  2003.       expect(el.dataset.color).toBe('black');
    
  2004.     });
    
  2005. 
    
  2006.     // Do another render just in case.
    
  2007.     ReactDOM.render(tree, container);
    
  2008.     expect(container.querySelectorAll('section').length).toBe(3);
    
  2009.     container.querySelectorAll('section').forEach((el, index) => {
    
  2010.       expect(el).toBe(elementsAfterRemount[index]);
    
  2011.       expect(el.dataset.color).toBe('black');
    
  2012.     });
    
  2013.   }
    
  2014. 
    
  2015.   it('can remount on signature change within a <root> wrapper', () => {
    
  2016.     if (__DEV__) {
    
  2017.       testRemountingWithWrapper(Hello => Hello);
    
  2018.     }
    
  2019.   });
    
  2020. 
    
  2021.   it('can remount on signature change within a simple memo wrapper', () => {
    
  2022.     if (__DEV__) {
    
  2023.       testRemountingWithWrapper(Hello => React.memo(Hello));
    
  2024.     }
    
  2025.   });
    
  2026. 
    
  2027.   it('can remount on signature change within a lazy simple memo wrapper', () => {
    
  2028.     if (__DEV__) {
    
  2029.       testRemountingWithWrapper(Hello =>
    
  2030.         React.lazy(() => ({
    
  2031.           then(cb) {
    
  2032.             cb({default: React.memo(Hello)});
    
  2033.           },
    
  2034.         })),
    
  2035.       );
    
  2036.     }
    
  2037.   });
    
  2038. 
    
  2039.   it('can remount on signature change within forwardRef', () => {
    
  2040.     if (__DEV__) {
    
  2041.       testRemountingWithWrapper(Hello => React.forwardRef(Hello));
    
  2042.     }
    
  2043.   });
    
  2044. 
    
  2045.   it('can remount on signature change within forwardRef render function', () => {
    
  2046.     if (__DEV__) {
    
  2047.       testRemountingWithWrapper(Hello => React.forwardRef(() => <Hello />));
    
  2048.     }
    
  2049.   });
    
  2050. 
    
  2051.   it('can remount on signature change within nested memo', () => {
    
  2052.     if (__DEV__) {
    
  2053.       testRemountingWithWrapper(Hello =>
    
  2054.         React.memo(React.memo(React.memo(Hello))),
    
  2055.       );
    
  2056.     }
    
  2057.   });
    
  2058. 
    
  2059.   it('can remount on signature change within a memo wrapper and custom comparison', () => {
    
  2060.     if (__DEV__) {
    
  2061.       testRemountingWithWrapper(Hello => React.memo(Hello, () => true));
    
  2062.     }
    
  2063.   });
    
  2064. 
    
  2065.   it('can remount on signature change within a class', () => {
    
  2066.     if (__DEV__) {
    
  2067.       testRemountingWithWrapper(Hello => {
    
  2068.         const child = <Hello />;
    
  2069.         return class Wrapper extends React.PureComponent {
    
  2070.           render() {
    
  2071.             return child;
    
  2072.           }
    
  2073.         };
    
  2074.       });
    
  2075.     }
    
  2076.   });
    
  2077. 
    
  2078.   it('can remount on signature change within a context provider', () => {
    
  2079.     if (__DEV__) {
    
  2080.       testRemountingWithWrapper(Hello => {
    
  2081.         const Context = React.createContext();
    
  2082.         const child = (
    
  2083.           <Context.Provider value="constant">
    
  2084.             <Hello />
    
  2085.           </Context.Provider>
    
  2086.         );
    
  2087.         return function Wrapper() {
    
  2088.           return child;
    
  2089.         };
    
  2090.       });
    
  2091.     }
    
  2092.   });
    
  2093. 
    
  2094.   it('can remount on signature change within a context consumer', () => {
    
  2095.     if (__DEV__) {
    
  2096.       testRemountingWithWrapper(Hello => {
    
  2097.         const Context = React.createContext();
    
  2098.         const child = <Context.Consumer>{() => <Hello />}</Context.Consumer>;
    
  2099.         return function Wrapper() {
    
  2100.           return child;
    
  2101.         };
    
  2102.       });
    
  2103.     }
    
  2104.   });
    
  2105. 
    
  2106.   it('can remount on signature change within a suspense node', () => {
    
  2107.     if (__DEV__) {
    
  2108.       testRemountingWithWrapper(Hello => {
    
  2109.         // TODO: we'll probably want to test fallback trees too.
    
  2110.         const child = (
    
  2111.           <React.Suspense>
    
  2112.             <Hello />
    
  2113.           </React.Suspense>
    
  2114.         );
    
  2115.         return function Wrapper() {
    
  2116.           return child;
    
  2117.         };
    
  2118.       });
    
  2119.     }
    
  2120.   });
    
  2121. 
    
  2122.   it('can remount on signature change within a mode node', () => {
    
  2123.     if (__DEV__) {
    
  2124.       testRemountingWithWrapper(Hello => {
    
  2125.         const child = (
    
  2126.           <React.StrictMode>
    
  2127.             <Hello />
    
  2128.           </React.StrictMode>
    
  2129.         );
    
  2130.         return function Wrapper() {
    
  2131.           return child;
    
  2132.         };
    
  2133.       });
    
  2134.     }
    
  2135.   });
    
  2136. 
    
  2137.   it('can remount on signature change within a fragment node', () => {
    
  2138.     if (__DEV__) {
    
  2139.       testRemountingWithWrapper(Hello => {
    
  2140.         const child = (
    
  2141.           <>
    
  2142.             <Hello />
    
  2143.           </>
    
  2144.         );
    
  2145.         return function Wrapper() {
    
  2146.           return child;
    
  2147.         };
    
  2148.       });
    
  2149.     }
    
  2150.   });
    
  2151. 
    
  2152.   it('can remount on signature change within multiple siblings', () => {
    
  2153.     if (__DEV__) {
    
  2154.       testRemountingWithWrapper(Hello => {
    
  2155.         const child = (
    
  2156.           <>
    
  2157.             <>
    
  2158.               <React.Fragment />
    
  2159.             </>
    
  2160.             <Hello />
    
  2161.             <React.Fragment />
    
  2162.           </>
    
  2163.         );
    
  2164.         return function Wrapper() {
    
  2165.           return child;
    
  2166.         };
    
  2167.       });
    
  2168.     }
    
  2169.   });
    
  2170. 
    
  2171.   it('can remount on signature change within a profiler node', () => {
    
  2172.     if (__DEV__) {
    
  2173.       testRemountingWithWrapper(Hello => {
    
  2174.         const child = <Hello />;
    
  2175.         return function Wrapper() {
    
  2176.           return (
    
  2177.             <React.Profiler onRender={() => {}} id="foo">
    
  2178.               {child}
    
  2179.             </React.Profiler>
    
  2180.           );
    
  2181.         };
    
  2182.       });
    
  2183.     }
    
  2184.   });
    
  2185. 
    
  2186.   function testRemountingWithWrapper(wrap) {
    
  2187.     render(() => {
    
  2188.       function Hello() {
    
  2189.         const [val, setVal] = React.useState(0);
    
  2190.         return (
    
  2191.           <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  2192.             {val}
    
  2193.           </p>
    
  2194.         );
    
  2195.       }
    
  2196.       $RefreshReg$(Hello, 'Hello');
    
  2197.       // When this changes, we'll expect a remount:
    
  2198.       $RefreshSig$(Hello, '1');
    
  2199. 
    
  2200.       // Use the passed wrapper.
    
  2201.       // This will be different in every test.
    
  2202.       return wrap(Hello);
    
  2203.     });
    
  2204. 
    
  2205.     // Bump the state before patching.
    
  2206.     const el = container.firstChild;
    
  2207.     expect(el.textContent).toBe('0');
    
  2208.     expect(el.style.color).toBe('blue');
    
  2209.     act(() => {
    
  2210.       el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  2211.     });
    
  2212.     expect(el.textContent).toBe('1');
    
  2213. 
    
  2214.     // Perform a hot update that doesn't remount.
    
  2215.     patch(() => {
    
  2216.       function Hello() {
    
  2217.         const [val, setVal] = React.useState(0);
    
  2218.         return (
    
  2219.           <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  2220.             {val}
    
  2221.           </p>
    
  2222.         );
    
  2223.       }
    
  2224.       $RefreshReg$(Hello, 'Hello');
    
  2225.       // The signature hasn't changed since the last time:
    
  2226.       $RefreshSig$(Hello, '1');
    
  2227.       return Hello;
    
  2228.     });
    
  2229. 
    
  2230.     // Assert the state was preserved but color changed.
    
  2231.     expect(container.firstChild).toBe(el);
    
  2232.     expect(el.textContent).toBe('1');
    
  2233.     expect(el.style.color).toBe('red');
    
  2234. 
    
  2235.     // Perform a hot update that remounts.
    
  2236.     patch(() => {
    
  2237.       function Hello() {
    
  2238.         const [val, setVal] = React.useState(0);
    
  2239.         return (
    
  2240.           <p style={{color: 'yellow'}} onClick={() => setVal(val + 1)}>
    
  2241.             {val}
    
  2242.           </p>
    
  2243.         );
    
  2244.       }
    
  2245.       // We're changing the signature now so it will remount:
    
  2246.       $RefreshReg$(Hello, 'Hello');
    
  2247.       $RefreshSig$(Hello, '2');
    
  2248.       return Hello;
    
  2249.     });
    
  2250. 
    
  2251.     // Expect a remount.
    
  2252.     expect(container.firstChild).not.toBe(el);
    
  2253.     const newEl = container.firstChild;
    
  2254.     expect(newEl.textContent).toBe('0');
    
  2255.     expect(newEl.style.color).toBe('yellow');
    
  2256. 
    
  2257.     // Bump state again.
    
  2258.     act(() => {
    
  2259.       newEl.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  2260.     });
    
  2261.     expect(newEl.textContent).toBe('1');
    
  2262.     expect(newEl.style.color).toBe('yellow');
    
  2263. 
    
  2264.     // Verify we can patch again while preserving the signature.
    
  2265.     patch(() => {
    
  2266.       function Hello() {
    
  2267.         const [val, setVal] = React.useState(0);
    
  2268.         return (
    
  2269.           <p style={{color: 'purple'}} onClick={() => setVal(val + 1)}>
    
  2270.             {val}
    
  2271.           </p>
    
  2272.         );
    
  2273.       }
    
  2274.       // Same signature as last time.
    
  2275.       $RefreshReg$(Hello, 'Hello');
    
  2276.       $RefreshSig$(Hello, '2');
    
  2277.       return Hello;
    
  2278.     });
    
  2279. 
    
  2280.     expect(container.firstChild).toBe(newEl);
    
  2281.     expect(newEl.textContent).toBe('1');
    
  2282.     expect(newEl.style.color).toBe('purple');
    
  2283. 
    
  2284.     // Check removing the signature also causes a remount.
    
  2285.     patch(() => {
    
  2286.       function Hello() {
    
  2287.         const [val, setVal] = React.useState(0);
    
  2288.         return (
    
  2289.           <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  2290.             {val}
    
  2291.           </p>
    
  2292.         );
    
  2293.       }
    
  2294.       // No signature this time.
    
  2295.       $RefreshReg$(Hello, 'Hello');
    
  2296.       return Hello;
    
  2297.     });
    
  2298. 
    
  2299.     // Expect a remount.
    
  2300.     expect(container.firstChild).not.toBe(newEl);
    
  2301.     const finalEl = container.firstChild;
    
  2302.     expect(finalEl.textContent).toBe('0');
    
  2303.     expect(finalEl.style.color).toBe('orange');
    
  2304.   }
    
  2305. 
    
  2306.   it('resets hooks with dependencies on hot reload', () => {
    
  2307.     if (__DEV__) {
    
  2308.       let useEffectWithEmptyArrayCalls = 0;
    
  2309. 
    
  2310.       render(() => {
    
  2311.         function Hello() {
    
  2312.           const [val, setVal] = React.useState(0);
    
  2313.           const tranformed = React.useMemo(() => val * 2, [val]);
    
  2314.           const handleClick = React.useCallback(() => setVal(v => v + 1), []);
    
  2315. 
    
  2316.           React.useEffect(() => {
    
  2317.             useEffectWithEmptyArrayCalls++;
    
  2318.           }, []);
    
  2319. 
    
  2320.           return (
    
  2321.             <p style={{color: 'blue'}} onClick={handleClick}>
    
  2322.               {tranformed}
    
  2323.             </p>
    
  2324.           );
    
  2325.         }
    
  2326.         $RefreshReg$(Hello, 'Hello');
    
  2327.         return Hello;
    
  2328.       });
    
  2329. 
    
  2330.       // Bump the state before patching.
    
  2331.       const el = container.firstChild;
    
  2332.       expect(el.textContent).toBe('0');
    
  2333.       expect(el.style.color).toBe('blue');
    
  2334.       expect(useEffectWithEmptyArrayCalls).toBe(1); // useEffect ran
    
  2335.       act(() => {
    
  2336.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  2337.       });
    
  2338.       expect(el.textContent).toBe('2'); // val * 2
    
  2339.       expect(useEffectWithEmptyArrayCalls).toBe(1); // useEffect didn't re-run
    
  2340. 
    
  2341.       // Perform a hot update.
    
  2342.       act(() => {
    
  2343.         patch(() => {
    
  2344.           function Hello() {
    
  2345.             const [val, setVal] = React.useState(0);
    
  2346.             const tranformed = React.useMemo(() => val * 10, [val]);
    
  2347.             const handleClick = React.useCallback(() => setVal(v => v - 1), []);
    
  2348. 
    
  2349.             React.useEffect(() => {
    
  2350.               useEffectWithEmptyArrayCalls++;
    
  2351.             }, []);
    
  2352. 
    
  2353.             return (
    
  2354.               <p style={{color: 'red'}} onClick={handleClick}>
    
  2355.                 {tranformed}
    
  2356.               </p>
    
  2357.             );
    
  2358.           }
    
  2359.           $RefreshReg$(Hello, 'Hello');
    
  2360.           return Hello;
    
  2361.         });
    
  2362.       });
    
  2363. 
    
  2364.       // Assert the state was preserved but memo was evicted.
    
  2365.       expect(container.firstChild).toBe(el);
    
  2366.       expect(el.textContent).toBe('10'); // val * 10
    
  2367.       expect(el.style.color).toBe('red');
    
  2368.       expect(useEffectWithEmptyArrayCalls).toBe(2); // useEffect re-ran
    
  2369. 
    
  2370.       // This should fire the new callback which decreases the counter.
    
  2371.       act(() => {
    
  2372.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  2373.       });
    
  2374.       expect(el.textContent).toBe('0');
    
  2375.       expect(el.style.color).toBe('red');
    
  2376.       expect(useEffectWithEmptyArrayCalls).toBe(2); // useEffect didn't re-run
    
  2377.     }
    
  2378.   });
    
  2379. 
    
  2380.   // This pattern is inspired by useSubscription and similar mechanisms.
    
  2381.   it('does not get into infinite loops during render phase updates', () => {
    
  2382.     if (__DEV__) {
    
  2383.       render(() => {
    
  2384.         function Hello() {
    
  2385.           const source = React.useMemo(() => ({value: 10}), []);
    
  2386.           const [state, setState] = React.useState({value: null});
    
  2387.           if (state !== source) {
    
  2388.             setState(source);
    
  2389.           }
    
  2390.           return <p style={{color: 'blue'}}>{state.value}</p>;
    
  2391.         }
    
  2392.         $RefreshReg$(Hello, 'Hello');
    
  2393.         return Hello;
    
  2394.       });
    
  2395. 
    
  2396.       const el = container.firstChild;
    
  2397.       expect(el.textContent).toBe('10');
    
  2398.       expect(el.style.color).toBe('blue');
    
  2399. 
    
  2400.       // Perform a hot update.
    
  2401.       act(() => {
    
  2402.         patch(() => {
    
  2403.           function Hello() {
    
  2404.             const source = React.useMemo(() => ({value: 20}), []);
    
  2405.             const [state, setState] = React.useState({value: null});
    
  2406.             if (state !== source) {
    
  2407.               // This should perform a single render-phase update.
    
  2408.               setState(source);
    
  2409.             }
    
  2410.             return <p style={{color: 'red'}}>{state.value}</p>;
    
  2411.           }
    
  2412.           $RefreshReg$(Hello, 'Hello');
    
  2413.           return Hello;
    
  2414.         });
    
  2415.       });
    
  2416. 
    
  2417.       expect(container.firstChild).toBe(el);
    
  2418.       expect(el.textContent).toBe('20');
    
  2419.       expect(el.style.color).toBe('red');
    
  2420.     }
    
  2421.   });
    
  2422. 
    
  2423.   // @gate www && __DEV__
    
  2424.   it('can hot reload offscreen components', async () => {
    
  2425.     const AppV1 = prepare(() => {
    
  2426.       function Hello() {
    
  2427.         React.useLayoutEffect(() => {
    
  2428.           Scheduler.log('Hello#layout');
    
  2429.         });
    
  2430.         const [val, setVal] = React.useState(0);
    
  2431.         return (
    
  2432.           <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  2433.             {val}
    
  2434.           </p>
    
  2435.         );
    
  2436.       }
    
  2437.       $RefreshReg$(Hello, 'Hello');
    
  2438. 
    
  2439.       return function App({offscreen}) {
    
  2440.         React.useLayoutEffect(() => {
    
  2441.           Scheduler.log('App#layout');
    
  2442.         });
    
  2443.         return (
    
  2444.           <LegacyHiddenDiv mode={offscreen ? 'hidden' : 'visible'}>
    
  2445.             <Hello />
    
  2446.           </LegacyHiddenDiv>
    
  2447.         );
    
  2448.       };
    
  2449.     });
    
  2450. 
    
  2451.     const root = ReactDOMClient.createRoot(container);
    
  2452.     root.render(<AppV1 offscreen={true} />);
    
  2453.     await waitFor(['App#layout']);
    
  2454.     const el = container.firstChild;
    
  2455.     expect(el.hidden).toBe(true);
    
  2456.     expect(el.firstChild).toBe(null); // Offscreen content not flushed yet.
    
  2457. 
    
  2458.     // Perform a hot update.
    
  2459.     patch(() => {
    
  2460.       function Hello() {
    
  2461.         React.useLayoutEffect(() => {
    
  2462.           Scheduler.log('Hello#layout');
    
  2463.         });
    
  2464.         const [val, setVal] = React.useState(0);
    
  2465.         return (
    
  2466.           <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  2467.             {val}
    
  2468.           </p>
    
  2469.         );
    
  2470.       }
    
  2471.       $RefreshReg$(Hello, 'Hello');
    
  2472.     });
    
  2473. 
    
  2474.     // It's still offscreen so we don't see anything.
    
  2475.     expect(container.firstChild).toBe(el);
    
  2476.     expect(el.hidden).toBe(true);
    
  2477.     expect(el.firstChild).toBe(null);
    
  2478. 
    
  2479.     // Process the offscreen updates.
    
  2480.     await waitFor(['Hello#layout']);
    
  2481.     expect(container.firstChild).toBe(el);
    
  2482.     expect(el.firstChild.textContent).toBe('0');
    
  2483.     expect(el.firstChild.style.color).toBe('red');
    
  2484. 
    
  2485.     await internalAct(() => {
    
  2486.       el.firstChild.dispatchEvent(
    
  2487.         new MouseEvent('click', {
    
  2488.           bubbles: true,
    
  2489.         }),
    
  2490.       );
    
  2491.     });
    
  2492. 
    
  2493.     assertLog(['Hello#layout']);
    
  2494.     expect(el.firstChild.textContent).toBe('1');
    
  2495.     expect(el.firstChild.style.color).toBe('red');
    
  2496. 
    
  2497.     // Hot reload while we're offscreen.
    
  2498.     patch(() => {
    
  2499.       function Hello() {
    
  2500.         React.useLayoutEffect(() => {
    
  2501.           Scheduler.log('Hello#layout');
    
  2502.         });
    
  2503.         const [val, setVal] = React.useState(0);
    
  2504.         return (
    
  2505.           <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  2506.             {val}
    
  2507.           </p>
    
  2508.         );
    
  2509.       }
    
  2510.       $RefreshReg$(Hello, 'Hello');
    
  2511.     });
    
  2512. 
    
  2513.     // It's still offscreen so we don't see the updates.
    
  2514.     expect(container.firstChild).toBe(el);
    
  2515.     expect(el.firstChild.textContent).toBe('1');
    
  2516.     expect(el.firstChild.style.color).toBe('red');
    
  2517. 
    
  2518.     // Process the offscreen updates.
    
  2519.     await waitFor(['Hello#layout']);
    
  2520.     expect(container.firstChild).toBe(el);
    
  2521.     expect(el.firstChild.textContent).toBe('1');
    
  2522.     expect(el.firstChild.style.color).toBe('orange');
    
  2523.   });
    
  2524. 
    
  2525.   it('remounts failed error boundaries (componentDidCatch)', () => {
    
  2526.     if (__DEV__) {
    
  2527.       render(() => {
    
  2528.         function Hello() {
    
  2529.           return <h1>Hi</h1>;
    
  2530.         }
    
  2531.         $RefreshReg$(Hello, 'Hello');
    
  2532. 
    
  2533.         class Boundary extends React.Component {
    
  2534.           state = {error: null};
    
  2535.           componentDidCatch(error) {
    
  2536.             this.setState({error});
    
  2537.           }
    
  2538.           render() {
    
  2539.             if (this.state.error) {
    
  2540.               return <h1>Oops: {this.state.error.message}</h1>;
    
  2541.             }
    
  2542.             return this.props.children;
    
  2543.           }
    
  2544.         }
    
  2545. 
    
  2546.         function App() {
    
  2547.           return (
    
  2548.             <>
    
  2549.               <p>A</p>
    
  2550.               <Boundary>
    
  2551.                 <Hello />
    
  2552.               </Boundary>
    
  2553.               <p>B</p>
    
  2554.             </>
    
  2555.           );
    
  2556.         }
    
  2557. 
    
  2558.         return App;
    
  2559.       });
    
  2560. 
    
  2561.       expect(container.innerHTML).toBe('<p>A</p><h1>Hi</h1><p>B</p>');
    
  2562.       const firstP = container.firstChild;
    
  2563.       const secondP = firstP.nextSibling.nextSibling;
    
  2564. 
    
  2565.       // Perform a hot update that fails.
    
  2566.       patch(() => {
    
  2567.         function Hello() {
    
  2568.           throw new Error('No');
    
  2569.         }
    
  2570.         $RefreshReg$(Hello, 'Hello');
    
  2571.       });
    
  2572. 
    
  2573.       expect(container.innerHTML).toBe('<p>A</p><h1>Oops: No</h1><p>B</p>');
    
  2574.       expect(container.firstChild).toBe(firstP);
    
  2575.       expect(container.firstChild.nextSibling.nextSibling).toBe(secondP);
    
  2576. 
    
  2577.       // Perform a hot update that fixes the error.
    
  2578.       patch(() => {
    
  2579.         function Hello() {
    
  2580.           return <h1>Fixed!</h1>;
    
  2581.         }
    
  2582.         $RefreshReg$(Hello, 'Hello');
    
  2583.       });
    
  2584. 
    
  2585.       // This should remount the error boundary (but not anything above it).
    
  2586.       expect(container.innerHTML).toBe('<p>A</p><h1>Fixed!</h1><p>B</p>');
    
  2587.       expect(container.firstChild).toBe(firstP);
    
  2588.       expect(container.firstChild.nextSibling.nextSibling).toBe(secondP);
    
  2589. 
    
  2590.       // Verify next hot reload doesn't remount anything.
    
  2591.       const helloNode = container.firstChild.nextSibling;
    
  2592.       patch(() => {
    
  2593.         function Hello() {
    
  2594.           return <h1>Nice.</h1>;
    
  2595.         }
    
  2596.         $RefreshReg$(Hello, 'Hello');
    
  2597.       });
    
  2598.       expect(container.firstChild.nextSibling).toBe(helloNode);
    
  2599.       expect(helloNode.textContent).toBe('Nice.');
    
  2600.     }
    
  2601.   });
    
  2602. 
    
  2603.   it('remounts failed error boundaries (getDerivedStateFromError)', () => {
    
  2604.     if (__DEV__) {
    
  2605.       render(() => {
    
  2606.         function Hello() {
    
  2607.           return <h1>Hi</h1>;
    
  2608.         }
    
  2609.         $RefreshReg$(Hello, 'Hello');
    
  2610. 
    
  2611.         class Boundary extends React.Component {
    
  2612.           state = {error: null};
    
  2613.           static getDerivedStateFromError(error) {
    
  2614.             return {error};
    
  2615.           }
    
  2616.           render() {
    
  2617.             if (this.state.error) {
    
  2618.               return <h1>Oops: {this.state.error.message}</h1>;
    
  2619.             }
    
  2620.             return this.props.children;
    
  2621.           }
    
  2622.         }
    
  2623. 
    
  2624.         function App() {
    
  2625.           return (
    
  2626.             <>
    
  2627.               <p>A</p>
    
  2628.               <Boundary>
    
  2629.                 <Hello />
    
  2630.               </Boundary>
    
  2631.               <p>B</p>
    
  2632.             </>
    
  2633.           );
    
  2634.         }
    
  2635. 
    
  2636.         return App;
    
  2637.       });
    
  2638. 
    
  2639.       expect(container.innerHTML).toBe('<p>A</p><h1>Hi</h1><p>B</p>');
    
  2640.       const firstP = container.firstChild;
    
  2641.       const secondP = firstP.nextSibling.nextSibling;
    
  2642. 
    
  2643.       // Perform a hot update that fails.
    
  2644.       patch(() => {
    
  2645.         function Hello() {
    
  2646.           throw new Error('No');
    
  2647.         }
    
  2648.         $RefreshReg$(Hello, 'Hello');
    
  2649.       });
    
  2650. 
    
  2651.       expect(container.innerHTML).toBe('<p>A</p><h1>Oops: No</h1><p>B</p>');
    
  2652.       expect(container.firstChild).toBe(firstP);
    
  2653.       expect(container.firstChild.nextSibling.nextSibling).toBe(secondP);
    
  2654. 
    
  2655.       // Perform a hot update that fixes the error.
    
  2656.       patch(() => {
    
  2657.         function Hello() {
    
  2658.           return <h1>Fixed!</h1>;
    
  2659.         }
    
  2660.         $RefreshReg$(Hello, 'Hello');
    
  2661.       });
    
  2662. 
    
  2663.       // This should remount the error boundary (but not anything above it).
    
  2664.       expect(container.innerHTML).toBe('<p>A</p><h1>Fixed!</h1><p>B</p>');
    
  2665.       expect(container.firstChild).toBe(firstP);
    
  2666.       expect(container.firstChild.nextSibling.nextSibling).toBe(secondP);
    
  2667. 
    
  2668.       // Verify next hot reload doesn't remount anything.
    
  2669.       const helloNode = container.firstChild.nextSibling;
    
  2670.       patch(() => {
    
  2671.         function Hello() {
    
  2672.           return <h1>Nice.</h1>;
    
  2673.         }
    
  2674.         $RefreshReg$(Hello, 'Hello');
    
  2675.       });
    
  2676.       expect(container.firstChild.nextSibling).toBe(helloNode);
    
  2677.       expect(helloNode.textContent).toBe('Nice.');
    
  2678.     }
    
  2679.   });
    
  2680. 
    
  2681.   it('remounts error boundaries that failed asynchronously after hot update', () => {
    
  2682.     if (__DEV__) {
    
  2683.       render(() => {
    
  2684.         function Hello() {
    
  2685.           const [x] = React.useState('');
    
  2686.           React.useEffect(() => {}, []);
    
  2687.           x.slice(); // Doesn't throw initially.
    
  2688.           return <h1>Hi</h1>;
    
  2689.         }
    
  2690.         $RefreshReg$(Hello, 'Hello');
    
  2691. 
    
  2692.         class Boundary extends React.Component {
    
  2693.           state = {error: null};
    
  2694.           static getDerivedStateFromError(error) {
    
  2695.             return {error};
    
  2696.           }
    
  2697.           render() {
    
  2698.             if (this.state.error) {
    
  2699.               return <h1>Oops: {this.state.error.message}</h1>;
    
  2700.             }
    
  2701.             return this.props.children;
    
  2702.           }
    
  2703.         }
    
  2704. 
    
  2705.         function App() {
    
  2706.           return (
    
  2707.             <>
    
  2708.               <p>A</p>
    
  2709.               <Boundary>
    
  2710.                 <Hello />
    
  2711.               </Boundary>
    
  2712.               <p>B</p>
    
  2713.             </>
    
  2714.           );
    
  2715.         }
    
  2716. 
    
  2717.         return App;
    
  2718.       });
    
  2719. 
    
  2720.       expect(container.innerHTML).toBe('<p>A</p><h1>Hi</h1><p>B</p>');
    
  2721.       const firstP = container.firstChild;
    
  2722.       const secondP = firstP.nextSibling.nextSibling;
    
  2723. 
    
  2724.       // Perform a hot update that fails.
    
  2725.       act(() => {
    
  2726.         patch(() => {
    
  2727.           function Hello() {
    
  2728.             const [x, setX] = React.useState('');
    
  2729.             React.useEffect(() => {
    
  2730.               setTimeout(() => {
    
  2731.                 setX(42); // This will crash next render.
    
  2732.               }, 1);
    
  2733.             }, []);
    
  2734.             x.slice();
    
  2735.             return <h1>Hi</h1>;
    
  2736.           }
    
  2737.           $RefreshReg$(Hello, 'Hello');
    
  2738.         });
    
  2739.       });
    
  2740. 
    
  2741.       expect(container.innerHTML).toBe('<p>A</p><h1>Hi</h1><p>B</p>');
    
  2742.       // Run timeout inside effect:
    
  2743.       act(() => {
    
  2744.         jest.runAllTimers();
    
  2745.       });
    
  2746.       expect(container.innerHTML).toBe(
    
  2747.         '<p>A</p><h1>Oops: x.slice is not a function</h1><p>B</p>',
    
  2748.       );
    
  2749.       expect(container.firstChild).toBe(firstP);
    
  2750.       expect(container.firstChild.nextSibling.nextSibling).toBe(secondP);
    
  2751. 
    
  2752.       // Perform a hot update that fixes the error.
    
  2753.       act(() => {
    
  2754.         patch(() => {
    
  2755.           function Hello() {
    
  2756.             const [x] = React.useState('');
    
  2757.             React.useEffect(() => {}, []); // Removes the bad effect code.
    
  2758.             x.slice(); // Doesn't throw initially.
    
  2759.             return <h1>Fixed!</h1>;
    
  2760.           }
    
  2761.           $RefreshReg$(Hello, 'Hello');
    
  2762.         });
    
  2763.       });
    
  2764. 
    
  2765.       // This should remount the error boundary (but not anything above it).
    
  2766.       expect(container.innerHTML).toBe('<p>A</p><h1>Fixed!</h1><p>B</p>');
    
  2767.       expect(container.firstChild).toBe(firstP);
    
  2768.       expect(container.firstChild.nextSibling.nextSibling).toBe(secondP);
    
  2769. 
    
  2770.       // Verify next hot reload doesn't remount anything.
    
  2771.       const helloNode = container.firstChild.nextSibling;
    
  2772.       act(() => {
    
  2773.         patch(() => {
    
  2774.           function Hello() {
    
  2775.             const [x] = React.useState('');
    
  2776.             React.useEffect(() => {}, []);
    
  2777.             x.slice();
    
  2778.             return <h1>Nice.</h1>;
    
  2779.           }
    
  2780.           $RefreshReg$(Hello, 'Hello');
    
  2781.         });
    
  2782.       });
    
  2783. 
    
  2784.       expect(container.firstChild.nextSibling).toBe(helloNode);
    
  2785.       expect(helloNode.textContent).toBe('Nice.');
    
  2786.     }
    
  2787.   });
    
  2788. 
    
  2789.   it('remounts a failed root on mount', () => {
    
  2790.     if (__DEV__) {
    
  2791.       expect(() => {
    
  2792.         render(() => {
    
  2793.           function Hello() {
    
  2794.             throw new Error('No');
    
  2795.           }
    
  2796.           $RefreshReg$(Hello, 'Hello');
    
  2797. 
    
  2798.           return Hello;
    
  2799.         });
    
  2800.       }).toThrow('No');
    
  2801.       expect(container.innerHTML).toBe('');
    
  2802. 
    
  2803.       // A bad retry
    
  2804.       expect(() => {
    
  2805.         patch(() => {
    
  2806.           function Hello() {
    
  2807.             throw new Error('Not yet');
    
  2808.           }
    
  2809.           $RefreshReg$(Hello, 'Hello');
    
  2810.         });
    
  2811.       }).toThrow('Not yet');
    
  2812.       expect(container.innerHTML).toBe('');
    
  2813. 
    
  2814.       // Perform a hot update that fixes the error.
    
  2815.       patch(() => {
    
  2816.         function Hello() {
    
  2817.           return <h1>Fixed!</h1>;
    
  2818.         }
    
  2819.         $RefreshReg$(Hello, 'Hello');
    
  2820.       });
    
  2821.       // This should mount the root.
    
  2822.       expect(container.innerHTML).toBe('<h1>Fixed!</h1>');
    
  2823. 
    
  2824.       // Ensure we can keep failing and recovering later.
    
  2825.       expect(() => {
    
  2826.         patch(() => {
    
  2827.           function Hello() {
    
  2828.             throw new Error('No 2');
    
  2829.           }
    
  2830.           $RefreshReg$(Hello, 'Hello');
    
  2831.         });
    
  2832.       }).toThrow('No 2');
    
  2833.       expect(container.innerHTML).toBe('');
    
  2834.       expect(() => {
    
  2835.         patch(() => {
    
  2836.           function Hello() {
    
  2837.             throw new Error('Not yet 2');
    
  2838.           }
    
  2839.           $RefreshReg$(Hello, 'Hello');
    
  2840.         });
    
  2841.       }).toThrow('Not yet 2');
    
  2842.       expect(container.innerHTML).toBe('');
    
  2843.       patch(() => {
    
  2844.         function Hello() {
    
  2845.           return <h1>Fixed 2!</h1>;
    
  2846.         }
    
  2847.         $RefreshReg$(Hello, 'Hello');
    
  2848.       });
    
  2849.       expect(container.innerHTML).toBe('<h1>Fixed 2!</h1>');
    
  2850. 
    
  2851.       // Updates after intentional unmount are ignored.
    
  2852.       ReactDOM.unmountComponentAtNode(container);
    
  2853.       patch(() => {
    
  2854.         function Hello() {
    
  2855.           throw new Error('Ignored');
    
  2856.         }
    
  2857.         $RefreshReg$(Hello, 'Hello');
    
  2858.       });
    
  2859.       expect(container.innerHTML).toBe('');
    
  2860.       patch(() => {
    
  2861.         function Hello() {
    
  2862.           return <h1>Ignored</h1>;
    
  2863.         }
    
  2864.         $RefreshReg$(Hello, 'Hello');
    
  2865.       });
    
  2866.       expect(container.innerHTML).toBe('');
    
  2867.     }
    
  2868.   });
    
  2869. 
    
  2870.   it('does not retry an intentionally unmounted failed root', () => {
    
  2871.     if (__DEV__) {
    
  2872.       expect(() => {
    
  2873.         render(() => {
    
  2874.           function Hello() {
    
  2875.             throw new Error('No');
    
  2876.           }
    
  2877.           $RefreshReg$(Hello, 'Hello');
    
  2878. 
    
  2879.           return Hello;
    
  2880.         });
    
  2881.       }).toThrow('No');
    
  2882.       expect(container.innerHTML).toBe('');
    
  2883. 
    
  2884.       // Intentional unmount.
    
  2885.       ReactDOM.unmountComponentAtNode(container);
    
  2886. 
    
  2887.       // Perform a hot update that fixes the error.
    
  2888.       patch(() => {
    
  2889.         function Hello() {
    
  2890.           return <h1>Fixed!</h1>;
    
  2891.         }
    
  2892.         $RefreshReg$(Hello, 'Hello');
    
  2893.       });
    
  2894.       // This should stay unmounted.
    
  2895.       expect(container.innerHTML).toBe('');
    
  2896.     }
    
  2897.   });
    
  2898. 
    
  2899.   it('remounts a failed root on update', () => {
    
  2900.     if (__DEV__) {
    
  2901.       render(() => {
    
  2902.         function Hello() {
    
  2903.           return <h1>Hi</h1>;
    
  2904.         }
    
  2905.         $RefreshReg$(Hello, 'Hello');
    
  2906. 
    
  2907.         return Hello;
    
  2908.       });
    
  2909.       expect(container.innerHTML).toBe('<h1>Hi</h1>');
    
  2910. 
    
  2911.       // Perform a hot update that fails.
    
  2912.       // This removes the root.
    
  2913.       expect(() => {
    
  2914.         patch(() => {
    
  2915.           function Hello() {
    
  2916.             throw new Error('No');
    
  2917.           }
    
  2918.           $RefreshReg$(Hello, 'Hello');
    
  2919.         });
    
  2920.       }).toThrow('No');
    
  2921.       expect(container.innerHTML).toBe('');
    
  2922. 
    
  2923.       // A bad retry
    
  2924.       expect(() => {
    
  2925.         patch(() => {
    
  2926.           function Hello() {
    
  2927.             throw new Error('Not yet');
    
  2928.           }
    
  2929.           $RefreshReg$(Hello, 'Hello');
    
  2930.         });
    
  2931.       }).toThrow('Not yet');
    
  2932.       expect(container.innerHTML).toBe('');
    
  2933. 
    
  2934.       // Perform a hot update that fixes the error.
    
  2935.       patch(() => {
    
  2936.         function Hello() {
    
  2937.           return <h1>Fixed!</h1>;
    
  2938.         }
    
  2939.         $RefreshReg$(Hello, 'Hello');
    
  2940.       });
    
  2941.       // This should remount the root.
    
  2942.       expect(container.innerHTML).toBe('<h1>Fixed!</h1>');
    
  2943. 
    
  2944.       // Verify next hot reload doesn't remount anything.
    
  2945.       const helloNode = container.firstChild;
    
  2946.       patch(() => {
    
  2947.         function Hello() {
    
  2948.           return <h1>Nice.</h1>;
    
  2949.         }
    
  2950.         $RefreshReg$(Hello, 'Hello');
    
  2951.       });
    
  2952.       expect(container.firstChild).toBe(helloNode);
    
  2953.       expect(helloNode.textContent).toBe('Nice.');
    
  2954. 
    
  2955.       // Break again.
    
  2956.       expect(() => {
    
  2957.         patch(() => {
    
  2958.           function Hello() {
    
  2959.             throw new Error('Oops');
    
  2960.           }
    
  2961.           $RefreshReg$(Hello, 'Hello');
    
  2962.         });
    
  2963.       }).toThrow('Oops');
    
  2964.       expect(container.innerHTML).toBe('');
    
  2965. 
    
  2966.       // Perform a hot update that fixes the error.
    
  2967.       patch(() => {
    
  2968.         function Hello() {
    
  2969.           return <h1>At last.</h1>;
    
  2970.         }
    
  2971.         $RefreshReg$(Hello, 'Hello');
    
  2972.       });
    
  2973.       // This should remount the root.
    
  2974.       expect(container.innerHTML).toBe('<h1>At last.</h1>');
    
  2975. 
    
  2976.       // Check we don't attempt to reverse an intentional unmount.
    
  2977.       ReactDOM.unmountComponentAtNode(container);
    
  2978.       expect(container.innerHTML).toBe('');
    
  2979.       patch(() => {
    
  2980.         function Hello() {
    
  2981.           return <h1>Never mind me!</h1>;
    
  2982.         }
    
  2983.         $RefreshReg$(Hello, 'Hello');
    
  2984.       });
    
  2985.       expect(container.innerHTML).toBe('');
    
  2986. 
    
  2987.       // Mount a new container.
    
  2988.       render(() => {
    
  2989.         function Hello() {
    
  2990.           return <h1>Hi</h1>;
    
  2991.         }
    
  2992.         $RefreshReg$(Hello, 'Hello');
    
  2993. 
    
  2994.         return Hello;
    
  2995.       });
    
  2996.       expect(container.innerHTML).toBe('<h1>Hi</h1>');
    
  2997. 
    
  2998.       // Break again.
    
  2999.       expect(() => {
    
  3000.         patch(() => {
    
  3001.           function Hello() {
    
  3002.             throw new Error('Oops');
    
  3003.           }
    
  3004.           $RefreshReg$(Hello, 'Hello');
    
  3005.         });
    
  3006.       }).toThrow('Oops');
    
  3007.       expect(container.innerHTML).toBe('');
    
  3008. 
    
  3009.       // Check we don't attempt to reverse an intentional unmount, even after an error.
    
  3010.       ReactDOM.unmountComponentAtNode(container);
    
  3011.       expect(container.innerHTML).toBe('');
    
  3012.       patch(() => {
    
  3013.         function Hello() {
    
  3014.           return <h1>Never mind me!</h1>;
    
  3015.         }
    
  3016.         $RefreshReg$(Hello, 'Hello');
    
  3017.       });
    
  3018.       expect(container.innerHTML).toBe('');
    
  3019.     }
    
  3020.   });
    
  3021. 
    
  3022.   it('regression test: does not get into an infinite loop', () => {
    
  3023.     if (__DEV__) {
    
  3024.       const containerA = document.createElement('div');
    
  3025.       const containerB = document.createElement('div');
    
  3026. 
    
  3027.       // Initially, nothing interesting.
    
  3028.       const RootAV1 = () => {
    
  3029.         return 'A1';
    
  3030.       };
    
  3031.       $RefreshReg$(RootAV1, 'RootA');
    
  3032.       const RootBV1 = () => {
    
  3033.         return 'B1';
    
  3034.       };
    
  3035.       $RefreshReg$(RootBV1, 'RootB');
    
  3036. 
    
  3037.       act(() => {
    
  3038.         ReactDOM.render(<RootAV1 />, containerA);
    
  3039.         ReactDOM.render(<RootBV1 />, containerB);
    
  3040.       });
    
  3041.       expect(containerA.innerHTML).toBe('A1');
    
  3042.       expect(containerB.innerHTML).toBe('B1');
    
  3043. 
    
  3044.       // Then make the first root fail.
    
  3045.       const RootAV2 = () => {
    
  3046.         throw new Error('A2!');
    
  3047.       };
    
  3048.       $RefreshReg$(RootAV2, 'RootA');
    
  3049.       expect(() => ReactFreshRuntime.performReactRefresh()).toThrow('A2!');
    
  3050.       expect(containerA.innerHTML).toBe('');
    
  3051.       expect(containerB.innerHTML).toBe('B1');
    
  3052. 
    
  3053.       // Then patch the first root, but make it fail in the commit phase.
    
  3054.       // This used to trigger an infinite loop due to a list of failed roots
    
  3055.       // being mutated while it was being iterated on.
    
  3056.       const RootAV3 = () => {
    
  3057.         React.useLayoutEffect(() => {
    
  3058.           throw new Error('A3!');
    
  3059.         }, []);
    
  3060.         return 'A3';
    
  3061.       };
    
  3062.       $RefreshReg$(RootAV3, 'RootA');
    
  3063.       expect(() => ReactFreshRuntime.performReactRefresh()).toThrow('A3!');
    
  3064.       expect(containerA.innerHTML).toBe('');
    
  3065.       expect(containerB.innerHTML).toBe('B1');
    
  3066. 
    
  3067.       const RootAV4 = () => {
    
  3068.         return 'A4';
    
  3069.       };
    
  3070.       $RefreshReg$(RootAV4, 'RootA');
    
  3071.       ReactFreshRuntime.performReactRefresh();
    
  3072.       expect(containerA.innerHTML).toBe('A4');
    
  3073.       expect(containerB.innerHTML).toBe('B1');
    
  3074.     }
    
  3075.   });
    
  3076. 
    
  3077.   it('remounts classes on every edit', () => {
    
  3078.     if (__DEV__) {
    
  3079.       const HelloV1 = render(() => {
    
  3080.         class Hello extends React.Component {
    
  3081.           state = {count: 0};
    
  3082.           handleClick = () => {
    
  3083.             this.setState(prev => ({
    
  3084.               count: prev.count + 1,
    
  3085.             }));
    
  3086.           };
    
  3087.           render() {
    
  3088.             return (
    
  3089.               <p style={{color: 'blue'}} onClick={this.handleClick}>
    
  3090.                 {this.state.count}
    
  3091.               </p>
    
  3092.             );
    
  3093.           }
    
  3094.         }
    
  3095.         // For classes, we wouldn't do this call via Babel plugin.
    
  3096.         // Instead, we'd do it at module boundaries.
    
  3097.         // Normally classes would get a different type and remount anyway,
    
  3098.         // but at module boundaries we may want to prevent propagation.
    
  3099.         // However we still want to force a remount and use latest version.
    
  3100.         $RefreshReg$(Hello, 'Hello');
    
  3101.         return Hello;
    
  3102.       });
    
  3103. 
    
  3104.       // Bump the state before patching.
    
  3105.       const el = container.firstChild;
    
  3106.       expect(el.textContent).toBe('0');
    
  3107.       expect(el.style.color).toBe('blue');
    
  3108.       act(() => {
    
  3109.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  3110.       });
    
  3111.       expect(el.textContent).toBe('1');
    
  3112. 
    
  3113.       // Perform a hot update.
    
  3114.       const HelloV2 = patch(() => {
    
  3115.         class Hello extends React.Component {
    
  3116.           state = {count: 0};
    
  3117.           handleClick = () => {
    
  3118.             this.setState(prev => ({
    
  3119.               count: prev.count + 1,
    
  3120.             }));
    
  3121.           };
    
  3122.           render() {
    
  3123.             return (
    
  3124.               <p style={{color: 'red'}} onClick={this.handleClick}>
    
  3125.                 {this.state.count}
    
  3126.               </p>
    
  3127.             );
    
  3128.           }
    
  3129.         }
    
  3130.         $RefreshReg$(Hello, 'Hello');
    
  3131.         return Hello;
    
  3132.       });
    
  3133. 
    
  3134.       // It should have remounted the class.
    
  3135.       expect(container.firstChild).not.toBe(el);
    
  3136.       const newEl = container.firstChild;
    
  3137.       expect(newEl.textContent).toBe('0');
    
  3138.       expect(newEl.style.color).toBe('red');
    
  3139.       act(() => {
    
  3140.         newEl.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  3141.       });
    
  3142.       expect(newEl.textContent).toBe('1');
    
  3143. 
    
  3144.       // Now top-level renders of both types resolve to latest.
    
  3145.       render(() => HelloV1);
    
  3146.       render(() => HelloV2);
    
  3147.       expect(container.firstChild).toBe(newEl);
    
  3148.       expect(newEl.style.color).toBe('red');
    
  3149.       expect(newEl.textContent).toBe('1');
    
  3150. 
    
  3151.       const HelloV3 = patch(() => {
    
  3152.         class Hello extends React.Component {
    
  3153.           state = {count: 0};
    
  3154.           handleClick = () => {
    
  3155.             this.setState(prev => ({
    
  3156.               count: prev.count + 1,
    
  3157.             }));
    
  3158.           };
    
  3159.           render() {
    
  3160.             return (
    
  3161.               <p style={{color: 'orange'}} onClick={this.handleClick}>
    
  3162.                 {this.state.count}
    
  3163.               </p>
    
  3164.             );
    
  3165.           }
    
  3166.         }
    
  3167.         $RefreshReg$(Hello, 'Hello');
    
  3168.         return Hello;
    
  3169.       });
    
  3170. 
    
  3171.       // It should have remounted the class again.
    
  3172.       expect(container.firstChild).not.toBe(el);
    
  3173.       const finalEl = container.firstChild;
    
  3174.       expect(finalEl.textContent).toBe('0');
    
  3175.       expect(finalEl.style.color).toBe('orange');
    
  3176.       act(() => {
    
  3177.         finalEl.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  3178.       });
    
  3179.       expect(finalEl.textContent).toBe('1');
    
  3180. 
    
  3181.       render(() => HelloV3);
    
  3182.       render(() => HelloV2);
    
  3183.       render(() => HelloV1);
    
  3184.       expect(container.firstChild).toBe(finalEl);
    
  3185.       expect(finalEl.style.color).toBe('orange');
    
  3186.       expect(finalEl.textContent).toBe('1');
    
  3187.     }
    
  3188.   });
    
  3189. 
    
  3190.   it('updates refs when remounting', () => {
    
  3191.     if (__DEV__) {
    
  3192.       const testRef = React.createRef();
    
  3193.       render(
    
  3194.         () => {
    
  3195.           class Hello extends React.Component {
    
  3196.             getColor() {
    
  3197.               return 'green';
    
  3198.             }
    
  3199.             render() {
    
  3200.               return <p />;
    
  3201.             }
    
  3202.           }
    
  3203.           $RefreshReg$(Hello, 'Hello');
    
  3204.           return Hello;
    
  3205.         },
    
  3206.         {ref: testRef},
    
  3207.       );
    
  3208.       expect(testRef.current.getColor()).toBe('green');
    
  3209. 
    
  3210.       patch(() => {
    
  3211.         class Hello extends React.Component {
    
  3212.           getColor() {
    
  3213.             return 'orange';
    
  3214.           }
    
  3215.           render() {
    
  3216.             return <p />;
    
  3217.           }
    
  3218.         }
    
  3219.         $RefreshReg$(Hello, 'Hello');
    
  3220.       });
    
  3221.       expect(testRef.current.getColor()).toBe('orange');
    
  3222. 
    
  3223.       patch(() => {
    
  3224.         const Hello = React.forwardRef((props, ref) => {
    
  3225.           React.useImperativeHandle(ref, () => ({
    
  3226.             getColor() {
    
  3227.               return 'pink';
    
  3228.             },
    
  3229.           }));
    
  3230.           return <p />;
    
  3231.         });
    
  3232.         $RefreshReg$(Hello, 'Hello');
    
  3233.       });
    
  3234.       expect(testRef.current.getColor()).toBe('pink');
    
  3235. 
    
  3236.       patch(() => {
    
  3237.         const Hello = React.forwardRef((props, ref) => {
    
  3238.           React.useImperativeHandle(ref, () => ({
    
  3239.             getColor() {
    
  3240.               return 'yellow';
    
  3241.             },
    
  3242.           }));
    
  3243.           return <p />;
    
  3244.         });
    
  3245.         $RefreshReg$(Hello, 'Hello');
    
  3246.       });
    
  3247.       expect(testRef.current.getColor()).toBe('yellow');
    
  3248. 
    
  3249.       patch(() => {
    
  3250.         const Hello = React.forwardRef((props, ref) => {
    
  3251.           React.useImperativeHandle(ref, () => ({
    
  3252.             getColor() {
    
  3253.               return 'yellow';
    
  3254.             },
    
  3255.           }));
    
  3256.           return <p />;
    
  3257.         });
    
  3258.         $RefreshReg$(Hello, 'Hello');
    
  3259.       });
    
  3260.       expect(testRef.current.getColor()).toBe('yellow');
    
  3261.     }
    
  3262.   });
    
  3263. 
    
  3264.   it('remounts on conversion from class to function and back', () => {
    
  3265.     if (__DEV__) {
    
  3266.       const HelloV1 = render(() => {
    
  3267.         function Hello() {
    
  3268.           const [val, setVal] = React.useState(0);
    
  3269.           return (
    
  3270.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  3271.               {val}
    
  3272.             </p>
    
  3273.           );
    
  3274.         }
    
  3275.         $RefreshReg$(Hello, 'Hello');
    
  3276.         return Hello;
    
  3277.       });
    
  3278. 
    
  3279.       // Bump the state before patching.
    
  3280.       const el = container.firstChild;
    
  3281.       expect(el.textContent).toBe('0');
    
  3282.       expect(el.style.color).toBe('blue');
    
  3283.       act(() => {
    
  3284.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  3285.       });
    
  3286.       expect(el.textContent).toBe('1');
    
  3287. 
    
  3288.       // Perform a hot update that turns it into a class.
    
  3289.       const HelloV2 = patch(() => {
    
  3290.         class Hello extends React.Component {
    
  3291.           state = {count: 0};
    
  3292.           handleClick = () => {
    
  3293.             this.setState(prev => ({
    
  3294.               count: prev.count + 1,
    
  3295.             }));
    
  3296.           };
    
  3297.           render() {
    
  3298.             return (
    
  3299.               <p style={{color: 'red'}} onClick={this.handleClick}>
    
  3300.                 {this.state.count}
    
  3301.               </p>
    
  3302.             );
    
  3303.           }
    
  3304.         }
    
  3305.         $RefreshReg$(Hello, 'Hello');
    
  3306.         return Hello;
    
  3307.       });
    
  3308. 
    
  3309.       // It should have remounted.
    
  3310.       expect(container.firstChild).not.toBe(el);
    
  3311.       const newEl = container.firstChild;
    
  3312.       expect(newEl.textContent).toBe('0');
    
  3313.       expect(newEl.style.color).toBe('red');
    
  3314.       act(() => {
    
  3315.         newEl.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  3316.       });
    
  3317.       expect(newEl.textContent).toBe('1');
    
  3318. 
    
  3319.       // Now top-level renders of both types resolve to latest.
    
  3320.       render(() => HelloV1);
    
  3321.       render(() => HelloV2);
    
  3322.       expect(container.firstChild).toBe(newEl);
    
  3323.       expect(newEl.style.color).toBe('red');
    
  3324.       expect(newEl.textContent).toBe('1');
    
  3325. 
    
  3326.       // Now convert it back to a function.
    
  3327.       const HelloV3 = patch(() => {
    
  3328.         function Hello() {
    
  3329.           const [val, setVal] = React.useState(0);
    
  3330.           return (
    
  3331.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  3332.               {val}
    
  3333.             </p>
    
  3334.           );
    
  3335.         }
    
  3336.         $RefreshReg$(Hello, 'Hello');
    
  3337.         return Hello;
    
  3338.       });
    
  3339. 
    
  3340.       // It should have remounted again.
    
  3341.       expect(container.firstChild).not.toBe(el);
    
  3342.       const finalEl = container.firstChild;
    
  3343.       expect(finalEl.textContent).toBe('0');
    
  3344.       expect(finalEl.style.color).toBe('orange');
    
  3345.       act(() => {
    
  3346.         finalEl.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  3347.       });
    
  3348.       expect(finalEl.textContent).toBe('1');
    
  3349. 
    
  3350.       render(() => HelloV3);
    
  3351.       render(() => HelloV2);
    
  3352.       render(() => HelloV1);
    
  3353.       expect(container.firstChild).toBe(finalEl);
    
  3354.       expect(finalEl.style.color).toBe('orange');
    
  3355.       expect(finalEl.textContent).toBe('1');
    
  3356. 
    
  3357.       // Now that it's a function, verify edits keep state.
    
  3358.       patch(() => {
    
  3359.         function Hello() {
    
  3360.           const [val, setVal] = React.useState(0);
    
  3361.           return (
    
  3362.             <p style={{color: 'purple'}} onClick={() => setVal(val + 1)}>
    
  3363.               {val}
    
  3364.             </p>
    
  3365.           );
    
  3366.         }
    
  3367.         $RefreshReg$(Hello, 'Hello');
    
  3368.         return Hello;
    
  3369.       });
    
  3370.       expect(container.firstChild).toBe(finalEl);
    
  3371.       expect(finalEl.style.color).toBe('purple');
    
  3372.       expect(finalEl.textContent).toBe('1');
    
  3373.     }
    
  3374.   });
    
  3375. 
    
  3376.   it('can find host instances for a family', () => {
    
  3377.     if (__DEV__) {
    
  3378.       render(() => {
    
  3379.         function Child({children}) {
    
  3380.           return <div className="Child">{children}</div>;
    
  3381.         }
    
  3382.         $RefreshReg$(Child, 'Child');
    
  3383. 
    
  3384.         function Parent({children}) {
    
  3385.           return (
    
  3386.             <div className="Parent">
    
  3387.               <div>
    
  3388.                 <Child />
    
  3389.               </div>
    
  3390.               <div>
    
  3391.                 <Child />
    
  3392.               </div>
    
  3393.             </div>
    
  3394.           );
    
  3395.         }
    
  3396.         $RefreshReg$(Parent, 'Parent');
    
  3397. 
    
  3398.         function App() {
    
  3399.           return (
    
  3400.             <div className="App">
    
  3401.               <Parent />
    
  3402.               <Cls>
    
  3403.                 <Parent />
    
  3404.               </Cls>
    
  3405.               <Indirection>
    
  3406.                 <Empty />
    
  3407.               </Indirection>
    
  3408.             </div>
    
  3409.           );
    
  3410.         }
    
  3411.         $RefreshReg$(App, 'App');
    
  3412. 
    
  3413.         class Cls extends React.Component {
    
  3414.           render() {
    
  3415.             return this.props.children;
    
  3416.           }
    
  3417.         }
    
  3418. 
    
  3419.         function Indirection({children}) {
    
  3420.           return children;
    
  3421.         }
    
  3422. 
    
  3423.         function Empty() {
    
  3424.           return null;
    
  3425.         }
    
  3426.         $RefreshReg$(Empty, 'Empty');
    
  3427. 
    
  3428.         function Frag() {
    
  3429.           return (
    
  3430.             <>
    
  3431.               <div className="Frag">
    
  3432.                 <div />
    
  3433.               </div>
    
  3434.               <div className="Frag">
    
  3435.                 <div />
    
  3436.               </div>
    
  3437.             </>
    
  3438.           );
    
  3439.         }
    
  3440.         $RefreshReg$(Frag, 'Frag');
    
  3441. 
    
  3442.         return App;
    
  3443.       });
    
  3444. 
    
  3445.       const parentFamily = ReactFreshRuntime.getFamilyByID('Parent');
    
  3446.       const childFamily = ReactFreshRuntime.getFamilyByID('Child');
    
  3447.       const emptyFamily = ReactFreshRuntime.getFamilyByID('Empty');
    
  3448. 
    
  3449.       testFindHostInstancesForFamilies(
    
  3450.         [parentFamily],
    
  3451.         container.querySelectorAll('.Parent'),
    
  3452.       );
    
  3453. 
    
  3454.       testFindHostInstancesForFamilies(
    
  3455.         [childFamily],
    
  3456.         container.querySelectorAll('.Child'),
    
  3457.       );
    
  3458. 
    
  3459.       // When searching for both Parent and Child,
    
  3460.       // we'll stop visual highlighting at the Parent.
    
  3461.       testFindHostInstancesForFamilies(
    
  3462.         [parentFamily, childFamily],
    
  3463.         container.querySelectorAll('.Parent'),
    
  3464.       );
    
  3465. 
    
  3466.       // When we can't find host nodes, use the closest parent.
    
  3467.       testFindHostInstancesForFamilies(
    
  3468.         [emptyFamily],
    
  3469.         container.querySelectorAll('.App'),
    
  3470.       );
    
  3471.     }
    
  3472.   });
    
  3473. 
    
  3474.   function testFindHostInstancesForFamilies(families, expectedNodes) {
    
  3475.     const foundInstances = Array.from(
    
  3476.       ReactFreshRuntime.findAffectedHostInstances(families),
    
  3477.     );
    
  3478.     expect(foundInstances.length).toEqual(expectedNodes.length);
    
  3479.     foundInstances.forEach((node, i) => {
    
  3480.       expect(node).toBe(expectedNodes[i]);
    
  3481.     });
    
  3482.   }
    
  3483. 
    
  3484.   it('can update multiple roots independently', () => {
    
  3485.     if (__DEV__) {
    
  3486.       // Declare the first version.
    
  3487.       const HelloV1 = () => {
    
  3488.         const [val, setVal] = React.useState(0);
    
  3489.         return (
    
  3490.           <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  3491.             {val}
    
  3492.           </p>
    
  3493.         );
    
  3494.       };
    
  3495.       $RefreshReg$(HelloV1, 'Hello');
    
  3496. 
    
  3497.       // Perform a hot update before any roots exist.
    
  3498.       const HelloV2 = () => {
    
  3499.         const [val, setVal] = React.useState(0);
    
  3500.         return (
    
  3501.           <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  3502.             {val}
    
  3503.           </p>
    
  3504.         );
    
  3505.       };
    
  3506.       $RefreshReg$(HelloV2, 'Hello');
    
  3507.       ReactFreshRuntime.performReactRefresh();
    
  3508. 
    
  3509.       // Mount three roots.
    
  3510.       const cont1 = document.createElement('div');
    
  3511.       const cont2 = document.createElement('div');
    
  3512.       const cont3 = document.createElement('div');
    
  3513.       document.body.appendChild(cont1);
    
  3514.       document.body.appendChild(cont2);
    
  3515.       document.body.appendChild(cont3);
    
  3516.       try {
    
  3517.         ReactDOM.render(<HelloV1 id={1} />, cont1);
    
  3518.         ReactDOM.render(<HelloV2 id={2} />, cont2);
    
  3519.         ReactDOM.render(<HelloV1 id={3} />, cont3);
    
  3520. 
    
  3521.         // Expect we see the V2 color.
    
  3522.         expect(cont1.firstChild.style.color).toBe('red');
    
  3523.         expect(cont2.firstChild.style.color).toBe('red');
    
  3524.         expect(cont3.firstChild.style.color).toBe('red');
    
  3525.         expect(cont1.firstChild.textContent).toBe('0');
    
  3526.         expect(cont2.firstChild.textContent).toBe('0');
    
  3527.         expect(cont3.firstChild.textContent).toBe('0');
    
  3528. 
    
  3529.         // Bump the state for each of them.
    
  3530.         act(() => {
    
  3531.           cont1.firstChild.dispatchEvent(
    
  3532.             new MouseEvent('click', {bubbles: true}),
    
  3533.           );
    
  3534.           cont2.firstChild.dispatchEvent(
    
  3535.             new MouseEvent('click', {bubbles: true}),
    
  3536.           );
    
  3537.           cont3.firstChild.dispatchEvent(
    
  3538.             new MouseEvent('click', {bubbles: true}),
    
  3539.           );
    
  3540.         });
    
  3541.         expect(cont1.firstChild.style.color).toBe('red');
    
  3542.         expect(cont2.firstChild.style.color).toBe('red');
    
  3543.         expect(cont3.firstChild.style.color).toBe('red');
    
  3544.         expect(cont1.firstChild.textContent).toBe('1');
    
  3545.         expect(cont2.firstChild.textContent).toBe('1');
    
  3546.         expect(cont3.firstChild.textContent).toBe('1');
    
  3547. 
    
  3548.         // Perform another hot update.
    
  3549.         const HelloV3 = () => {
    
  3550.           const [val, setVal] = React.useState(0);
    
  3551.           return (
    
  3552.             <p style={{color: 'green'}} onClick={() => setVal(val + 1)}>
    
  3553.               {val}
    
  3554.             </p>
    
  3555.           );
    
  3556.         };
    
  3557.         $RefreshReg$(HelloV3, 'Hello');
    
  3558.         ReactFreshRuntime.performReactRefresh();
    
  3559. 
    
  3560.         // It should affect all roots.
    
  3561.         expect(cont1.firstChild.style.color).toBe('green');
    
  3562.         expect(cont2.firstChild.style.color).toBe('green');
    
  3563.         expect(cont3.firstChild.style.color).toBe('green');
    
  3564.         expect(cont1.firstChild.textContent).toBe('1');
    
  3565.         expect(cont2.firstChild.textContent).toBe('1');
    
  3566.         expect(cont3.firstChild.textContent).toBe('1');
    
  3567. 
    
  3568.         // Unmount the second root.
    
  3569.         ReactDOM.unmountComponentAtNode(cont2);
    
  3570.         // Make the first root throw and unmount on hot update.
    
  3571.         const HelloV4 = ({id}) => {
    
  3572.           if (id === 1) {
    
  3573.             throw new Error('Oops.');
    
  3574.           }
    
  3575.           const [val, setVal] = React.useState(0);
    
  3576.           return (
    
  3577.             <p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
    
  3578.               {val}
    
  3579.             </p>
    
  3580.           );
    
  3581.         };
    
  3582.         $RefreshReg$(HelloV4, 'Hello');
    
  3583.         expect(() => {
    
  3584.           ReactFreshRuntime.performReactRefresh();
    
  3585.         }).toThrow('Oops.');
    
  3586. 
    
  3587.         // Still, we expect the last root to be updated.
    
  3588.         expect(cont1.innerHTML).toBe('');
    
  3589.         expect(cont2.innerHTML).toBe('');
    
  3590.         expect(cont3.firstChild.style.color).toBe('orange');
    
  3591.         expect(cont3.firstChild.textContent).toBe('1');
    
  3592.       } finally {
    
  3593.         document.body.removeChild(cont1);
    
  3594.         document.body.removeChild(cont2);
    
  3595.         document.body.removeChild(cont3);
    
  3596.       }
    
  3597.     }
    
  3598.   });
    
  3599. 
    
  3600.   // Module runtimes can use this to decide whether
    
  3601.   // to propagate an update up to the modules that imported it,
    
  3602.   // or to stop at the current module because it's a component.
    
  3603.   // This can't and doesn't need to be 100% precise.
    
  3604.   it('can detect likely component types', () => {
    
  3605.     function useTheme() {}
    
  3606.     function Widget() {}
    
  3607. 
    
  3608.     if (__DEV__) {
    
  3609.       expect(ReactFreshRuntime.isLikelyComponentType(false)).toBe(false);
    
  3610.       expect(ReactFreshRuntime.isLikelyComponentType(null)).toBe(false);
    
  3611.       expect(ReactFreshRuntime.isLikelyComponentType('foo')).toBe(false);
    
  3612. 
    
  3613.       // We need to hit a balance here.
    
  3614.       // If we lean towards assuming everything is a component,
    
  3615.       // editing modules that export plain functions won't trigger
    
  3616.       // a proper reload because we will bottle up the update.
    
  3617.       // So we're being somewhat conservative.
    
  3618.       expect(ReactFreshRuntime.isLikelyComponentType(() => {})).toBe(false);
    
  3619.       expect(ReactFreshRuntime.isLikelyComponentType(function () {})).toBe(
    
  3620.         false,
    
  3621.       );
    
  3622.       expect(
    
  3623.         ReactFreshRuntime.isLikelyComponentType(function lightenColor() {}),
    
  3624.       ).toBe(false);
    
  3625.       const loadUser = () => {};
    
  3626.       expect(ReactFreshRuntime.isLikelyComponentType(loadUser)).toBe(false);
    
  3627.       const useStore = () => {};
    
  3628.       expect(ReactFreshRuntime.isLikelyComponentType(useStore)).toBe(false);
    
  3629.       expect(ReactFreshRuntime.isLikelyComponentType(useTheme)).toBe(false);
    
  3630.       const rogueProxy = new Proxy(
    
  3631.         {},
    
  3632.         {
    
  3633.           get(target, property) {
    
  3634.             throw new Error();
    
  3635.           },
    
  3636.         },
    
  3637.       );
    
  3638.       expect(ReactFreshRuntime.isLikelyComponentType(rogueProxy)).toBe(false);
    
  3639. 
    
  3640.       // These seem like function components.
    
  3641.       const Button = () => {};
    
  3642.       expect(ReactFreshRuntime.isLikelyComponentType(Button)).toBe(true);
    
  3643.       expect(ReactFreshRuntime.isLikelyComponentType(Widget)).toBe(true);
    
  3644.       const ProxyButton = new Proxy(Button, {
    
  3645.         get(target, property) {
    
  3646.           return target[property];
    
  3647.         },
    
  3648.       });
    
  3649.       expect(ReactFreshRuntime.isLikelyComponentType(ProxyButton)).toBe(true);
    
  3650.       const anon = (() => () => {})();
    
  3651.       anon.displayName = 'Foo';
    
  3652.       expect(ReactFreshRuntime.isLikelyComponentType(anon)).toBe(true);
    
  3653. 
    
  3654.       // These seem like class components.
    
  3655.       class Btn extends React.Component {}
    
  3656.       class PureBtn extends React.PureComponent {}
    
  3657.       const ProxyBtn = new Proxy(Btn, {
    
  3658.         get(target, property) {
    
  3659.           return target[property];
    
  3660.         },
    
  3661.       });
    
  3662.       expect(ReactFreshRuntime.isLikelyComponentType(Btn)).toBe(true);
    
  3663.       expect(ReactFreshRuntime.isLikelyComponentType(PureBtn)).toBe(true);
    
  3664.       expect(ReactFreshRuntime.isLikelyComponentType(ProxyBtn)).toBe(true);
    
  3665.       expect(
    
  3666.         ReactFreshRuntime.isLikelyComponentType(
    
  3667.           createReactClass({render() {}}),
    
  3668.         ),
    
  3669.       ).toBe(true);
    
  3670. 
    
  3671.       // These don't.
    
  3672.       class Figure {
    
  3673.         move() {}
    
  3674.       }
    
  3675.       expect(ReactFreshRuntime.isLikelyComponentType(Figure)).toBe(false);
    
  3676.       class Point extends Figure {}
    
  3677.       expect(ReactFreshRuntime.isLikelyComponentType(Point)).toBe(false);
    
  3678. 
    
  3679.       // Run the same tests without Babel.
    
  3680.       // This tests real arrow functions and classes, as implemented in Node.
    
  3681. 
    
  3682.       // eslint-disable-next-line no-new-func
    
  3683.       new Function(
    
  3684.         'global',
    
  3685.         'React',
    
  3686.         'ReactFreshRuntime',
    
  3687.         'expect',
    
  3688.         'createReactClass',
    
  3689.         `
    
  3690.         expect(ReactFreshRuntime.isLikelyComponentType(() => {})).toBe(false);
    
  3691.         expect(ReactFreshRuntime.isLikelyComponentType(function() {})).toBe(false);
    
  3692.         expect(
    
  3693.           ReactFreshRuntime.isLikelyComponentType(function lightenColor() {}),
    
  3694.         ).toBe(false);
    
  3695.         const loadUser = () => {};
    
  3696.         expect(ReactFreshRuntime.isLikelyComponentType(loadUser)).toBe(false);
    
  3697.         const useStore = () => {};
    
  3698.         expect(ReactFreshRuntime.isLikelyComponentType(useStore)).toBe(false);
    
  3699.         function useTheme() {}
    
  3700.         expect(ReactFreshRuntime.isLikelyComponentType(useTheme)).toBe(false);
    
  3701. 
    
  3702.         // These seem like function components.
    
  3703.         let Button = () => {};
    
  3704.         expect(ReactFreshRuntime.isLikelyComponentType(Button)).toBe(true);
    
  3705.         function Widget() {}
    
  3706.         expect(ReactFreshRuntime.isLikelyComponentType(Widget)).toBe(true);
    
  3707.         let anon = (() => () => {})();
    
  3708.         anon.displayName = 'Foo';
    
  3709.         expect(ReactFreshRuntime.isLikelyComponentType(anon)).toBe(true);
    
  3710. 
    
  3711.         // These seem like class components.
    
  3712.         class Btn extends React.Component {}
    
  3713.         class PureBtn extends React.PureComponent {}
    
  3714.         expect(ReactFreshRuntime.isLikelyComponentType(Btn)).toBe(true);
    
  3715.         expect(ReactFreshRuntime.isLikelyComponentType(PureBtn)).toBe(true);
    
  3716.         expect(
    
  3717.           ReactFreshRuntime.isLikelyComponentType(createReactClass({render() {}})),
    
  3718.         ).toBe(true);
    
  3719. 
    
  3720.         // These don't.
    
  3721.         class Figure {
    
  3722.           move() {}
    
  3723.         }
    
  3724.         expect(ReactFreshRuntime.isLikelyComponentType(Figure)).toBe(false);
    
  3725.         class Point extends Figure {}
    
  3726.         expect(ReactFreshRuntime.isLikelyComponentType(Point)).toBe(false);
    
  3727.       `,
    
  3728.       )(global, React, ReactFreshRuntime, expect, createReactClass);
    
  3729.     }
    
  3730.   });
    
  3731. 
    
  3732.   it('reports updated and remounted families to the caller', () => {
    
  3733.     if (__DEV__) {
    
  3734.       const HelloV1 = () => {
    
  3735.         const [val, setVal] = React.useState(0);
    
  3736.         return (
    
  3737.           <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  3738.             {val}
    
  3739.           </p>
    
  3740.         );
    
  3741.       };
    
  3742.       $RefreshReg$(HelloV1, 'Hello');
    
  3743. 
    
  3744.       const HelloV2 = () => {
    
  3745.         const [val, setVal] = React.useState(0);
    
  3746.         return (
    
  3747.           <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  3748.             {val}
    
  3749.           </p>
    
  3750.         );
    
  3751.       };
    
  3752.       $RefreshReg$(HelloV2, 'Hello');
    
  3753. 
    
  3754.       const update = ReactFreshRuntime.performReactRefresh();
    
  3755.       expect(update.updatedFamilies.size).toBe(1);
    
  3756.       expect(update.staleFamilies.size).toBe(0);
    
  3757.       const family = update.updatedFamilies.values().next().value;
    
  3758.       expect(family.current.name).toBe('HelloV2');
    
  3759.       // For example, we can use this to print a log of what was updated.
    
  3760.     }
    
  3761.   });
    
  3762. 
    
  3763.   function initFauxDevToolsHook() {
    
  3764.     const onCommitFiberRoot = jest.fn();
    
  3765.     const onCommitFiberUnmount = jest.fn();
    
  3766. 
    
  3767.     let idCounter = 0;
    
  3768.     const renderers = new Map();
    
  3769. 
    
  3770.     // This is a minimal shim for the global hook installed by DevTools.
    
  3771.     // The real one is in packages/react-devtools-shared/src/hook.js.
    
  3772.     global.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
    
  3773.       renderers,
    
  3774.       supportsFiber: true,
    
  3775.       inject(renderer) {
    
  3776.         const id = ++idCounter;
    
  3777.         renderers.set(id, renderer);
    
  3778.         return id;
    
  3779.       },
    
  3780.       onCommitFiberRoot,
    
  3781.       onCommitFiberUnmount,
    
  3782.     };
    
  3783.   }
    
  3784. 
    
  3785.   // This simulates the scenario in https://github.com/facebook/react/issues/17626
    
  3786.   it('can inject the runtime after the renderer executes', async () => {
    
  3787.     if (__DEV__) {
    
  3788.       initFauxDevToolsHook();
    
  3789. 
    
  3790.       // Load these first, as if they're coming from a CDN.
    
  3791.       jest.resetModules();
    
  3792.       React = require('react');
    
  3793.       ReactDOM = require('react-dom');
    
  3794.       Scheduler = require('scheduler');
    
  3795.       act = require('react-dom/test-utils').act;
    
  3796.       internalAct = require('internal-test-utils').act;
    
  3797. 
    
  3798.       // Important! Inject into the global hook *after* ReactDOM runs:
    
  3799.       ReactFreshRuntime = require('react-refresh/runtime');
    
  3800.       ReactFreshRuntime.injectIntoGlobalHook(global);
    
  3801. 
    
  3802.       // We're verifying that we're able to track roots mounted after this point.
    
  3803.       // The rest of this test is taken from the simplest first test case.
    
  3804. 
    
  3805.       render(() => {
    
  3806.         function Hello() {
    
  3807.           const [val, setVal] = React.useState(0);
    
  3808.           return (
    
  3809.             <p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
    
  3810.               {val}
    
  3811.             </p>
    
  3812.           );
    
  3813.         }
    
  3814.         $RefreshReg$(Hello, 'Hello');
    
  3815.         return Hello;
    
  3816.       });
    
  3817. 
    
  3818.       // Bump the state before patching.
    
  3819.       const el = container.firstChild;
    
  3820.       expect(el.textContent).toBe('0');
    
  3821.       expect(el.style.color).toBe('blue');
    
  3822.       act(() => {
    
  3823.         el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
    
  3824.       });
    
  3825.       expect(el.textContent).toBe('1');
    
  3826. 
    
  3827.       // Perform a hot update.
    
  3828.       patch(() => {
    
  3829.         function Hello() {
    
  3830.           const [val, setVal] = React.useState(0);
    
  3831.           return (
    
  3832.             <p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
    
  3833.               {val}
    
  3834.             </p>
    
  3835.           );
    
  3836.         }
    
  3837.         $RefreshReg$(Hello, 'Hello');
    
  3838.         return Hello;
    
  3839.       });
    
  3840. 
    
  3841.       // Assert the state was preserved but color changed.
    
  3842.       expect(container.firstChild).toBe(el);
    
  3843.       expect(el.textContent).toBe('1');
    
  3844.       expect(el.style.color).toBe('red');
    
  3845.     }
    
  3846.   });
    
  3847. 
    
  3848.   // This simulates the scenario in https://github.com/facebook/react/issues/20100
    
  3849.   it('does not block DevTools when an unsupported renderer is injected', () => {
    
  3850.     if (__DEV__) {
    
  3851.       initFauxDevToolsHook();
    
  3852. 
    
  3853.       const onCommitFiberRoot =
    
  3854.         global.__REACT_DEVTOOLS_GLOBAL_HOOK__.onCommitFiberRoot;
    
  3855. 
    
  3856.       // Redirect all React/ReactDOM requires to v16.8.0
    
  3857.       // This version predates Fast Refresh support.
    
  3858.       jest.mock('scheduler', () => jest.requireActual('scheduler-0-13'));
    
  3859.       jest.mock('scheduler/tracing', () =>
    
  3860.         jest.requireActual('scheduler-0-13/tracing'),
    
  3861.       );
    
  3862.       jest.mock('react', () => jest.requireActual('react-16-8'));
    
  3863.       jest.mock('react-dom', () => jest.requireActual('react-dom-16-8'));
    
  3864. 
    
  3865.       // Load React and company.
    
  3866.       jest.resetModules();
    
  3867.       React = require('react');
    
  3868.       ReactDOM = require('react-dom');
    
  3869.       Scheduler = require('scheduler');
    
  3870. 
    
  3871.       // Important! Inject into the global hook *after* ReactDOM runs:
    
  3872.       ReactFreshRuntime = require('react-refresh/runtime');
    
  3873.       ReactFreshRuntime.injectIntoGlobalHook(global);
    
  3874. 
    
  3875.       render(() => {
    
  3876.         function Hello() {
    
  3877.           return <div>Hi!</div>;
    
  3878.         }
    
  3879.         $RefreshReg$(Hello, 'Hello');
    
  3880.         return Hello;
    
  3881.       });
    
  3882. 
    
  3883.       expect(onCommitFiberRoot).toHaveBeenCalled();
    
  3884.     }
    
  3885.   });
    
  3886. });