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 ReactDOM;
    
  14. let ReactDOMClient;
    
  15. let act;
    
  16. let waitForAll;
    
  17. 
    
  18. describe('ReactDOMHooks', () => {
    
  19.   let container;
    
  20. 
    
  21.   beforeEach(() => {
    
  22.     jest.resetModules();
    
  23. 
    
  24.     React = require('react');
    
  25.     ReactDOM = require('react-dom');
    
  26.     ReactDOMClient = require('react-dom/client');
    
  27.     act = require('internal-test-utils').act;
    
  28.     waitForAll = require('internal-test-utils').waitForAll;
    
  29. 
    
  30.     container = document.createElement('div');
    
  31.     document.body.appendChild(container);
    
  32.   });
    
  33. 
    
  34.   afterEach(() => {
    
  35.     document.body.removeChild(container);
    
  36.   });
    
  37. 
    
  38.   it('can ReactDOM.render() from useEffect', async () => {
    
  39.     const container2 = document.createElement('div');
    
  40.     const container3 = document.createElement('div');
    
  41. 
    
  42.     function Example1({n}) {
    
  43.       React.useEffect(() => {
    
  44.         ReactDOM.render(<Example2 n={n} />, container2);
    
  45.       });
    
  46.       return 1 * n;
    
  47.     }
    
  48. 
    
  49.     function Example2({n}) {
    
  50.       React.useEffect(() => {
    
  51.         ReactDOM.render(<Example3 n={n} />, container3);
    
  52.       });
    
  53.       return 2 * n;
    
  54.     }
    
  55. 
    
  56.     function Example3({n}) {
    
  57.       return 3 * n;
    
  58.     }
    
  59. 
    
  60.     ReactDOM.render(<Example1 n={1} />, container);
    
  61.     expect(container.textContent).toBe('1');
    
  62.     expect(container2.textContent).toBe('');
    
  63.     expect(container3.textContent).toBe('');
    
  64.     await waitForAll([]);
    
  65.     expect(container.textContent).toBe('1');
    
  66.     expect(container2.textContent).toBe('2');
    
  67.     expect(container3.textContent).toBe('3');
    
  68. 
    
  69.     ReactDOM.render(<Example1 n={2} />, container);
    
  70.     expect(container.textContent).toBe('2');
    
  71.     expect(container2.textContent).toBe('2'); // Not flushed yet
    
  72.     expect(container3.textContent).toBe('3'); // Not flushed yet
    
  73.     await waitForAll([]);
    
  74.     expect(container.textContent).toBe('2');
    
  75.     expect(container2.textContent).toBe('4');
    
  76.     expect(container3.textContent).toBe('6');
    
  77.   });
    
  78. 
    
  79.   it('should not bail out when an update is scheduled from within an event handler', () => {
    
  80.     const {createRef, useCallback, useState} = React;
    
  81. 
    
  82.     const Example = ({inputRef, labelRef}) => {
    
  83.       const [text, setText] = useState('');
    
  84.       const handleInput = useCallback(event => {
    
  85.         setText(event.target.value);
    
  86.       });
    
  87. 
    
  88.       return (
    
  89.         <>
    
  90.           <input ref={inputRef} onInput={handleInput} />
    
  91.           <label ref={labelRef}>{text}</label>
    
  92.         </>
    
  93.       );
    
  94.     };
    
  95. 
    
  96.     const inputRef = createRef();
    
  97.     const labelRef = createRef();
    
  98. 
    
  99.     ReactDOM.render(
    
  100.       <Example inputRef={inputRef} labelRef={labelRef} />,
    
  101.       container,
    
  102.     );
    
  103. 
    
  104.     inputRef.current.value = 'abc';
    
  105.     inputRef.current.dispatchEvent(
    
  106.       new Event('input', {bubbles: true, cancelable: true}),
    
  107.     );
    
  108. 
    
  109.     expect(labelRef.current.innerHTML).toBe('abc');
    
  110.   });
    
  111. 
    
  112.   it('should not bail out when an update is scheduled from within an event handler in Concurrent Mode', async () => {
    
  113.     const {createRef, useCallback, useState} = React;
    
  114. 
    
  115.     const Example = ({inputRef, labelRef}) => {
    
  116.       const [text, setText] = useState('');
    
  117.       const handleInput = useCallback(event => {
    
  118.         setText(event.target.value);
    
  119.       });
    
  120. 
    
  121.       return (
    
  122.         <>
    
  123.           <input ref={inputRef} onInput={handleInput} />
    
  124.           <label ref={labelRef}>{text}</label>
    
  125.         </>
    
  126.       );
    
  127.     };
    
  128. 
    
  129.     const inputRef = createRef();
    
  130.     const labelRef = createRef();
    
  131. 
    
  132.     const root = ReactDOMClient.createRoot(container);
    
  133.     root.render(<Example inputRef={inputRef} labelRef={labelRef} />);
    
  134. 
    
  135.     await waitForAll([]);
    
  136. 
    
  137.     inputRef.current.value = 'abc';
    
  138.     await act(() => {
    
  139.       inputRef.current.dispatchEvent(
    
  140.         new Event('input', {
    
  141.           bubbles: true,
    
  142.           cancelable: true,
    
  143.         }),
    
  144.       );
    
  145.     });
    
  146. 
    
  147.     expect(labelRef.current.innerHTML).toBe('abc');
    
  148.   });
    
  149. });