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 ReactFreshRuntime;
    
  17. let act;
    
  18. 
    
  19. const babel = require('@babel/core');
    
  20. const freshPlugin = require('react-refresh/babel');
    
  21. const ts = require('typescript');
    
  22. 
    
  23. describe('ReactFreshIntegration', () => {
    
  24.   let container;
    
  25.   let exportsObj;
    
  26. 
    
  27.   beforeEach(() => {
    
  28.     if (__DEV__) {
    
  29.       jest.resetModules();
    
  30.       React = require('react');
    
  31.       ReactFreshRuntime = require('react-refresh/runtime');
    
  32.       ReactFreshRuntime.injectIntoGlobalHook(global);
    
  33.       ReactDOM = require('react-dom');
    
  34.       act = require('react-dom/test-utils').act;
    
  35.       container = document.createElement('div');
    
  36.       document.body.appendChild(container);
    
  37.       exportsObj = undefined;
    
  38.     }
    
  39.   });
    
  40. 
    
  41.   afterEach(() => {
    
  42.     if (__DEV__) {
    
  43.       ReactDOM.unmountComponentAtNode(container);
    
  44.       // Ensure we don't leak memory by holding onto dead roots.
    
  45.       expect(ReactFreshRuntime._getMountedRootCount()).toBe(0);
    
  46.       document.body.removeChild(container);
    
  47.     }
    
  48.   });
    
  49. 
    
  50.   function executeCommon(source, compileDestructuring) {
    
  51.     const compiled = babel.transform(source, {
    
  52.       babelrc: false,
    
  53.       presets: ['@babel/react'],
    
  54.       plugins: [
    
  55.         [freshPlugin, {skipEnvCheck: true}],
    
  56.         '@babel/plugin-transform-modules-commonjs',
    
  57.         compileDestructuring && '@babel/plugin-transform-destructuring',
    
  58.       ].filter(Boolean),
    
  59.     }).code;
    
  60.     return executeCompiled(compiled);
    
  61.   }
    
  62. 
    
  63.   function executeCompiled(compiled) {
    
  64.     exportsObj = {};
    
  65.     // eslint-disable-next-line no-new-func
    
  66.     new Function(
    
  67.       'global',
    
  68.       'React',
    
  69.       'exports',
    
  70.       '$RefreshReg$',
    
  71.       '$RefreshSig$',
    
  72.       compiled,
    
  73.     )(global, React, exportsObj, $RefreshReg$, $RefreshSig$);
    
  74.     // Module systems will register exports as a fallback.
    
  75.     // This is useful for cases when e.g. a class is exported,
    
  76.     // and we don't want to propagate the update beyond this module.
    
  77.     $RefreshReg$(exportsObj.default, 'exports.default');
    
  78.     return exportsObj.default;
    
  79.   }
    
  80. 
    
  81.   function $RefreshReg$(type, id) {
    
  82.     ReactFreshRuntime.register(type, id);
    
  83.   }
    
  84. 
    
  85.   function $RefreshSig$() {
    
  86.     return ReactFreshRuntime.createSignatureFunctionForTransform();
    
  87.   }
    
  88. 
    
  89.   describe('with compiled destructuring', () => {
    
  90.     runTests(executeCommon, testCommon);
    
  91.   });
    
  92. 
    
  93.   describe('without compiled destructuring', () => {
    
  94.     runTests(executeCommon, testCommon);
    
  95.   });
    
  96. 
    
  97.   describe('with typescript syntax', () => {
    
  98.     runTests(function (source) {
    
  99.       const typescriptSource = babel.transform(source, {
    
  100.         babelrc: false,
    
  101.         configFile: false,
    
  102.         presets: ['@babel/react'],
    
  103.         plugins: [
    
  104.           [freshPlugin, {skipEnvCheck: true}],
    
  105.           ['@babel/plugin-syntax-typescript', {isTSX: true}],
    
  106.         ],
    
  107.       }).code;
    
  108.       const compiled = ts.transpileModule(typescriptSource, {
    
  109.         module: ts.ModuleKind.CommonJS,
    
  110.       }).outputText;
    
  111.       return executeCompiled(compiled);
    
  112.     }, testTypescript);
    
  113.   });
    
  114. 
    
  115.   function runTests(execute, test) {
    
  116.     function render(source) {
    
  117.       const Component = execute(source);
    
  118.       act(() => {
    
  119.         ReactDOM.render(<Component />, container);
    
  120.       });
    
  121.       // Module initialization shouldn't be counted as a hot update.
    
  122.       expect(ReactFreshRuntime.performReactRefresh()).toBe(null);
    
  123.     }
    
  124. 
    
  125.     function patch(source) {
    
  126.       const prevExports = exportsObj;
    
  127.       execute(source);
    
  128.       const nextExports = exportsObj;
    
  129. 
    
  130.       // Check if exported families have changed.
    
  131.       // (In a real module system we'd do this for *all* exports.)
    
  132.       // For example, this can happen if you convert a class to a function.
    
  133.       // Or if you wrap something in a HOC.
    
  134.       const didExportsChange =
    
  135.         ReactFreshRuntime.getFamilyByType(prevExports.default) !==
    
  136.         ReactFreshRuntime.getFamilyByType(nextExports.default);
    
  137.       if (didExportsChange) {
    
  138.         // In a real module system, we would propagate such updates upwards,
    
  139.         // and re-execute modules that imported this one. (Just like if we edited them.)
    
  140.         // This makes adding/removing/renaming exports re-render references to them.
    
  141.         // Here, we'll just force a re-render using the newer type to emulate this.
    
  142.         const NextComponent = nextExports.default;
    
  143.         act(() => {
    
  144.           ReactDOM.render(<NextComponent />, container);
    
  145.         });
    
  146.       }
    
  147.       act(() => {
    
  148.         const result = ReactFreshRuntime.performReactRefresh();
    
  149.         if (!didExportsChange) {
    
  150.           // Normally we expect that some components got updated in our tests.
    
  151.           expect(result).not.toBe(null);
    
  152.         } else {
    
  153.           // However, we have tests where we convert functions to classes,
    
  154.           // and in those cases it's expected nothing would get updated.
    
  155.           // (Instead, the export change branch above would take care of it.)
    
  156.         }
    
  157.       });
    
  158.       expect(ReactFreshRuntime._getMountedRootCount()).toBe(1);
    
  159.     }
    
  160. 
    
  161.     test(render, patch);
    
  162.   }
    
  163. 
    
  164.   function testCommon(render, patch) {
    
  165.     it('reloads function declarations', () => {
    
  166.       if (__DEV__) {
    
  167.         render(`
    
  168.           function Parent() {
    
  169.             return <Child prop="A" />;
    
  170.           };
    
  171. 
    
  172.           function Child({prop}) {
    
  173.             return <h1>{prop}1</h1>;
    
  174.           };
    
  175. 
    
  176.           export default Parent;
    
  177.         `);
    
  178.         const el = container.firstChild;
    
  179.         expect(el.textContent).toBe('A1');
    
  180.         patch(`
    
  181.           function Parent() {
    
  182.             return <Child prop="B" />;
    
  183.           };
    
  184. 
    
  185.           function Child({prop}) {
    
  186.             return <h1>{prop}2</h1>;
    
  187.           };
    
  188. 
    
  189.           export default Parent;
    
  190.         `);
    
  191.         expect(container.firstChild).toBe(el);
    
  192.         expect(el.textContent).toBe('B2');
    
  193.       }
    
  194.     });
    
  195. 
    
  196.     it('reloads arrow functions', () => {
    
  197.       if (__DEV__) {
    
  198.         render(`
    
  199.           const Parent = () => {
    
  200.             return <Child prop="A" />;
    
  201.           };
    
  202. 
    
  203.           const Child = ({prop}) => {
    
  204.             return <h1>{prop}1</h1>;
    
  205.           };
    
  206. 
    
  207.           export default Parent;
    
  208.         `);
    
  209.         const el = container.firstChild;
    
  210.         expect(el.textContent).toBe('A1');
    
  211.         patch(`
    
  212.           const Parent = () => {
    
  213.             return <Child prop="B" />;
    
  214.           };
    
  215. 
    
  216.           const Child = ({prop}) => {
    
  217.             return <h1>{prop}2</h1>;
    
  218.           };
    
  219. 
    
  220.           export default Parent;
    
  221.         `);
    
  222.         expect(container.firstChild).toBe(el);
    
  223.         expect(el.textContent).toBe('B2');
    
  224.       }
    
  225.     });
    
  226. 
    
  227.     it('reloads a combination of memo and forwardRef', () => {
    
  228.       if (__DEV__) {
    
  229.         render(`
    
  230.           const {memo} = React;
    
  231. 
    
  232.           const Parent = memo(React.forwardRef(function (props, ref) {
    
  233.             return <Child prop="A" ref={ref} />;
    
  234.           }));
    
  235. 
    
  236.           const Child = React.memo(({prop}) => {
    
  237.             return <h1>{prop}1</h1>;
    
  238.           });
    
  239. 
    
  240.           export default React.memo(Parent);
    
  241.         `);
    
  242.         const el = container.firstChild;
    
  243.         expect(el.textContent).toBe('A1');
    
  244.         patch(`
    
  245.           const {memo} = React;
    
  246. 
    
  247.           const Parent = memo(React.forwardRef(function (props, ref) {
    
  248.             return <Child prop="B" ref={ref} />;
    
  249.           }));
    
  250. 
    
  251.           const Child = React.memo(({prop}) => {
    
  252.             return <h1>{prop}2</h1>;
    
  253.           });
    
  254. 
    
  255.           export default React.memo(Parent);
    
  256.         `);
    
  257.         expect(container.firstChild).toBe(el);
    
  258.         expect(el.textContent).toBe('B2');
    
  259.       }
    
  260.     });
    
  261. 
    
  262.     it('reloads default export with named memo', () => {
    
  263.       if (__DEV__) {
    
  264.         render(`
    
  265.           const {memo} = React;
    
  266. 
    
  267.           const Child = React.memo(({prop}) => {
    
  268.             return <h1>{prop}1</h1>;
    
  269.           });
    
  270. 
    
  271.           export default memo(React.forwardRef(function Parent(props, ref) {
    
  272.             return <Child prop="A" ref={ref} />;
    
  273.           }));
    
  274.         `);
    
  275.         const el = container.firstChild;
    
  276.         expect(el.textContent).toBe('A1');
    
  277.         patch(`
    
  278.           const {memo} = React;
    
  279. 
    
  280.           const Child = React.memo(({prop}) => {
    
  281.             return <h1>{prop}2</h1>;
    
  282.           });
    
  283. 
    
  284.           export default memo(React.forwardRef(function Parent(props, ref) {
    
  285.             return <Child prop="B" ref={ref} />;
    
  286.           }));
    
  287.         `);
    
  288.         expect(container.firstChild).toBe(el);
    
  289.         expect(el.textContent).toBe('B2');
    
  290.       }
    
  291.     });
    
  292. 
    
  293.     it('reloads HOCs if they return functions', () => {
    
  294.       if (__DEV__) {
    
  295.         render(`
    
  296.           function hoc(letter) {
    
  297.             return function() {
    
  298.               return <h1>{letter}1</h1>;
    
  299.             }
    
  300.           }
    
  301. 
    
  302.           export default function Parent() {
    
  303.             return <Child />;
    
  304.           }
    
  305. 
    
  306.           const Child = hoc('A');
    
  307.         `);
    
  308.         const el = container.firstChild;
    
  309.         expect(el.textContent).toBe('A1');
    
  310.         patch(`
    
  311.           function hoc(letter) {
    
  312.             return function() {
    
  313.               return <h1>{letter}2</h1>;
    
  314.             }
    
  315.           }
    
  316. 
    
  317.           export default function Parent() {
    
  318.             return React.createElement(Child);
    
  319.           }
    
  320. 
    
  321.           const Child = hoc('B');
    
  322.         `);
    
  323.         expect(container.firstChild).toBe(el);
    
  324.         expect(el.textContent).toBe('B2');
    
  325.       }
    
  326.     });
    
  327. 
    
  328.     it('resets state when renaming a state variable', () => {
    
  329.       if (__DEV__) {
    
  330.         render(`
    
  331.           const {useState} = React;
    
  332.           const S = 1;
    
  333. 
    
  334.           export default function App() {
    
  335.             const [foo, setFoo] = useState(S);
    
  336.             return <h1>A{foo}</h1>;
    
  337.           }
    
  338.         `);
    
  339.         const el = container.firstChild;
    
  340.         expect(el.textContent).toBe('A1');
    
  341. 
    
  342.         patch(`
    
  343.           const {useState} = React;
    
  344.           const S = 2;
    
  345. 
    
  346.           export default function App() {
    
  347.             const [foo, setFoo] = useState(S);
    
  348.             return <h1>B{foo}</h1>;
    
  349.           }
    
  350.         `);
    
  351.         // Same state variable name, so state is preserved.
    
  352.         expect(container.firstChild).toBe(el);
    
  353.         expect(el.textContent).toBe('B1');
    
  354. 
    
  355.         patch(`
    
  356.           const {useState} = React;
    
  357.           const S = 3;
    
  358. 
    
  359.           export default function App() {
    
  360.             const [bar, setBar] = useState(S);
    
  361.             return <h1>C{bar}</h1>;
    
  362.           }
    
  363.         `);
    
  364.         // Different state variable name, so state is reset.
    
  365.         expect(container.firstChild).not.toBe(el);
    
  366.         const newEl = container.firstChild;
    
  367.         expect(newEl.textContent).toBe('C3');
    
  368.       }
    
  369.     });
    
  370. 
    
  371.     it('resets state when renaming a state variable in a HOC', () => {
    
  372.       if (__DEV__) {
    
  373.         render(`
    
  374.           const {useState} = React;
    
  375.           const S = 1;
    
  376. 
    
  377.           function hoc(Wrapped) {
    
  378.             return function Generated() {
    
  379.               const [foo, setFoo] = useState(S);
    
  380.               return <Wrapped value={foo} />;
    
  381.             };
    
  382.           }
    
  383. 
    
  384.           export default hoc(({ value }) => {
    
  385.             return <h1>A{value}</h1>;
    
  386.           });
    
  387.         `);
    
  388.         const el = container.firstChild;
    
  389.         expect(el.textContent).toBe('A1');
    
  390. 
    
  391.         patch(`
    
  392.           const {useState} = React;
    
  393.           const S = 2;
    
  394. 
    
  395.           function hoc(Wrapped) {
    
  396.             return function Generated() {
    
  397.               const [foo, setFoo] = useState(S);
    
  398.               return <Wrapped value={foo} />;
    
  399.             };
    
  400.           }
    
  401. 
    
  402.           export default hoc(({ value }) => {
    
  403.             return <h1>B{value}</h1>;
    
  404.           });
    
  405.         `);
    
  406.         // Same state variable name, so state is preserved.
    
  407.         expect(container.firstChild).toBe(el);
    
  408.         expect(el.textContent).toBe('B1');
    
  409. 
    
  410.         patch(`
    
  411.           const {useState} = React;
    
  412.           const S = 3;
    
  413. 
    
  414.           function hoc(Wrapped) {
    
  415.             return function Generated() {
    
  416.               const [bar, setBar] = useState(S);
    
  417.               return <Wrapped value={bar} />;
    
  418.             };
    
  419.           }
    
  420. 
    
  421.           export default hoc(({ value }) => {
    
  422.             return <h1>C{value}</h1>;
    
  423.           });
    
  424.         `);
    
  425.         // Different state variable name, so state is reset.
    
  426.         expect(container.firstChild).not.toBe(el);
    
  427.         const newEl = container.firstChild;
    
  428.         expect(newEl.textContent).toBe('C3');
    
  429.       }
    
  430.     });
    
  431. 
    
  432.     it('resets state when renaming a state variable in a HOC with indirection', () => {
    
  433.       if (__DEV__) {
    
  434.         render(`
    
  435.           const {useState} = React;
    
  436.           const S = 1;
    
  437. 
    
  438.           function hoc(Wrapped) {
    
  439.             return function Generated() {
    
  440.               const [foo, setFoo] = useState(S);
    
  441.               return <Wrapped value={foo} />;
    
  442.             };
    
  443.           }
    
  444. 
    
  445.           function Indirection({ value }) {
    
  446.             return <h1>A{value}</h1>;
    
  447.           }
    
  448. 
    
  449.           export default hoc(Indirection);
    
  450.         `);
    
  451.         const el = container.firstChild;
    
  452.         expect(el.textContent).toBe('A1');
    
  453. 
    
  454.         patch(`
    
  455.           const {useState} = React;
    
  456.           const S = 2;
    
  457. 
    
  458.           function hoc(Wrapped) {
    
  459.             return function Generated() {
    
  460.               const [foo, setFoo] = useState(S);
    
  461.               return <Wrapped value={foo} />;
    
  462.             };
    
  463.           }
    
  464. 
    
  465.           function Indirection({ value }) {
    
  466.             return <h1>B{value}</h1>;
    
  467.           }
    
  468. 
    
  469.           export default hoc(Indirection);
    
  470.         `);
    
  471.         // Same state variable name, so state is preserved.
    
  472.         expect(container.firstChild).toBe(el);
    
  473.         expect(el.textContent).toBe('B1');
    
  474. 
    
  475.         patch(`
    
  476.           const {useState} = React;
    
  477.           const S = 3;
    
  478. 
    
  479.           function hoc(Wrapped) {
    
  480.             return function Generated() {
    
  481.               const [bar, setBar] = useState(S);
    
  482.               return <Wrapped value={bar} />;
    
  483.             };
    
  484.           }
    
  485. 
    
  486.           function Indirection({ value }) {
    
  487.             return <h1>C{value}</h1>;
    
  488.           }
    
  489. 
    
  490.           export default hoc(Indirection);
    
  491.         `);
    
  492.         // Different state variable name, so state is reset.
    
  493.         expect(container.firstChild).not.toBe(el);
    
  494.         const newEl = container.firstChild;
    
  495.         expect(newEl.textContent).toBe('C3');
    
  496.       }
    
  497.     });
    
  498. 
    
  499.     it('resets state when renaming a state variable inside a HOC with direct call', () => {
    
  500.       if (__DEV__) {
    
  501.         render(`
    
  502.           const {useState} = React;
    
  503.           const S = 1;
    
  504. 
    
  505.           function hocWithDirectCall(Wrapped) {
    
  506.             return function Generated() {
    
  507.               return Wrapped();
    
  508.             };
    
  509.           }
    
  510. 
    
  511.           export default hocWithDirectCall(() => {
    
  512.             const [foo, setFoo] = useState(S);
    
  513.             return <h1>A{foo}</h1>;
    
  514.           });
    
  515.         `);
    
  516.         const el = container.firstChild;
    
  517.         expect(el.textContent).toBe('A1');
    
  518. 
    
  519.         patch(`
    
  520.           const {useState} = React;
    
  521.           const S = 2;
    
  522. 
    
  523.           function hocWithDirectCall(Wrapped) {
    
  524.             return function Generated() {
    
  525.               return Wrapped();
    
  526.             };
    
  527.           }
    
  528. 
    
  529.           export default hocWithDirectCall(() => {
    
  530.             const [foo, setFoo] = useState(S);
    
  531.             return <h1>B{foo}</h1>;
    
  532.           });
    
  533.         `);
    
  534.         // Same state variable name, so state is preserved.
    
  535.         expect(container.firstChild).toBe(el);
    
  536.         expect(el.textContent).toBe('B1');
    
  537. 
    
  538.         patch(`
    
  539.           const {useState} = React;
    
  540.           const S = 3;
    
  541. 
    
  542.           function hocWithDirectCall(Wrapped) {
    
  543.             return function Generated() {
    
  544.               return Wrapped();
    
  545.             };
    
  546.           }
    
  547. 
    
  548.           export default hocWithDirectCall(() => {
    
  549.             const [bar, setBar] = useState(S);
    
  550.             return <h1>C{bar}</h1>;
    
  551.           });
    
  552.         `);
    
  553.         // Different state variable name, so state is reset.
    
  554.         expect(container.firstChild).not.toBe(el);
    
  555.         const newEl = container.firstChild;
    
  556.         expect(newEl.textContent).toBe('C3');
    
  557.       }
    
  558.     });
    
  559. 
    
  560.     it('does not crash when changing Hook order inside a HOC with direct call', () => {
    
  561.       if (__DEV__) {
    
  562.         render(`
    
  563.           const {useEffect} = React;
    
  564. 
    
  565.           function hocWithDirectCall(Wrapped) {
    
  566.             return function Generated() {
    
  567.               return Wrapped();
    
  568.             };
    
  569.           }
    
  570. 
    
  571.           export default hocWithDirectCall(() => {
    
  572.             useEffect(() => {}, []);
    
  573.             return <h1>A</h1>;
    
  574.           });
    
  575.         `);
    
  576.         const el = container.firstChild;
    
  577.         expect(el.textContent).toBe('A');
    
  578. 
    
  579.         patch(`
    
  580.           const {useEffect} = React;
    
  581. 
    
  582.           function hocWithDirectCall(Wrapped) {
    
  583.             return function Generated() {
    
  584.               return Wrapped();
    
  585.             };
    
  586.           }
    
  587. 
    
  588.           export default hocWithDirectCall(() => {
    
  589.             useEffect(() => {}, []);
    
  590.             useEffect(() => {}, []);
    
  591.             return <h1>B</h1>;
    
  592.           });
    
  593.         `);
    
  594.         // Hook order changed, so we remount.
    
  595.         expect(container.firstChild).not.toBe(el);
    
  596.         const newEl = container.firstChild;
    
  597.         expect(newEl.textContent).toBe('B');
    
  598.       }
    
  599.     });
    
  600. 
    
  601.     it('does not crash when changing Hook order inside a memo-ed HOC with direct call', () => {
    
  602.       if (__DEV__) {
    
  603.         render(`
    
  604.           const {useEffect, memo} = React;
    
  605. 
    
  606.           function hocWithDirectCall(Wrapped) {
    
  607.             return memo(function Generated() {
    
  608.               return Wrapped();
    
  609.             });
    
  610.           }
    
  611. 
    
  612.           export default hocWithDirectCall(() => {
    
  613.             useEffect(() => {}, []);
    
  614.             return <h1>A</h1>;
    
  615.           });
    
  616.         `);
    
  617.         const el = container.firstChild;
    
  618.         expect(el.textContent).toBe('A');
    
  619. 
    
  620.         patch(`
    
  621.           const {useEffect, memo} = React;
    
  622. 
    
  623.           function hocWithDirectCall(Wrapped) {
    
  624.             return memo(function Generated() {
    
  625.               return Wrapped();
    
  626.             });
    
  627.           }
    
  628. 
    
  629.           export default hocWithDirectCall(() => {
    
  630.             useEffect(() => {}, []);
    
  631.             useEffect(() => {}, []);
    
  632.             return <h1>B</h1>;
    
  633.           });
    
  634.         `);
    
  635.         // Hook order changed, so we remount.
    
  636.         expect(container.firstChild).not.toBe(el);
    
  637.         const newEl = container.firstChild;
    
  638.         expect(newEl.textContent).toBe('B');
    
  639.       }
    
  640.     });
    
  641. 
    
  642.     it('does not crash when changing Hook order inside a memo+forwardRef-ed HOC with direct call', () => {
    
  643.       if (__DEV__) {
    
  644.         render(`
    
  645.           const {useEffect, memo, forwardRef} = React;
    
  646. 
    
  647.           function hocWithDirectCall(Wrapped) {
    
  648.             return memo(forwardRef(function Generated() {
    
  649.               return Wrapped();
    
  650.             }));
    
  651.           }
    
  652. 
    
  653.           export default hocWithDirectCall(() => {
    
  654.             useEffect(() => {}, []);
    
  655.             return <h1>A</h1>;
    
  656.           });
    
  657.         `);
    
  658.         const el = container.firstChild;
    
  659.         expect(el.textContent).toBe('A');
    
  660. 
    
  661.         patch(`
    
  662.           const {useEffect, memo, forwardRef} = React;
    
  663. 
    
  664.           function hocWithDirectCall(Wrapped) {
    
  665.             return memo(forwardRef(function Generated() {
    
  666.               return Wrapped();
    
  667.             }));
    
  668.           }
    
  669. 
    
  670.           export default hocWithDirectCall(() => {
    
  671.             useEffect(() => {}, []);
    
  672.             useEffect(() => {}, []);
    
  673.             return <h1>B</h1>;
    
  674.           });
    
  675.         `);
    
  676.         // Hook order changed, so we remount.
    
  677.         expect(container.firstChild).not.toBe(el);
    
  678.         const newEl = container.firstChild;
    
  679.         expect(newEl.textContent).toBe('B');
    
  680.       }
    
  681.     });
    
  682. 
    
  683.     it('does not crash when changing Hook order inside a HOC returning an object', () => {
    
  684.       if (__DEV__) {
    
  685.         render(`
    
  686.           const {useEffect} = React;
    
  687. 
    
  688.           function hocWithDirectCall(Wrapped) {
    
  689.             return {Wrapped: Wrapped};
    
  690.           }
    
  691. 
    
  692.           export default hocWithDirectCall(() => {
    
  693.             useEffect(() => {}, []);
    
  694.             return <h1>A</h1>;
    
  695.           }).Wrapped;
    
  696.         `);
    
  697.         const el = container.firstChild;
    
  698.         expect(el.textContent).toBe('A');
    
  699. 
    
  700.         patch(`
    
  701.           const {useEffect} = React;
    
  702. 
    
  703.           function hocWithDirectCall(Wrapped) {
    
  704.             return {Wrapped: Wrapped};
    
  705.           }
    
  706. 
    
  707.           export default hocWithDirectCall(() => {
    
  708.             useEffect(() => {}, []);
    
  709.             useEffect(() => {}, []);
    
  710.             return <h1>B</h1>;
    
  711.           }).Wrapped;
    
  712.         `);
    
  713.         // Hook order changed, so we remount.
    
  714.         expect(container.firstChild).not.toBe(el);
    
  715.         const newEl = container.firstChild;
    
  716.         expect(newEl.textContent).toBe('B');
    
  717.       }
    
  718.     });
    
  719. 
    
  720.     it('resets effects while preserving state', () => {
    
  721.       if (__DEV__) {
    
  722.         render(`
    
  723.           const {useState} = React;
    
  724. 
    
  725.           export default function App() {
    
  726.             const [value, setValue] = useState(0);
    
  727.             return <h1>A{value}</h1>;
    
  728.           }
    
  729.         `);
    
  730.         let el = container.firstChild;
    
  731.         expect(el.textContent).toBe('A0');
    
  732. 
    
  733.         // Add an effect.
    
  734.         patch(`
    
  735.           const {useState} = React;
    
  736. 
    
  737.           export default function App() {
    
  738.             const [value, setValue] = useState(0);
    
  739.             React.useEffect(() => {
    
  740.               const id = setInterval(() => {
    
  741.                 setValue(v => v + 1);
    
  742.               }, 1000);
    
  743.               return () => clearInterval(id);
    
  744.             }, []);
    
  745.             return <h1>B{value}</h1>;
    
  746.           }
    
  747.         `);
    
  748.         // We added an effect, thereby changing Hook order.
    
  749.         // This causes a remount.
    
  750.         expect(container.firstChild).not.toBe(el);
    
  751.         el = container.firstChild;
    
  752.         expect(el.textContent).toBe('B0');
    
  753. 
    
  754.         act(() => {
    
  755.           jest.advanceTimersByTime(1000);
    
  756.         });
    
  757.         expect(el.textContent).toBe('B1');
    
  758. 
    
  759.         patch(`
    
  760.           const {useState} = React;
    
  761. 
    
  762.           export default function App() {
    
  763.             const [value, setValue] = useState(0);
    
  764.             React.useEffect(() => {
    
  765.               const id = setInterval(() => {
    
  766.                 setValue(v => v + 10);
    
  767.               }, 1000);
    
  768.               return () => clearInterval(id);
    
  769.             }, []);
    
  770.             return <h1>C{value}</h1>;
    
  771.           }
    
  772.         `);
    
  773.         // Same Hooks are called, so state is preserved.
    
  774.         expect(container.firstChild).toBe(el);
    
  775.         expect(el.textContent).toBe('C1');
    
  776. 
    
  777.         // Effects are always reset, so timer was reinstalled.
    
  778.         // The new version increments by 10 rather than 1.
    
  779.         act(() => {
    
  780.           jest.advanceTimersByTime(1000);
    
  781.         });
    
  782.         expect(el.textContent).toBe('C11');
    
  783. 
    
  784.         patch(`
    
  785.           const {useState} = React;
    
  786. 
    
  787.           export default function App() {
    
  788.             const [value, setValue] = useState(0);
    
  789.             return <h1>D{value}</h1>;
    
  790.           }
    
  791.         `);
    
  792.         // Removing the effect changes the signature
    
  793.         // and causes the component to remount.
    
  794.         expect(container.firstChild).not.toBe(el);
    
  795.         el = container.firstChild;
    
  796.         expect(el.textContent).toBe('D0');
    
  797.       }
    
  798.     });
    
  799. 
    
  800.     it('does not get confused when custom hooks are reordered', () => {
    
  801.       if (__DEV__) {
    
  802.         render(`
    
  803.           function useFancyState(initialState) {
    
  804.             return React.useState(initialState);
    
  805.           }
    
  806. 
    
  807.           const App = () => {
    
  808.             const [x, setX] = useFancyState('X');
    
  809.             const [y, setY] = useFancyState('Y');
    
  810.             return <h1>A{x}{y}</h1>;
    
  811.           };
    
  812. 
    
  813.           export default App;
    
  814.         `);
    
  815.         let el = container.firstChild;
    
  816.         expect(el.textContent).toBe('AXY');
    
  817. 
    
  818.         patch(`
    
  819.           function useFancyState(initialState) {
    
  820.             return React.useState(initialState);
    
  821.           }
    
  822. 
    
  823.           const App = () => {
    
  824.             const [x, setX] = useFancyState('X');
    
  825.             const [y, setY] = useFancyState('Y');
    
  826.             return <h1>B{x}{y}</h1>;
    
  827.           };
    
  828. 
    
  829.           export default App;
    
  830.         `);
    
  831.         // Same state variables, so no remount.
    
  832.         expect(container.firstChild).toBe(el);
    
  833.         expect(el.textContent).toBe('BXY');
    
  834. 
    
  835.         patch(`
    
  836.           function useFancyState(initialState) {
    
  837.             return React.useState(initialState);
    
  838.           }
    
  839. 
    
  840.           const App = () => {
    
  841.             const [y, setY] = useFancyState('Y');
    
  842.             const [x, setX] = useFancyState('X');
    
  843.             return <h1>B{x}{y}</h1>;
    
  844.           };
    
  845. 
    
  846.           export default App;
    
  847.         `);
    
  848.         // Hooks were re-ordered. This causes a remount.
    
  849.         // Therefore, Hook calls don't accidentally share state.
    
  850.         expect(container.firstChild).not.toBe(el);
    
  851.         el = container.firstChild;
    
  852.         expect(el.textContent).toBe('BXY');
    
  853.       }
    
  854.     });
    
  855. 
    
  856.     it('does not get confused when component is called early', () => {
    
  857.       if (__DEV__) {
    
  858.         render(`
    
  859.           // This isn't really a valid pattern but it's close enough
    
  860.           // to simulate what happens when you call ReactDOM.render
    
  861.           // in the same file. We want to ensure this doesn't confuse
    
  862.           // the runtime.
    
  863.           App();
    
  864. 
    
  865.           function App() {
    
  866.             const [x, setX] = useFancyState('X');
    
  867.             const [y, setY] = useFancyState('Y');
    
  868.             return <h1>A{x}{y}</h1>;
    
  869.           };
    
  870. 
    
  871.           function useFancyState(initialState) {
    
  872.             // No real Hook calls to avoid triggering invalid call invariant.
    
  873.             // We only want to verify that we can still call this function early.
    
  874.             return initialState;
    
  875.           }
    
  876. 
    
  877.           export default App;
    
  878.         `);
    
  879.         let el = container.firstChild;
    
  880.         expect(el.textContent).toBe('AXY');
    
  881. 
    
  882.         patch(`
    
  883.           // This isn't really a valid pattern but it's close enough
    
  884.           // to simulate what happens when you call ReactDOM.render
    
  885.           // in the same file. We want to ensure this doesn't confuse
    
  886.           // the runtime.
    
  887.           App();
    
  888. 
    
  889.           function App() {
    
  890.             const [x, setX] = useFancyState('X');
    
  891.             const [y, setY] = useFancyState('Y');
    
  892.             return <h1>B{x}{y}</h1>;
    
  893.           };
    
  894. 
    
  895.           function useFancyState(initialState) {
    
  896.             // No real Hook calls to avoid triggering invalid call invariant.
    
  897.             // We only want to verify that we can still call this function early.
    
  898.             return initialState;
    
  899.           }
    
  900. 
    
  901.           export default App;
    
  902.         `);
    
  903.         // Same state variables, so no remount.
    
  904.         expect(container.firstChild).toBe(el);
    
  905.         expect(el.textContent).toBe('BXY');
    
  906. 
    
  907.         patch(`
    
  908.           // This isn't really a valid pattern but it's close enough
    
  909.           // to simulate what happens when you call ReactDOM.render
    
  910.           // in the same file. We want to ensure this doesn't confuse
    
  911.           // the runtime.
    
  912.           App();
    
  913. 
    
  914.           function App() {
    
  915.             const [y, setY] = useFancyState('Y');
    
  916.             const [x, setX] = useFancyState('X');
    
  917.             return <h1>B{x}{y}</h1>;
    
  918.           };
    
  919. 
    
  920.           function useFancyState(initialState) {
    
  921.             // No real Hook calls to avoid triggering invalid call invariant.
    
  922.             // We only want to verify that we can still call this function early.
    
  923.             return initialState;
    
  924.           }
    
  925. 
    
  926.           export default App;
    
  927.         `);
    
  928.         // Hooks were re-ordered. This causes a remount.
    
  929.         // Therefore, Hook calls don't accidentally share state.
    
  930.         expect(container.firstChild).not.toBe(el);
    
  931.         el = container.firstChild;
    
  932.         expect(el.textContent).toBe('BXY');
    
  933.       }
    
  934.     });
    
  935. 
    
  936.     it('does not get confused by Hooks defined inline', () => {
    
  937.       // This is not a recommended pattern but at least it shouldn't break.
    
  938.       if (__DEV__) {
    
  939.         render(`
    
  940.           const App = () => {
    
  941.             const useFancyState = (initialState) => {
    
  942.               const result = React.useState(initialState);
    
  943.               return result;
    
  944.             };
    
  945.             const [x, setX] = useFancyState('X1');
    
  946.             const [y, setY] = useFancyState('Y1');
    
  947.             return <h1>A{x}{y}</h1>;
    
  948.           };
    
  949. 
    
  950.           export default App;
    
  951.         `);
    
  952.         let el = container.firstChild;
    
  953.         expect(el.textContent).toBe('AX1Y1');
    
  954. 
    
  955.         patch(`
    
  956.           const App = () => {
    
  957.             const useFancyState = (initialState) => {
    
  958.               const result = React.useState(initialState);
    
  959.               return result;
    
  960.             };
    
  961.             const [x, setX] = useFancyState('X2');
    
  962.             const [y, setY] = useFancyState('Y2');
    
  963.             return <h1>B{x}{y}</h1>;
    
  964.           };
    
  965. 
    
  966.           export default App;
    
  967.         `);
    
  968.         // Remount even though nothing changed because
    
  969.         // the custom Hook is inside -- and so we don't
    
  970.         // really know whether its signature has changed.
    
  971.         // We could potentially make it work, but for now
    
  972.         // let's assert we don't crash with confusing errors.
    
  973.         expect(container.firstChild).not.toBe(el);
    
  974.         el = container.firstChild;
    
  975.         expect(el.textContent).toBe('BX2Y2');
    
  976.       }
    
  977.     });
    
  978. 
    
  979.     it('remounts component if custom hook it uses changes order', () => {
    
  980.       if (__DEV__) {
    
  981.         render(`
    
  982.           const App = () => {
    
  983.             const [x, setX] = useFancyState('X');
    
  984.             const [y, setY] = useFancyState('Y');
    
  985.             return <h1>A{x}{y}</h1>;
    
  986.           };
    
  987. 
    
  988.           const useFancyState = (initialState) => {
    
  989.             const result = useIndirection(initialState);
    
  990.             return result;
    
  991.           };
    
  992. 
    
  993.           function useIndirection(initialState) {
    
  994.             return React.useState(initialState);
    
  995.           }
    
  996. 
    
  997.           export default App;
    
  998.         `);
    
  999.         let el = container.firstChild;
    
  1000.         expect(el.textContent).toBe('AXY');
    
  1001. 
    
  1002.         patch(`
    
  1003.           const App = () => {
    
  1004.             const [x, setX] = useFancyState('X');
    
  1005.             const [y, setY] = useFancyState('Y');
    
  1006.             return <h1>B{x}{y}</h1>;
    
  1007.           };
    
  1008. 
    
  1009.           const useFancyState = (initialState) => {
    
  1010.             const result = useIndirection();
    
  1011.             return result;
    
  1012.           };
    
  1013. 
    
  1014.           function useIndirection(initialState) {
    
  1015.             return React.useState(initialState);
    
  1016.           }
    
  1017. 
    
  1018.           export default App;
    
  1019.         `);
    
  1020.         // We didn't change anything except the header text.
    
  1021.         // So we don't expect a remount.
    
  1022.         expect(container.firstChild).toBe(el);
    
  1023.         expect(el.textContent).toBe('BXY');
    
  1024. 
    
  1025.         patch(`
    
  1026.           const App = () => {
    
  1027.             const [x, setX] = useFancyState('X');
    
  1028.             const [y, setY] = useFancyState('Y');
    
  1029.             return <h1>C{x}{y}</h1>;
    
  1030.           };
    
  1031. 
    
  1032.           const useFancyState = (initialState) => {
    
  1033.             const result = useIndirection(initialState);
    
  1034.             return result;
    
  1035.           };
    
  1036. 
    
  1037.           function useIndirection(initialState) {
    
  1038.             React.useEffect(() => {});
    
  1039.             return React.useState(initialState);
    
  1040.           }
    
  1041. 
    
  1042.           export default App;
    
  1043.         `);
    
  1044.         // The useIndirection Hook added an affect,
    
  1045.         // so we had to remount the component.
    
  1046.         expect(container.firstChild).not.toBe(el);
    
  1047.         el = container.firstChild;
    
  1048.         expect(el.textContent).toBe('CXY');
    
  1049. 
    
  1050.         patch(`
    
  1051.           const App = () => {
    
  1052.             const [x, setX] = useFancyState('X');
    
  1053.             const [y, setY] = useFancyState('Y');
    
  1054.             return <h1>D{x}{y}</h1>;
    
  1055.           };
    
  1056. 
    
  1057.           const useFancyState = (initialState) => {
    
  1058.             const result = useIndirection();
    
  1059.             return result;
    
  1060.           };
    
  1061. 
    
  1062.           function useIndirection(initialState) {
    
  1063.             React.useEffect(() => {});
    
  1064.             return React.useState(initialState);
    
  1065.           }
    
  1066. 
    
  1067.           export default App;
    
  1068.         `);
    
  1069.         // We didn't change anything except the header text.
    
  1070.         // So we don't expect a remount.
    
  1071.         expect(container.firstChild).toBe(el);
    
  1072.         expect(el.textContent).toBe('DXY');
    
  1073.       }
    
  1074.     });
    
  1075. 
    
  1076.     it('does not lose the inferred arrow names', () => {
    
  1077.       if (__DEV__) {
    
  1078.         render(`
    
  1079.           const Parent = () => {
    
  1080.             return <Child/>;
    
  1081.           };
    
  1082. 
    
  1083.           const Child = () => {
    
  1084.             useMyThing();
    
  1085.             return <h1>{Parent.name} {Child.name} {useMyThing.name}</h1>;
    
  1086.           };
    
  1087. 
    
  1088.           const useMyThing = () => {
    
  1089.             React.useState();
    
  1090.           };
    
  1091. 
    
  1092.           export default Parent;
    
  1093.         `);
    
  1094.         expect(container.textContent).toBe('Parent Child useMyThing');
    
  1095.       }
    
  1096.     });
    
  1097. 
    
  1098.     it('does not lose the inferred function names', () => {
    
  1099.       if (__DEV__) {
    
  1100.         render(`
    
  1101.           var Parent = function() {
    
  1102.             return <Child/>;
    
  1103.           };
    
  1104. 
    
  1105.           var Child = function() {
    
  1106.             useMyThing();
    
  1107.             return <h1>{Parent.name} {Child.name} {useMyThing.name}</h1>;
    
  1108.           };
    
  1109. 
    
  1110.           var useMyThing = function() {
    
  1111.             React.useState();
    
  1112.           };
    
  1113. 
    
  1114.           export default Parent;
    
  1115.         `);
    
  1116.         expect(container.textContent).toBe('Parent Child useMyThing');
    
  1117.       }
    
  1118.     });
    
  1119. 
    
  1120.     it('resets state on every edit with @refresh reset annotation', () => {
    
  1121.       if (__DEV__) {
    
  1122.         render(`
    
  1123.           const {useState} = React;
    
  1124.           const S = 1;
    
  1125. 
    
  1126.           export default function App() {
    
  1127.             const [foo, setFoo] = useState(S);
    
  1128.             return <h1>A{foo}</h1>;
    
  1129.           }
    
  1130.         `);
    
  1131.         let el = container.firstChild;
    
  1132.         expect(el.textContent).toBe('A1');
    
  1133. 
    
  1134.         patch(`
    
  1135.           const {useState} = React;
    
  1136.           const S = 2;
    
  1137. 
    
  1138.           export default function App() {
    
  1139.             const [foo, setFoo] = useState(S);
    
  1140.             return <h1>B{foo}</h1>;
    
  1141.           }
    
  1142.         `);
    
  1143.         // Same state variable name, so state is preserved.
    
  1144.         expect(container.firstChild).toBe(el);
    
  1145.         expect(el.textContent).toBe('B1');
    
  1146. 
    
  1147.         patch(`
    
  1148.           const {useState} = React;
    
  1149.           const S = 3;
    
  1150. 
    
  1151.           /* @refresh reset */
    
  1152. 
    
  1153.           export default function App() {
    
  1154.             const [foo, setFoo] = useState(S);
    
  1155.             return <h1>C{foo}</h1>;
    
  1156.           }
    
  1157.         `);
    
  1158.         // Found remount annotation, so state is reset.
    
  1159.         expect(container.firstChild).not.toBe(el);
    
  1160.         el = container.firstChild;
    
  1161.         expect(el.textContent).toBe('C3');
    
  1162. 
    
  1163.         patch(`
    
  1164.           const {useState} = React;
    
  1165.           const S = 4;
    
  1166. 
    
  1167.           export default function App() {
    
  1168. 
    
  1169.             // @refresh reset
    
  1170. 
    
  1171.             const [foo, setFoo] = useState(S);
    
  1172.             return <h1>D{foo}</h1>;
    
  1173.           }
    
  1174.         `);
    
  1175.         // Found remount annotation, so state is reset.
    
  1176.         expect(container.firstChild).not.toBe(el);
    
  1177.         el = container.firstChild;
    
  1178.         expect(el.textContent).toBe('D4');
    
  1179. 
    
  1180.         patch(`
    
  1181.           const {useState} = React;
    
  1182.           const S = 5;
    
  1183. 
    
  1184.           export default function App() {
    
  1185.             const [foo, setFoo] = useState(S);
    
  1186.             return <h1>E{foo}</h1>;
    
  1187.           }
    
  1188.         `);
    
  1189.         // There is no remount annotation anymore,
    
  1190.         // so preserve the previous state.
    
  1191.         expect(container.firstChild).toBe(el);
    
  1192.         expect(el.textContent).toBe('E4');
    
  1193. 
    
  1194.         patch(`
    
  1195.           const {useState} = React;
    
  1196.           const S = 6;
    
  1197. 
    
  1198.           export default function App() {
    
  1199.             const [foo, setFoo] = useState(S);
    
  1200.             return <h1>F{foo}</h1>;
    
  1201.           }
    
  1202.         `);
    
  1203.         // Continue editing.
    
  1204.         expect(container.firstChild).toBe(el);
    
  1205.         expect(el.textContent).toBe('F4');
    
  1206. 
    
  1207.         patch(`
    
  1208.           const {useState} = React;
    
  1209.           const S = 7;
    
  1210. 
    
  1211.           export default function App() {
    
  1212. 
    
  1213.             /* @refresh reset */
    
  1214. 
    
  1215.             const [foo, setFoo] = useState(S);
    
  1216.             return <h1>G{foo}</h1>;
    
  1217.           }
    
  1218.         `);
    
  1219.         // Force remount one last time.
    
  1220.         expect(container.firstChild).not.toBe(el);
    
  1221.         el = container.firstChild;
    
  1222.         expect(el.textContent).toBe('G7');
    
  1223.       }
    
  1224.     });
    
  1225. 
    
  1226.     // This is best effort for simple cases.
    
  1227.     // We won't attempt to resolve identifiers.
    
  1228.     it('resets state when useState initial state is edited', () => {
    
  1229.       if (__DEV__) {
    
  1230.         render(`
    
  1231.           const {useState} = React;
    
  1232. 
    
  1233.           export default function App() {
    
  1234.             const [foo, setFoo] = useState(1);
    
  1235.             return <h1>A{foo}</h1>;
    
  1236.           }
    
  1237.         `);
    
  1238.         let el = container.firstChild;
    
  1239.         expect(el.textContent).toBe('A1');
    
  1240. 
    
  1241.         patch(`
    
  1242.           const {useState} = React;
    
  1243. 
    
  1244.           export default function App() {
    
  1245.             const [foo, setFoo] = useState(1);
    
  1246.             return <h1>B{foo}</h1>;
    
  1247.           }
    
  1248.         `);
    
  1249.         // Same initial state, so it's preserved.
    
  1250.         expect(container.firstChild).toBe(el);
    
  1251.         expect(el.textContent).toBe('B1');
    
  1252. 
    
  1253.         patch(`
    
  1254.           const {useState} = React;
    
  1255. 
    
  1256.           export default function App() {
    
  1257.             const [foo, setFoo] = useState(2);
    
  1258.             return <h1>C{foo}</h1>;
    
  1259.           }
    
  1260.         `);
    
  1261.         // Different initial state, so state is reset.
    
  1262.         expect(container.firstChild).not.toBe(el);
    
  1263.         el = container.firstChild;
    
  1264.         expect(el.textContent).toBe('C2');
    
  1265.       }
    
  1266.     });
    
  1267. 
    
  1268.     // This is best effort for simple cases.
    
  1269.     // We won't attempt to resolve identifiers.
    
  1270.     it('resets state when useReducer initial state is edited', () => {
    
  1271.       if (__DEV__) {
    
  1272.         render(`
    
  1273.           const {useReducer} = React;
    
  1274. 
    
  1275.           export default function App() {
    
  1276.             const [foo, setFoo] = useReducer(x => x, 1);
    
  1277.             return <h1>A{foo}</h1>;
    
  1278.           }
    
  1279.         `);
    
  1280.         let el = container.firstChild;
    
  1281.         expect(el.textContent).toBe('A1');
    
  1282. 
    
  1283.         patch(`
    
  1284.           const {useReducer} = React;
    
  1285. 
    
  1286.           export default function App() {
    
  1287.             const [foo, setFoo] = useReducer(x => x, 1);
    
  1288.             return <h1>B{foo}</h1>;
    
  1289.           }
    
  1290.         `);
    
  1291.         // Same initial state, so it's preserved.
    
  1292.         expect(container.firstChild).toBe(el);
    
  1293.         expect(el.textContent).toBe('B1');
    
  1294. 
    
  1295.         patch(`
    
  1296.           const {useReducer} = React;
    
  1297. 
    
  1298.           export default function App() {
    
  1299.             const [foo, setFoo] = useReducer(x => x, 2);
    
  1300.             return <h1>C{foo}</h1>;
    
  1301.           }
    
  1302.         `);
    
  1303.         // Different initial state, so state is reset.
    
  1304.         expect(container.firstChild).not.toBe(el);
    
  1305.         el = container.firstChild;
    
  1306.         expect(el.textContent).toBe('C2');
    
  1307.       }
    
  1308.     });
    
  1309. 
    
  1310.     it('remounts when switching export from function to class', () => {
    
  1311.       if (__DEV__) {
    
  1312.         render(`
    
  1313.           export default function App() {
    
  1314.             return <h1>A1</h1>;
    
  1315.           }
    
  1316.         `);
    
  1317.         let el = container.firstChild;
    
  1318.         expect(el.textContent).toBe('A1');
    
  1319.         patch(`
    
  1320.           export default function App() {
    
  1321.             return <h1>A2</h1>;
    
  1322.           }
    
  1323.         `);
    
  1324.         // Keep state.
    
  1325.         expect(container.firstChild).toBe(el);
    
  1326.         expect(el.textContent).toBe('A2');
    
  1327. 
    
  1328.         patch(`
    
  1329.           export default class App extends React.Component {
    
  1330.             render() {
    
  1331.               return <h1>B1</h1>
    
  1332.             }
    
  1333.           }
    
  1334.         `);
    
  1335.         // Reset (function -> class).
    
  1336.         expect(container.firstChild).not.toBe(el);
    
  1337.         el = container.firstChild;
    
  1338.         expect(el.textContent).toBe('B1');
    
  1339.         patch(`
    
  1340.           export default class App extends React.Component {
    
  1341.             render() {
    
  1342.               return <h1>B2</h1>
    
  1343.             }
    
  1344.           }
    
  1345.         `);
    
  1346.         // Reset (classes always do).
    
  1347.         expect(container.firstChild).not.toBe(el);
    
  1348.         el = container.firstChild;
    
  1349.         expect(el.textContent).toBe('B2');
    
  1350. 
    
  1351.         patch(`
    
  1352.           export default function App() {
    
  1353.             return <h1>C1</h1>;
    
  1354.           }
    
  1355.         `);
    
  1356.         // Reset (class -> function).
    
  1357.         expect(container.firstChild).not.toBe(el);
    
  1358.         el = container.firstChild;
    
  1359.         expect(el.textContent).toBe('C1');
    
  1360.         patch(`
    
  1361.           export default function App() {
    
  1362.             return <h1>C2</h1>;
    
  1363.           }
    
  1364.         `);
    
  1365.         expect(container.firstChild).toBe(el);
    
  1366.         expect(el.textContent).toBe('C2');
    
  1367. 
    
  1368.         patch(`
    
  1369.           export default function App() {
    
  1370.             return <h1>D1</h1>;
    
  1371.           }
    
  1372.         `);
    
  1373.         el = container.firstChild;
    
  1374.         expect(el.textContent).toBe('D1');
    
  1375.         patch(`
    
  1376.           export default function App() {
    
  1377.             return <h1>D2</h1>;
    
  1378.           }
    
  1379.         `);
    
  1380.         // Keep state.
    
  1381.         expect(container.firstChild).toBe(el);
    
  1382.         expect(el.textContent).toBe('D2');
    
  1383.       }
    
  1384.     });
    
  1385. 
    
  1386.     it('remounts when switching export from class to function', () => {
    
  1387.       if (__DEV__) {
    
  1388.         render(`
    
  1389.           export default class App extends React.Component {
    
  1390.             render() {
    
  1391.               return <h1>A1</h1>
    
  1392.             }
    
  1393.           }
    
  1394.         `);
    
  1395.         let el = container.firstChild;
    
  1396.         expect(el.textContent).toBe('A1');
    
  1397.         patch(`
    
  1398.           export default class App extends React.Component {
    
  1399.             render() {
    
  1400.               return <h1>A2</h1>
    
  1401.             }
    
  1402.           }
    
  1403.         `);
    
  1404.         // Reset (classes always do).
    
  1405.         expect(container.firstChild).not.toBe(el);
    
  1406.         el = container.firstChild;
    
  1407.         expect(el.textContent).toBe('A2');
    
  1408. 
    
  1409.         patch(`
    
  1410.           export default function App() {
    
  1411.             return <h1>B1</h1>;
    
  1412.           }
    
  1413.         `);
    
  1414.         // Reset (class -> function).
    
  1415.         expect(container.firstChild).not.toBe(el);
    
  1416.         el = container.firstChild;
    
  1417.         expect(el.textContent).toBe('B1');
    
  1418.         patch(`
    
  1419.           export default function App() {
    
  1420.             return <h1>B2</h1>;
    
  1421.           }
    
  1422.         `);
    
  1423.         // Keep state.
    
  1424.         expect(container.firstChild).toBe(el);
    
  1425.         expect(el.textContent).toBe('B2');
    
  1426. 
    
  1427.         patch(`
    
  1428.           export default class App extends React.Component {
    
  1429.             render() {
    
  1430.               return <h1>C1</h1>
    
  1431.             }
    
  1432.           }
    
  1433.         `);
    
  1434.         // Reset (function -> class).
    
  1435.         expect(container.firstChild).not.toBe(el);
    
  1436.         el = container.firstChild;
    
  1437.         expect(el.textContent).toBe('C1');
    
  1438.       }
    
  1439.     });
    
  1440. 
    
  1441.     it('remounts when wrapping export in a HOC', () => {
    
  1442.       if (__DEV__) {
    
  1443.         render(`
    
  1444.           export default function App() {
    
  1445.             return <h1>A1</h1>;
    
  1446.           }
    
  1447.         `);
    
  1448.         let el = container.firstChild;
    
  1449.         expect(el.textContent).toBe('A1');
    
  1450.         patch(`
    
  1451.           export default function App() {
    
  1452.             return <h1>A2</h1>;
    
  1453.           }
    
  1454.         `);
    
  1455.         // Keep state.
    
  1456.         expect(container.firstChild).toBe(el);
    
  1457.         expect(el.textContent).toBe('A2');
    
  1458. 
    
  1459.         patch(`
    
  1460.           function hoc(Inner) {
    
  1461.             return function Wrapper() {
    
  1462.               return <Inner />;
    
  1463.             }
    
  1464.           }
    
  1465. 
    
  1466.           function App() {
    
  1467.             return <h1>B1</h1>;
    
  1468.           }
    
  1469. 
    
  1470.           export default hoc(App);
    
  1471.         `);
    
  1472.         // Reset (wrapped in HOC).
    
  1473.         expect(container.firstChild).not.toBe(el);
    
  1474.         el = container.firstChild;
    
  1475.         expect(el.textContent).toBe('B1');
    
  1476.         patch(`
    
  1477.           function hoc(Inner) {
    
  1478.             return function Wrapper() {
    
  1479.               return <Inner />;
    
  1480.             }
    
  1481.           }
    
  1482. 
    
  1483.           function App() {
    
  1484.             return <h1>B2</h1>;
    
  1485.           }
    
  1486. 
    
  1487.           export default hoc(App);
    
  1488.         `);
    
  1489.         // Keep state.
    
  1490.         expect(container.firstChild).toBe(el);
    
  1491.         expect(el.textContent).toBe('B2');
    
  1492. 
    
  1493.         patch(`
    
  1494.           export default function App() {
    
  1495.             return <h1>C1</h1>;
    
  1496.           }
    
  1497.         `);
    
  1498.         // Reset (unwrapped).
    
  1499.         expect(container.firstChild).not.toBe(el);
    
  1500.         el = container.firstChild;
    
  1501.         expect(el.textContent).toBe('C1');
    
  1502.         patch(`
    
  1503.           export default function App() {
    
  1504.             return <h1>C2</h1>;
    
  1505.           }
    
  1506.         `);
    
  1507.         expect(container.firstChild).toBe(el);
    
  1508.         expect(el.textContent).toBe('C2');
    
  1509.       }
    
  1510.     });
    
  1511. 
    
  1512.     it('remounts when wrapping export in memo()', () => {
    
  1513.       if (__DEV__) {
    
  1514.         render(`
    
  1515.           export default function App() {
    
  1516.             return <h1>A1</h1>;
    
  1517.           }
    
  1518.         `);
    
  1519.         let el = container.firstChild;
    
  1520.         expect(el.textContent).toBe('A1');
    
  1521.         patch(`
    
  1522.           export default function App() {
    
  1523.             return <h1>A2</h1>;
    
  1524.           }
    
  1525.         `);
    
  1526.         // Keep state.
    
  1527.         expect(container.firstChild).toBe(el);
    
  1528.         expect(el.textContent).toBe('A2');
    
  1529. 
    
  1530.         patch(`
    
  1531.           function App() {
    
  1532.             return <h1>B1</h1>;
    
  1533.           }
    
  1534. 
    
  1535.           export default React.memo(App);
    
  1536.         `);
    
  1537.         // Reset (wrapped in HOC).
    
  1538.         expect(container.firstChild).not.toBe(el);
    
  1539.         el = container.firstChild;
    
  1540.         expect(el.textContent).toBe('B1');
    
  1541.         patch(`
    
  1542.           function App() {
    
  1543.             return <h1>B2</h1>;
    
  1544.           }
    
  1545. 
    
  1546.           export default React.memo(App);
    
  1547.         `);
    
  1548.         // Keep state.
    
  1549.         expect(container.firstChild).toBe(el);
    
  1550.         expect(el.textContent).toBe('B2');
    
  1551. 
    
  1552.         patch(`
    
  1553.           export default function App() {
    
  1554.             return <h1>C1</h1>;
    
  1555.           }
    
  1556.         `);
    
  1557.         // Reset (unwrapped).
    
  1558.         expect(container.firstChild).not.toBe(el);
    
  1559.         el = container.firstChild;
    
  1560.         expect(el.textContent).toBe('C1');
    
  1561.         patch(`
    
  1562.           export default function App() {
    
  1563.             return <h1>C2</h1>;
    
  1564.           }
    
  1565.         `);
    
  1566.         expect(container.firstChild).toBe(el);
    
  1567.         expect(el.textContent).toBe('C2');
    
  1568.       }
    
  1569.     });
    
  1570. 
    
  1571.     it('remounts when wrapping export in forwardRef()', () => {
    
  1572.       if (__DEV__) {
    
  1573.         render(`
    
  1574.           export default function App() {
    
  1575.             return <h1>A1</h1>;
    
  1576.           }
    
  1577.         `);
    
  1578.         let el = container.firstChild;
    
  1579.         expect(el.textContent).toBe('A1');
    
  1580.         patch(`
    
  1581.           export default function App() {
    
  1582.             return <h1>A2</h1>;
    
  1583.           }
    
  1584.         `);
    
  1585.         // Keep state.
    
  1586.         expect(container.firstChild).toBe(el);
    
  1587.         expect(el.textContent).toBe('A2');
    
  1588. 
    
  1589.         patch(`
    
  1590.           function App() {
    
  1591.             return <h1>B1</h1>;
    
  1592.           }
    
  1593. 
    
  1594.           export default React.forwardRef(App);
    
  1595.         `);
    
  1596.         // Reset (wrapped in HOC).
    
  1597.         expect(container.firstChild).not.toBe(el);
    
  1598.         el = container.firstChild;
    
  1599.         expect(el.textContent).toBe('B1');
    
  1600.         patch(`
    
  1601.           function App() {
    
  1602.             return <h1>B2</h1>;
    
  1603.           }
    
  1604. 
    
  1605.           export default React.forwardRef(App);
    
  1606.         `);
    
  1607.         // Keep state.
    
  1608.         expect(container.firstChild).toBe(el);
    
  1609.         expect(el.textContent).toBe('B2');
    
  1610. 
    
  1611.         patch(`
    
  1612.           export default function App() {
    
  1613.             return <h1>C1</h1>;
    
  1614.           }
    
  1615.         `);
    
  1616.         // Reset (unwrapped).
    
  1617.         expect(container.firstChild).not.toBe(el);
    
  1618.         el = container.firstChild;
    
  1619.         expect(el.textContent).toBe('C1');
    
  1620.         patch(`
    
  1621.           export default function App() {
    
  1622.             return <h1>C2</h1>;
    
  1623.           }
    
  1624.         `);
    
  1625.         expect(container.firstChild).toBe(el);
    
  1626.         expect(el.textContent).toBe('C2');
    
  1627.       }
    
  1628.     });
    
  1629. 
    
  1630.     if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
    
  1631.       it('remounts deprecated factory components', () => {
    
  1632.         if (__DEV__) {
    
  1633.           expect(() => {
    
  1634.             render(`
    
  1635.               function Parent() {
    
  1636.                 return {
    
  1637.                   render() {
    
  1638.                     return <Child prop="A" />;
    
  1639.                   }
    
  1640.                 };
    
  1641.               };
    
  1642. 
    
  1643.               function Child({prop}) {
    
  1644.                 return <h1>{prop}1</h1>;
    
  1645.               };
    
  1646. 
    
  1647.               export default Parent;
    
  1648.             `);
    
  1649.           }).toErrorDev(
    
  1650.             'The <Parent /> component appears to be a function component ' +
    
  1651.               'that returns a class instance.',
    
  1652.           );
    
  1653.           const el = container.firstChild;
    
  1654.           expect(el.textContent).toBe('A1');
    
  1655.           patch(`
    
  1656.             function Parent() {
    
  1657.               return {
    
  1658.                 render() {
    
  1659.                   return <Child prop="B" />;
    
  1660.                 }
    
  1661.               };
    
  1662.             };
    
  1663. 
    
  1664.             function Child({prop}) {
    
  1665.               return <h1>{prop}2</h1>;
    
  1666.             };
    
  1667. 
    
  1668.             export default Parent;
    
  1669.           `);
    
  1670.           // Like classes, factory components always remount.
    
  1671.           expect(container.firstChild).not.toBe(el);
    
  1672.           const newEl = container.firstChild;
    
  1673.           expect(newEl.textContent).toBe('B2');
    
  1674.         }
    
  1675.       });
    
  1676.     }
    
  1677. 
    
  1678.     describe('with inline requires', () => {
    
  1679.       beforeEach(() => {
    
  1680.         global.FakeModuleSystem = {};
    
  1681.       });
    
  1682. 
    
  1683.       afterEach(() => {
    
  1684.         delete global.FakeModuleSystem;
    
  1685.       });
    
  1686. 
    
  1687.       it('remounts component if custom hook it uses changes order on first edit', () => {
    
  1688.         // This test verifies that remounting works even if calls to custom Hooks
    
  1689.         // were transformed with an inline requires transform, like we have on RN.
    
  1690.         // Inline requires make it harder to compare previous and next signatures
    
  1691.         // because useFancyState inline require always resolves to the newest version.
    
  1692.         // We're not actually using inline requires in the test, but it has similar semantics.
    
  1693.         if (__DEV__) {
    
  1694.           render(`
    
  1695.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1696. 
    
  1697.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1698.               return React.useState(initialState);
    
  1699.             };
    
  1700. 
    
  1701.             const App = () => {
    
  1702.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1703.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1704.               return <h1>A{x}{y}</h1>;
    
  1705.             };
    
  1706. 
    
  1707.             export default App;
    
  1708.           `);
    
  1709.           let el = container.firstChild;
    
  1710.           expect(el.textContent).toBe('AXY');
    
  1711. 
    
  1712.           patch(`
    
  1713.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1714. 
    
  1715.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1716.               React.useEffect(() => {});
    
  1717.               return React.useState(initialState);
    
  1718.             };
    
  1719. 
    
  1720.             const App = () => {
    
  1721.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1722.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1723.               return <h1>B{x}{y}</h1>;
    
  1724.             };
    
  1725. 
    
  1726.             export default App;
    
  1727.           `);
    
  1728.           // The useFancyState Hook added an effect,
    
  1729.           // so we had to remount the component.
    
  1730.           expect(container.firstChild).not.toBe(el);
    
  1731.           el = container.firstChild;
    
  1732.           expect(el.textContent).toBe('BXY');
    
  1733. 
    
  1734.           patch(`
    
  1735.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1736. 
    
  1737.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1738.               React.useEffect(() => {});
    
  1739.               return React.useState(initialState);
    
  1740.             };
    
  1741. 
    
  1742.             const App = () => {
    
  1743.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1744.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1745.               return <h1>C{x}{y}</h1>;
    
  1746.             };
    
  1747. 
    
  1748.             export default App;
    
  1749.           `);
    
  1750.           // We didn't change anything except the header text.
    
  1751.           // So we don't expect a remount.
    
  1752.           expect(container.firstChild).toBe(el);
    
  1753.           expect(el.textContent).toBe('CXY');
    
  1754.         }
    
  1755.       });
    
  1756. 
    
  1757.       it('remounts component if custom hook it uses changes order on second edit', () => {
    
  1758.         if (__DEV__) {
    
  1759.           render(`
    
  1760.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1761. 
    
  1762.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1763.               return React.useState(initialState);
    
  1764.             };
    
  1765. 
    
  1766.             const App = () => {
    
  1767.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1768.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1769.               return <h1>A{x}{y}</h1>;
    
  1770.             };
    
  1771. 
    
  1772.             export default App;
    
  1773.           `);
    
  1774.           let el = container.firstChild;
    
  1775.           expect(el.textContent).toBe('AXY');
    
  1776. 
    
  1777.           patch(`
    
  1778.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1779. 
    
  1780.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1781.               return React.useState(initialState);
    
  1782.             };
    
  1783. 
    
  1784.             const App = () => {
    
  1785.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1786.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1787.               return <h1>B{x}{y}</h1>;
    
  1788.             };
    
  1789. 
    
  1790.             export default App;
    
  1791.           `);
    
  1792.           expect(container.firstChild).toBe(el);
    
  1793.           expect(el.textContent).toBe('BXY');
    
  1794. 
    
  1795.           patch(`
    
  1796.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1797. 
    
  1798.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1799.               React.useEffect(() => {});
    
  1800.               return React.useState(initialState);
    
  1801.             };
    
  1802. 
    
  1803.             const App = () => {
    
  1804.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1805.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1806.               return <h1>C{x}{y}</h1>;
    
  1807.             };
    
  1808. 
    
  1809.             export default App;
    
  1810.           `);
    
  1811.           // The useFancyState Hook added an effect,
    
  1812.           // so we had to remount the component.
    
  1813.           expect(container.firstChild).not.toBe(el);
    
  1814.           el = container.firstChild;
    
  1815.           expect(el.textContent).toBe('CXY');
    
  1816. 
    
  1817.           patch(`
    
  1818.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1819. 
    
  1820.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1821.               React.useEffect(() => {});
    
  1822.               return React.useState(initialState);
    
  1823.             };
    
  1824. 
    
  1825.             const App = () => {
    
  1826.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1827.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1828.               return <h1>D{x}{y}</h1>;
    
  1829.             };
    
  1830. 
    
  1831.             export default App;
    
  1832.           `);
    
  1833.           // We didn't change anything except the header text.
    
  1834.           // So we don't expect a remount.
    
  1835.           expect(container.firstChild).toBe(el);
    
  1836.           expect(el.textContent).toBe('DXY');
    
  1837.         }
    
  1838.       });
    
  1839. 
    
  1840.       it('recovers if evaluating Hook list throws', () => {
    
  1841.         if (__DEV__) {
    
  1842.           render(`
    
  1843.           let FakeModuleSystem = null;
    
  1844. 
    
  1845.           global.FakeModuleSystem.useFancyState = function(initialState) {
    
  1846.             return React.useState(initialState);
    
  1847.           };
    
  1848. 
    
  1849.           const App = () => {
    
  1850.             FakeModuleSystem = global.FakeModuleSystem;
    
  1851.             const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1852.             const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1853.             return <h1>A{x}{y}</h1>;
    
  1854.           };
    
  1855. 
    
  1856.           export default App;
    
  1857.         `);
    
  1858.           let el = container.firstChild;
    
  1859.           expect(el.textContent).toBe('AXY');
    
  1860. 
    
  1861.           patch(`
    
  1862.           let FakeModuleSystem = null;
    
  1863. 
    
  1864.           global.FakeModuleSystem.useFancyState = function(initialState) {
    
  1865.             React.useEffect(() => {});
    
  1866.             return React.useState(initialState);
    
  1867.           };
    
  1868. 
    
  1869.           const App = () => {
    
  1870.             FakeModuleSystem = global.FakeModuleSystem;
    
  1871.             const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1872.             const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1873.             return <h1>B{x}{y}</h1>;
    
  1874.           };
    
  1875. 
    
  1876.           export default App;
    
  1877.         `);
    
  1878.           // We couldn't evaluate the Hook signatures
    
  1879.           // so we had to remount the component.
    
  1880.           expect(container.firstChild).not.toBe(el);
    
  1881.           el = container.firstChild;
    
  1882.           expect(el.textContent).toBe('BXY');
    
  1883.         }
    
  1884.       });
    
  1885. 
    
  1886.       it('remounts component if custom hook it uses changes order behind an indirection', () => {
    
  1887.         if (__DEV__) {
    
  1888.           render(`
    
  1889.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1890. 
    
  1891.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1892.               return FakeModuleSystem.useIndirection(initialState);
    
  1893.             };
    
  1894. 
    
  1895.             FakeModuleSystem.useIndirection = function(initialState) {
    
  1896.               return FakeModuleSystem.useOtherIndirection(initialState);
    
  1897.             };
    
  1898. 
    
  1899.             FakeModuleSystem.useOtherIndirection = function(initialState) {
    
  1900.               return React.useState(initialState);
    
  1901.             };
    
  1902. 
    
  1903.             const App = () => {
    
  1904.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1905.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1906.               return <h1>A{x}{y}</h1>;
    
  1907.             };
    
  1908. 
    
  1909.             export default App;
    
  1910.           `);
    
  1911.           let el = container.firstChild;
    
  1912.           expect(el.textContent).toBe('AXY');
    
  1913. 
    
  1914.           patch(`
    
  1915.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1916. 
    
  1917.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1918.               return FakeModuleSystem.useIndirection(initialState);
    
  1919.             };
    
  1920. 
    
  1921.             FakeModuleSystem.useIndirection = function(initialState) {
    
  1922.               return FakeModuleSystem.useOtherIndirection(initialState);
    
  1923.             };
    
  1924. 
    
  1925.             FakeModuleSystem.useOtherIndirection = function(initialState) {
    
  1926.               React.useEffect(() => {});
    
  1927.               return React.useState(initialState);
    
  1928.             };
    
  1929. 
    
  1930.             const App = () => {
    
  1931.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1932.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1933.               return <h1>B{x}{y}</h1>;
    
  1934.             };
    
  1935. 
    
  1936.             export default App;
    
  1937.           `);
    
  1938. 
    
  1939.           // The useFancyState Hook added an effect,
    
  1940.           // so we had to remount the component.
    
  1941.           expect(container.firstChild).not.toBe(el);
    
  1942.           el = container.firstChild;
    
  1943.           expect(el.textContent).toBe('BXY');
    
  1944. 
    
  1945.           patch(`
    
  1946.             const FakeModuleSystem = global.FakeModuleSystem;
    
  1947. 
    
  1948.             FakeModuleSystem.useFancyState = function(initialState) {
    
  1949.               return FakeModuleSystem.useIndirection(initialState);
    
  1950.             };
    
  1951. 
    
  1952.             FakeModuleSystem.useIndirection = function(initialState) {
    
  1953.               return FakeModuleSystem.useOtherIndirection(initialState);
    
  1954.             };
    
  1955. 
    
  1956.             FakeModuleSystem.useOtherIndirection = function(initialState) {
    
  1957.               React.useEffect(() => {});
    
  1958.               return React.useState(initialState);
    
  1959.             };
    
  1960. 
    
  1961.             const App = () => {
    
  1962.               const [x, setX] = FakeModuleSystem.useFancyState('X');
    
  1963.               const [y, setY] = FakeModuleSystem.useFancyState('Y');
    
  1964.               return <h1>C{x}{y}</h1>;
    
  1965.             };
    
  1966. 
    
  1967.             export default App;
    
  1968.           `);
    
  1969.           // We didn't change anything except the header text.
    
  1970.           // So we don't expect a remount.
    
  1971.           expect(container.firstChild).toBe(el);
    
  1972.           expect(el.textContent).toBe('CXY');
    
  1973.         }
    
  1974.       });
    
  1975.     });
    
  1976.   }
    
  1977. 
    
  1978.   function testTypescript(render, patch) {
    
  1979.     it('reloads component exported in typescript namespace', () => {
    
  1980.       if (__DEV__) {
    
  1981.         render(`
    
  1982.           namespace Foo {
    
  1983.             export namespace Bar {
    
  1984.               export const Child = ({prop}) => {
    
  1985.                 return <h1>{prop}1</h1>
    
  1986.               };
    
  1987.             }
    
  1988.           }
    
  1989. 
    
  1990.           export default function Parent() {
    
  1991.             return <Foo.Bar.Child prop={'A'} />;
    
  1992.           }
    
  1993.         `);
    
  1994.         const el = container.firstChild;
    
  1995.         expect(el.textContent).toBe('A1');
    
  1996.         patch(`
    
  1997.           namespace Foo {
    
  1998.             export namespace Bar {
    
  1999.               export const Child = ({prop}) => {
    
  2000.                 return <h1>{prop}2</h1>
    
  2001.               };
    
  2002.             }
    
  2003.           }
    
  2004. 
    
  2005.           export default function Parent() {
    
  2006.             return <Foo.Bar.Child prop={'B'} />;
    
  2007.           }
    
  2008.         `);
    
  2009.         expect(container.firstChild).toBe(el);
    
  2010.         expect(el.textContent).toBe('B2');
    
  2011.       }
    
  2012.     });
    
  2013.   }
    
  2014. });