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.  * @jest-environment node
    
  9.  */
    
  10. 
    
  11. 'use strict';
    
  12. 
    
  13. let React;
    
  14. let ReactTestRenderer;
    
  15. let Scheduler;
    
  16. let waitForAll;
    
  17. let waitFor;
    
  18. 
    
  19. describe('ReactTestRendererAsync', () => {
    
  20.   beforeEach(() => {
    
  21.     jest.resetModules();
    
  22. 
    
  23.     React = require('react');
    
  24.     ReactTestRenderer = require('react-test-renderer');
    
  25.     Scheduler = require('scheduler');
    
  26. 
    
  27.     const InternalTestUtils = require('internal-test-utils');
    
  28.     waitForAll = InternalTestUtils.waitForAll;
    
  29.     waitFor = InternalTestUtils.waitFor;
    
  30.   });
    
  31. 
    
  32.   it('flushAll flushes all work', async () => {
    
  33.     function Foo(props) {
    
  34.       return props.children;
    
  35.     }
    
  36.     const renderer = ReactTestRenderer.create(<Foo>Hi</Foo>, {
    
  37.       unstable_isConcurrent: true,
    
  38.     });
    
  39. 
    
  40.     // Before flushing, nothing has mounted.
    
  41.     expect(renderer.toJSON()).toEqual(null);
    
  42. 
    
  43.     // Flush initial mount.
    
  44.     await waitForAll([]);
    
  45.     expect(renderer.toJSON()).toEqual('Hi');
    
  46. 
    
  47.     // Update
    
  48.     renderer.update(<Foo>Bye</Foo>);
    
  49.     // Not yet updated.
    
  50.     expect(renderer.toJSON()).toEqual('Hi');
    
  51.     // Flush update.
    
  52.     await waitForAll([]);
    
  53.     expect(renderer.toJSON()).toEqual('Bye');
    
  54.   });
    
  55. 
    
  56.   it('flushAll returns array of yielded values', async () => {
    
  57.     function Child(props) {
    
  58.       Scheduler.log(props.children);
    
  59.       return props.children;
    
  60.     }
    
  61.     function Parent(props) {
    
  62.       return (
    
  63.         <>
    
  64.           <Child>{'A:' + props.step}</Child>
    
  65.           <Child>{'B:' + props.step}</Child>
    
  66.           <Child>{'C:' + props.step}</Child>
    
  67.         </>
    
  68.       );
    
  69.     }
    
  70.     const renderer = ReactTestRenderer.create(<Parent step={1} />, {
    
  71.       unstable_isConcurrent: true,
    
  72.     });
    
  73. 
    
  74.     await waitForAll(['A:1', 'B:1', 'C:1']);
    
  75.     expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']);
    
  76. 
    
  77.     renderer.update(<Parent step={2} />);
    
  78.     await waitForAll(['A:2', 'B:2', 'C:2']);
    
  79.     expect(renderer.toJSON()).toEqual(['A:2', 'B:2', 'C:2']);
    
  80.   });
    
  81. 
    
  82.   it('flushThrough flushes until the expected values is yielded', async () => {
    
  83.     function Child(props) {
    
  84.       Scheduler.log(props.children);
    
  85.       return props.children;
    
  86.     }
    
  87.     function Parent(props) {
    
  88.       return (
    
  89.         <>
    
  90.           <Child>{'A:' + props.step}</Child>
    
  91.           <Child>{'B:' + props.step}</Child>
    
  92.           <Child>{'C:' + props.step}</Child>
    
  93.         </>
    
  94.       );
    
  95.     }
    
  96. 
    
  97.     let renderer;
    
  98.     React.startTransition(() => {
    
  99.       renderer = ReactTestRenderer.create(<Parent step={1} />, {
    
  100.         unstable_isConcurrent: true,
    
  101.       });
    
  102.     });
    
  103. 
    
  104.     // Flush the first two siblings
    
  105.     await waitFor(['A:1', 'B:1']);
    
  106.     // Did not commit yet.
    
  107.     expect(renderer.toJSON()).toEqual(null);
    
  108. 
    
  109.     // Flush the remaining work
    
  110.     await waitForAll(['C:1']);
    
  111.     expect(renderer.toJSON()).toEqual(['A:1', 'B:1', 'C:1']);
    
  112.   });
    
  113. 
    
  114.   it('supports high priority interruptions', async () => {
    
  115.     function Child(props) {
    
  116.       Scheduler.log(props.children);
    
  117.       return props.children;
    
  118.     }
    
  119. 
    
  120.     class Example extends React.Component {
    
  121.       componentDidMount() {
    
  122.         expect(this.props.step).toEqual(2);
    
  123.       }
    
  124.       componentDidUpdate() {
    
  125.         throw Error('Unexpected update');
    
  126.       }
    
  127.       render() {
    
  128.         return (
    
  129.           <>
    
  130.             <Child>{'A:' + this.props.step}</Child>
    
  131.             <Child>{'B:' + this.props.step}</Child>
    
  132.           </>
    
  133.         );
    
  134.       }
    
  135.     }
    
  136. 
    
  137.     let renderer;
    
  138.     React.startTransition(() => {
    
  139.       renderer = ReactTestRenderer.create(<Example step={1} />, {
    
  140.         unstable_isConcurrent: true,
    
  141.       });
    
  142.     });
    
  143. 
    
  144.     // Flush the some of the changes, but don't commit
    
  145.     await waitFor(['A:1']);
    
  146.     expect(renderer.toJSON()).toEqual(null);
    
  147. 
    
  148.     // Interrupt with higher priority properties
    
  149.     renderer.unstable_flushSync(() => {
    
  150.       renderer.update(<Example step={2} />);
    
  151.     });
    
  152. 
    
  153.     // Only the higher priority properties have been committed
    
  154.     expect(renderer.toJSON()).toEqual(['A:2', 'B:2']);
    
  155.   });
    
  156. });