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. 'use strict';
    
  11. 
    
  12. let React;
    
  13. let ReactTestRenderer;
    
  14. let Scheduler;
    
  15. let act;
    
  16. let assertLog;
    
  17. 
    
  18. describe('StrictEffectsMode', () => {
    
  19.   beforeEach(() => {
    
  20.     jest.resetModules();
    
  21.     React = require('react');
    
  22.     ReactTestRenderer = require('react-test-renderer');
    
  23.     Scheduler = require('scheduler');
    
  24.     act = require('internal-test-utils').act;
    
  25. 
    
  26.     const InternalTestUtils = require('internal-test-utils');
    
  27.     assertLog = InternalTestUtils.assertLog;
    
  28.   });
    
  29. 
    
  30.   function supportsDoubleInvokeEffects() {
    
  31.     return gate(
    
  32.       flags =>
    
  33.         flags.build === 'development' &&
    
  34.         flags.createRootStrictEffectsByDefault &&
    
  35.         flags.dfsEffectsRefactor,
    
  36.     );
    
  37.   }
    
  38. 
    
  39.   it('should not double invoke effects in legacy mode', async () => {
    
  40.     function App({text}) {
    
  41.       React.useEffect(() => {
    
  42.         Scheduler.log('useEffect mount');
    
  43.         return () => Scheduler.log('useEffect unmount');
    
  44.       });
    
  45. 
    
  46.       React.useLayoutEffect(() => {
    
  47.         Scheduler.log('useLayoutEffect mount');
    
  48.         return () => Scheduler.log('useLayoutEffect unmount');
    
  49.       });
    
  50. 
    
  51.       return text;
    
  52.     }
    
  53. 
    
  54.     await act(() => {
    
  55.       ReactTestRenderer.create(<App text={'mount'} />);
    
  56.     });
    
  57. 
    
  58.     assertLog(['useLayoutEffect mount', 'useEffect mount']);
    
  59.   });
    
  60. 
    
  61.   it('double invoking for effects works properly', async () => {
    
  62.     function App({text}) {
    
  63.       React.useEffect(() => {
    
  64.         Scheduler.log('useEffect mount');
    
  65.         return () => Scheduler.log('useEffect unmount');
    
  66.       });
    
  67. 
    
  68.       React.useLayoutEffect(() => {
    
  69.         Scheduler.log('useLayoutEffect mount');
    
  70.         return () => Scheduler.log('useLayoutEffect unmount');
    
  71.       });
    
  72. 
    
  73.       return text;
    
  74.     }
    
  75. 
    
  76.     let renderer;
    
  77.     await act(() => {
    
  78.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  79.         unstable_isConcurrent: true,
    
  80.       });
    
  81.     });
    
  82. 
    
  83.     if (supportsDoubleInvokeEffects()) {
    
  84.       assertLog([
    
  85.         'useLayoutEffect mount',
    
  86.         'useEffect mount',
    
  87.         'useLayoutEffect unmount',
    
  88.         'useEffect unmount',
    
  89.         'useLayoutEffect mount',
    
  90.         'useEffect mount',
    
  91.       ]);
    
  92.     } else {
    
  93.       assertLog(['useLayoutEffect mount', 'useEffect mount']);
    
  94.     }
    
  95. 
    
  96.     await act(() => {
    
  97.       renderer.update(<App text={'update'} />);
    
  98.     });
    
  99. 
    
  100.     assertLog([
    
  101.       'useLayoutEffect unmount',
    
  102.       'useLayoutEffect mount',
    
  103.       'useEffect unmount',
    
  104.       'useEffect mount',
    
  105.     ]);
    
  106. 
    
  107.     await act(() => {
    
  108.       renderer.unmount();
    
  109.     });
    
  110. 
    
  111.     assertLog(['useLayoutEffect unmount', 'useEffect unmount']);
    
  112.   });
    
  113. 
    
  114.   it('multiple effects are double invoked in the right order (all mounted, all unmounted, all remounted)', async () => {
    
  115.     function App({text}) {
    
  116.       React.useEffect(() => {
    
  117.         Scheduler.log('useEffect One mount');
    
  118.         return () => Scheduler.log('useEffect One unmount');
    
  119.       });
    
  120. 
    
  121.       React.useEffect(() => {
    
  122.         Scheduler.log('useEffect Two mount');
    
  123.         return () => Scheduler.log('useEffect Two unmount');
    
  124.       });
    
  125. 
    
  126.       return text;
    
  127.     }
    
  128. 
    
  129.     let renderer;
    
  130.     await act(() => {
    
  131.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  132.         unstable_isConcurrent: true,
    
  133.       });
    
  134.     });
    
  135. 
    
  136.     if (supportsDoubleInvokeEffects()) {
    
  137.       assertLog([
    
  138.         'useEffect One mount',
    
  139.         'useEffect Two mount',
    
  140.         'useEffect One unmount',
    
  141.         'useEffect Two unmount',
    
  142.         'useEffect One mount',
    
  143.         'useEffect Two mount',
    
  144.       ]);
    
  145.     } else {
    
  146.       assertLog(['useEffect One mount', 'useEffect Two mount']);
    
  147.     }
    
  148. 
    
  149.     await act(() => {
    
  150.       renderer.update(<App text={'update'} />);
    
  151.     });
    
  152. 
    
  153.     assertLog([
    
  154.       'useEffect One unmount',
    
  155.       'useEffect Two unmount',
    
  156.       'useEffect One mount',
    
  157.       'useEffect Two mount',
    
  158.     ]);
    
  159. 
    
  160.     await act(() => {
    
  161.       renderer.unmount(null);
    
  162.     });
    
  163. 
    
  164.     assertLog(['useEffect One unmount', 'useEffect Two unmount']);
    
  165.   });
    
  166. 
    
  167.   it('multiple layout effects are double invoked in the right order (all mounted, all unmounted, all remounted)', async () => {
    
  168.     function App({text}) {
    
  169.       React.useLayoutEffect(() => {
    
  170.         Scheduler.log('useLayoutEffect One mount');
    
  171.         return () => Scheduler.log('useLayoutEffect One unmount');
    
  172.       });
    
  173. 
    
  174.       React.useLayoutEffect(() => {
    
  175.         Scheduler.log('useLayoutEffect Two mount');
    
  176.         return () => Scheduler.log('useLayoutEffect Two unmount');
    
  177.       });
    
  178. 
    
  179.       return text;
    
  180.     }
    
  181. 
    
  182.     let renderer;
    
  183.     await act(() => {
    
  184.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  185.         unstable_isConcurrent: true,
    
  186.       });
    
  187.     });
    
  188. 
    
  189.     if (supportsDoubleInvokeEffects()) {
    
  190.       assertLog([
    
  191.         'useLayoutEffect One mount',
    
  192.         'useLayoutEffect Two mount',
    
  193.         'useLayoutEffect One unmount',
    
  194.         'useLayoutEffect Two unmount',
    
  195.         'useLayoutEffect One mount',
    
  196.         'useLayoutEffect Two mount',
    
  197.       ]);
    
  198.     } else {
    
  199.       assertLog(['useLayoutEffect One mount', 'useLayoutEffect Two mount']);
    
  200.     }
    
  201. 
    
  202.     await act(() => {
    
  203.       renderer.update(<App text={'update'} />);
    
  204.     });
    
  205. 
    
  206.     assertLog([
    
  207.       'useLayoutEffect One unmount',
    
  208.       'useLayoutEffect Two unmount',
    
  209.       'useLayoutEffect One mount',
    
  210.       'useLayoutEffect Two mount',
    
  211.     ]);
    
  212. 
    
  213.     await act(() => {
    
  214.       renderer.unmount();
    
  215.     });
    
  216. 
    
  217.     assertLog(['useLayoutEffect One unmount', 'useLayoutEffect Two unmount']);
    
  218.   });
    
  219. 
    
  220.   it('useEffect and useLayoutEffect is called twice when there is no unmount', async () => {
    
  221.     function App({text}) {
    
  222.       React.useEffect(() => {
    
  223.         Scheduler.log('useEffect mount');
    
  224.       });
    
  225. 
    
  226.       React.useLayoutEffect(() => {
    
  227.         Scheduler.log('useLayoutEffect mount');
    
  228.       });
    
  229. 
    
  230.       return text;
    
  231.     }
    
  232. 
    
  233.     let renderer;
    
  234.     await act(() => {
    
  235.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  236.         unstable_isConcurrent: true,
    
  237.       });
    
  238.     });
    
  239. 
    
  240.     if (supportsDoubleInvokeEffects()) {
    
  241.       assertLog([
    
  242.         'useLayoutEffect mount',
    
  243.         'useEffect mount',
    
  244.         'useLayoutEffect mount',
    
  245.         'useEffect mount',
    
  246.       ]);
    
  247.     } else {
    
  248.       assertLog(['useLayoutEffect mount', 'useEffect mount']);
    
  249.     }
    
  250. 
    
  251.     await act(() => {
    
  252.       renderer.update(<App text={'update'} />);
    
  253.     });
    
  254. 
    
  255.     assertLog(['useLayoutEffect mount', 'useEffect mount']);
    
  256. 
    
  257.     await act(() => {
    
  258.       renderer.unmount();
    
  259.     });
    
  260. 
    
  261.     assertLog([]);
    
  262.   });
    
  263. 
    
  264.   it('passes the right context to class component lifecycles', async () => {
    
  265.     class App extends React.PureComponent {
    
  266.       test() {}
    
  267. 
    
  268.       componentDidMount() {
    
  269.         this.test();
    
  270.         Scheduler.log('componentDidMount');
    
  271.       }
    
  272. 
    
  273.       componentDidUpdate() {
    
  274.         this.test();
    
  275.         Scheduler.log('componentDidUpdate');
    
  276.       }
    
  277. 
    
  278.       componentWillUnmount() {
    
  279.         this.test();
    
  280.         Scheduler.log('componentWillUnmount');
    
  281.       }
    
  282. 
    
  283.       render() {
    
  284.         return null;
    
  285.       }
    
  286.     }
    
  287. 
    
  288.     await act(() => {
    
  289.       ReactTestRenderer.create(<App />, {unstable_isConcurrent: true});
    
  290.     });
    
  291. 
    
  292.     if (supportsDoubleInvokeEffects()) {
    
  293.       assertLog([
    
  294.         'componentDidMount',
    
  295.         'componentWillUnmount',
    
  296.         'componentDidMount',
    
  297.       ]);
    
  298.     } else {
    
  299.       assertLog(['componentDidMount']);
    
  300.     }
    
  301.   });
    
  302. 
    
  303.   it('double invoking works for class components', async () => {
    
  304.     class App extends React.PureComponent {
    
  305.       componentDidMount() {
    
  306.         Scheduler.log('componentDidMount');
    
  307.       }
    
  308. 
    
  309.       componentDidUpdate() {
    
  310.         Scheduler.log('componentDidUpdate');
    
  311.       }
    
  312. 
    
  313.       componentWillUnmount() {
    
  314.         Scheduler.log('componentWillUnmount');
    
  315.       }
    
  316. 
    
  317.       render() {
    
  318.         return this.props.text;
    
  319.       }
    
  320.     }
    
  321. 
    
  322.     let renderer;
    
  323.     await act(() => {
    
  324.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  325.         unstable_isConcurrent: true,
    
  326.       });
    
  327.     });
    
  328. 
    
  329.     if (supportsDoubleInvokeEffects()) {
    
  330.       assertLog([
    
  331.         'componentDidMount',
    
  332.         'componentWillUnmount',
    
  333.         'componentDidMount',
    
  334.       ]);
    
  335.     } else {
    
  336.       assertLog(['componentDidMount']);
    
  337.     }
    
  338. 
    
  339.     await act(() => {
    
  340.       renderer.update(<App text={'update'} />);
    
  341.     });
    
  342. 
    
  343.     assertLog(['componentDidUpdate']);
    
  344. 
    
  345.     await act(() => {
    
  346.       renderer.unmount();
    
  347.     });
    
  348. 
    
  349.     assertLog(['componentWillUnmount']);
    
  350.   });
    
  351. 
    
  352.   it('invokes componentWillUnmount for class components without componentDidMount', async () => {
    
  353.     class App extends React.PureComponent {
    
  354.       componentDidUpdate() {
    
  355.         Scheduler.log('componentDidUpdate');
    
  356.       }
    
  357. 
    
  358.       componentWillUnmount() {
    
  359.         Scheduler.log('componentWillUnmount');
    
  360.       }
    
  361. 
    
  362.       render() {
    
  363.         return this.props.text;
    
  364.       }
    
  365.     }
    
  366. 
    
  367.     let renderer;
    
  368.     await act(() => {
    
  369.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  370.         unstable_isConcurrent: true,
    
  371.       });
    
  372.     });
    
  373. 
    
  374.     if (supportsDoubleInvokeEffects()) {
    
  375.       assertLog(['componentWillUnmount']);
    
  376.     } else {
    
  377.       assertLog([]);
    
  378.     }
    
  379. 
    
  380.     await act(() => {
    
  381.       renderer.update(<App text={'update'} />);
    
  382.     });
    
  383. 
    
  384.     assertLog(['componentDidUpdate']);
    
  385. 
    
  386.     await act(() => {
    
  387.       renderer.unmount();
    
  388.     });
    
  389. 
    
  390.     assertLog(['componentWillUnmount']);
    
  391.   });
    
  392. 
    
  393.   it('should not double invoke class lifecycles in legacy mode', async () => {
    
  394.     class App extends React.PureComponent {
    
  395.       componentDidMount() {
    
  396.         Scheduler.log('componentDidMount');
    
  397.       }
    
  398. 
    
  399.       componentDidUpdate() {
    
  400.         Scheduler.log('componentDidUpdate');
    
  401.       }
    
  402. 
    
  403.       componentWillUnmount() {
    
  404.         Scheduler.log('componentWillUnmount');
    
  405.       }
    
  406. 
    
  407.       render() {
    
  408.         return this.props.text;
    
  409.       }
    
  410.     }
    
  411. 
    
  412.     await act(() => {
    
  413.       ReactTestRenderer.create(<App text={'mount'} />);
    
  414.     });
    
  415. 
    
  416.     assertLog(['componentDidMount']);
    
  417.   });
    
  418. 
    
  419.   it('double flushing passive effects only results in one double invoke', async () => {
    
  420.     function App({text}) {
    
  421.       const [state, setState] = React.useState(0);
    
  422.       React.useEffect(() => {
    
  423.         if (state !== 1) {
    
  424.           setState(1);
    
  425.         }
    
  426.         Scheduler.log('useEffect mount');
    
  427.         return () => Scheduler.log('useEffect unmount');
    
  428.       });
    
  429. 
    
  430.       React.useLayoutEffect(() => {
    
  431.         Scheduler.log('useLayoutEffect mount');
    
  432.         return () => Scheduler.log('useLayoutEffect unmount');
    
  433.       });
    
  434. 
    
  435.       Scheduler.log(text);
    
  436.       return text;
    
  437.     }
    
  438. 
    
  439.     await act(() => {
    
  440.       ReactTestRenderer.create(<App text={'mount'} />, {
    
  441.         unstable_isConcurrent: true,
    
  442.       });
    
  443.     });
    
  444. 
    
  445.     if (supportsDoubleInvokeEffects()) {
    
  446.       assertLog([
    
  447.         'mount',
    
  448.         'useLayoutEffect mount',
    
  449.         'useEffect mount',
    
  450.         'useLayoutEffect unmount',
    
  451.         'useEffect unmount',
    
  452.         'useLayoutEffect mount',
    
  453.         'useEffect mount',
    
  454.         'mount',
    
  455.         'useLayoutEffect unmount',
    
  456.         'useLayoutEffect mount',
    
  457.         'useEffect unmount',
    
  458.         'useEffect mount',
    
  459.       ]);
    
  460.     } else {
    
  461.       assertLog([
    
  462.         'mount',
    
  463.         'useLayoutEffect mount',
    
  464.         'useEffect mount',
    
  465.         'mount',
    
  466.         'useLayoutEffect unmount',
    
  467.         'useLayoutEffect mount',
    
  468.         'useEffect unmount',
    
  469.         'useEffect mount',
    
  470.       ]);
    
  471.     }
    
  472.   });
    
  473. 
    
  474.   it('newly mounted components after initial mount get double invoked', async () => {
    
  475.     let _setShowChild;
    
  476.     function Child() {
    
  477.       React.useEffect(() => {
    
  478.         Scheduler.log('Child useEffect mount');
    
  479.         return () => Scheduler.log('Child useEffect unmount');
    
  480.       });
    
  481.       React.useLayoutEffect(() => {
    
  482.         Scheduler.log('Child useLayoutEffect mount');
    
  483.         return () => Scheduler.log('Child useLayoutEffect unmount');
    
  484.       });
    
  485. 
    
  486.       return null;
    
  487.     }
    
  488. 
    
  489.     function App() {
    
  490.       const [showChild, setShowChild] = React.useState(false);
    
  491.       _setShowChild = setShowChild;
    
  492.       React.useEffect(() => {
    
  493.         Scheduler.log('App useEffect mount');
    
  494.         return () => Scheduler.log('App useEffect unmount');
    
  495.       });
    
  496.       React.useLayoutEffect(() => {
    
  497.         Scheduler.log('App useLayoutEffect mount');
    
  498.         return () => Scheduler.log('App useLayoutEffect unmount');
    
  499.       });
    
  500. 
    
  501.       return showChild && <Child />;
    
  502.     }
    
  503. 
    
  504.     await act(() => {
    
  505.       ReactTestRenderer.create(<App />, {unstable_isConcurrent: true});
    
  506.     });
    
  507. 
    
  508.     if (supportsDoubleInvokeEffects()) {
    
  509.       assertLog([
    
  510.         'App useLayoutEffect mount',
    
  511.         'App useEffect mount',
    
  512.         'App useLayoutEffect unmount',
    
  513.         'App useEffect unmount',
    
  514.         'App useLayoutEffect mount',
    
  515.         'App useEffect mount',
    
  516.       ]);
    
  517.     } else {
    
  518.       assertLog(['App useLayoutEffect mount', 'App useEffect mount']);
    
  519.     }
    
  520. 
    
  521.     await act(() => {
    
  522.       _setShowChild(true);
    
  523.     });
    
  524. 
    
  525.     if (supportsDoubleInvokeEffects()) {
    
  526.       assertLog([
    
  527.         'App useLayoutEffect unmount',
    
  528.         'Child useLayoutEffect mount',
    
  529.         'App useLayoutEffect mount',
    
  530.         'App useEffect unmount',
    
  531.         'Child useEffect mount',
    
  532.         'App useEffect mount',
    
  533.         'Child useLayoutEffect unmount',
    
  534.         'Child useEffect unmount',
    
  535.         'Child useLayoutEffect mount',
    
  536.         'Child useEffect mount',
    
  537.       ]);
    
  538.     } else {
    
  539.       assertLog([
    
  540.         'App useLayoutEffect unmount',
    
  541.         'Child useLayoutEffect mount',
    
  542.         'App useLayoutEffect mount',
    
  543.         'App useEffect unmount',
    
  544.         'Child useEffect mount',
    
  545.         'App useEffect mount',
    
  546.       ]);
    
  547.     }
    
  548.   });
    
  549. 
    
  550.   it('classes and functions are double invoked together correctly', async () => {
    
  551.     class ClassChild extends React.PureComponent {
    
  552.       componentDidMount() {
    
  553.         Scheduler.log('componentDidMount');
    
  554.       }
    
  555. 
    
  556.       componentWillUnmount() {
    
  557.         Scheduler.log('componentWillUnmount');
    
  558.       }
    
  559. 
    
  560.       render() {
    
  561.         return this.props.text;
    
  562.       }
    
  563.     }
    
  564. 
    
  565.     function FunctionChild({text}) {
    
  566.       React.useEffect(() => {
    
  567.         Scheduler.log('useEffect mount');
    
  568.         return () => Scheduler.log('useEffect unmount');
    
  569.       });
    
  570.       React.useLayoutEffect(() => {
    
  571.         Scheduler.log('useLayoutEffect mount');
    
  572.         return () => Scheduler.log('useLayoutEffect unmount');
    
  573.       });
    
  574.       return text;
    
  575.     }
    
  576. 
    
  577.     function App({text}) {
    
  578.       return (
    
  579.         <>
    
  580.           <ClassChild text={text} />
    
  581.           <FunctionChild text={text} />
    
  582.         </>
    
  583.       );
    
  584.     }
    
  585. 
    
  586.     let renderer;
    
  587.     await act(() => {
    
  588.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  589.         unstable_isConcurrent: true,
    
  590.       });
    
  591.     });
    
  592. 
    
  593.     if (supportsDoubleInvokeEffects()) {
    
  594.       assertLog([
    
  595.         'componentDidMount',
    
  596.         'useLayoutEffect mount',
    
  597.         'useEffect mount',
    
  598.         'componentWillUnmount',
    
  599.         'useLayoutEffect unmount',
    
  600.         'useEffect unmount',
    
  601.         'componentDidMount',
    
  602.         'useLayoutEffect mount',
    
  603.         'useEffect mount',
    
  604.       ]);
    
  605.     } else {
    
  606.       assertLog([
    
  607.         'componentDidMount',
    
  608.         'useLayoutEffect mount',
    
  609.         'useEffect mount',
    
  610.       ]);
    
  611.     }
    
  612. 
    
  613.     await act(() => {
    
  614.       renderer.update(<App text={'mount'} />);
    
  615.     });
    
  616. 
    
  617.     assertLog([
    
  618.       'useLayoutEffect unmount',
    
  619.       'useLayoutEffect mount',
    
  620.       'useEffect unmount',
    
  621.       'useEffect mount',
    
  622.     ]);
    
  623. 
    
  624.     await act(() => {
    
  625.       renderer.unmount();
    
  626.     });
    
  627. 
    
  628.     assertLog([
    
  629.       'componentWillUnmount',
    
  630.       'useLayoutEffect unmount',
    
  631.       'useEffect unmount',
    
  632.     ]);
    
  633.   });
    
  634. 
    
  635.   it('classes without componentDidMount and functions are double invoked together correctly', async () => {
    
  636.     class ClassChild extends React.PureComponent {
    
  637.       componentWillUnmount() {
    
  638.         Scheduler.log('componentWillUnmount');
    
  639.       }
    
  640. 
    
  641.       render() {
    
  642.         return this.props.text;
    
  643.       }
    
  644.     }
    
  645. 
    
  646.     function FunctionChild({text}) {
    
  647.       React.useEffect(() => {
    
  648.         Scheduler.log('useEffect mount');
    
  649.         return () => Scheduler.log('useEffect unmount');
    
  650.       });
    
  651.       React.useLayoutEffect(() => {
    
  652.         Scheduler.log('useLayoutEffect mount');
    
  653.         return () => Scheduler.log('useLayoutEffect unmount');
    
  654.       });
    
  655.       return text;
    
  656.     }
    
  657. 
    
  658.     function App({text}) {
    
  659.       return (
    
  660.         <>
    
  661.           <ClassChild text={text} />
    
  662.           <FunctionChild text={text} />
    
  663.         </>
    
  664.       );
    
  665.     }
    
  666. 
    
  667.     let renderer;
    
  668.     await act(() => {
    
  669.       renderer = ReactTestRenderer.create(<App text={'mount'} />, {
    
  670.         unstable_isConcurrent: true,
    
  671.       });
    
  672.     });
    
  673. 
    
  674.     if (supportsDoubleInvokeEffects()) {
    
  675.       assertLog([
    
  676.         'useLayoutEffect mount',
    
  677.         'useEffect mount',
    
  678.         'componentWillUnmount',
    
  679.         'useLayoutEffect unmount',
    
  680.         'useEffect unmount',
    
  681.         'useLayoutEffect mount',
    
  682.         'useEffect mount',
    
  683.       ]);
    
  684.     } else {
    
  685.       assertLog(['useLayoutEffect mount', 'useEffect mount']);
    
  686.     }
    
  687. 
    
  688.     await act(() => {
    
  689.       renderer.update(<App text={'mount'} />);
    
  690.     });
    
  691. 
    
  692.     assertLog([
    
  693.       'useLayoutEffect unmount',
    
  694.       'useLayoutEffect mount',
    
  695.       'useEffect unmount',
    
  696.       'useEffect mount',
    
  697.     ]);
    
  698. 
    
  699.     await act(() => {
    
  700.       renderer.unmount();
    
  701.     });
    
  702. 
    
  703.     assertLog([
    
  704.       'componentWillUnmount',
    
  705.       'useLayoutEffect unmount',
    
  706.       'useEffect unmount',
    
  707.     ]);
    
  708.   });
    
  709. });