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. const React = require('react');
    
  14. const {startTransition, useDeferredValue} = React;
    
  15. const ReactNoop = require('react-noop-renderer');
    
  16. const {
    
  17.   waitFor,
    
  18.   waitForAll,
    
  19.   waitForPaint,
    
  20.   waitForThrow,
    
  21.   assertLog,
    
  22. } = require('internal-test-utils');
    
  23. const act = require('internal-test-utils').act;
    
  24. const Scheduler = require('scheduler/unstable_mock');
    
  25. 
    
  26. describe('ReactInternalTestUtils', () => {
    
  27.   test('waitFor', async () => {
    
  28.     const Yield = ({id}) => {
    
  29.       Scheduler.log(id);
    
  30.       return id;
    
  31.     };
    
  32. 
    
  33.     const root = ReactNoop.createRoot();
    
  34.     startTransition(() => {
    
  35.       root.render(
    
  36.         <div>
    
  37.           <Yield id="foo" />
    
  38.           <Yield id="bar" />
    
  39.           <Yield id="baz" />
    
  40.         </div>
    
  41.       );
    
  42.     });
    
  43. 
    
  44.     await waitFor(['foo', 'bar']);
    
  45.     expect(root).toMatchRenderedOutput(null);
    
  46.     await waitFor(['baz']);
    
  47.     expect(root).toMatchRenderedOutput(null);
    
  48.     await waitForAll([]);
    
  49.     expect(root).toMatchRenderedOutput(<div>foobarbaz</div>);
    
  50.   });
    
  51. 
    
  52.   test('waitForAll', async () => {
    
  53.     const Yield = ({id}) => {
    
  54.       Scheduler.log(id);
    
  55.       return id;
    
  56.     };
    
  57. 
    
  58.     const root = ReactNoop.createRoot();
    
  59.     startTransition(() => {
    
  60.       root.render(
    
  61.         <div>
    
  62.           <Yield id="foo" />
    
  63.           <Yield id="bar" />
    
  64.           <Yield id="baz" />
    
  65.         </div>
    
  66.       );
    
  67.     });
    
  68. 
    
  69.     await waitForAll(['foo', 'bar', 'baz']);
    
  70.     expect(root).toMatchRenderedOutput(<div>foobarbaz</div>);
    
  71.   });
    
  72. 
    
  73.   test('waitForThrow', async () => {
    
  74.     const Yield = ({id}) => {
    
  75.       Scheduler.log(id);
    
  76.       return id;
    
  77.     };
    
  78. 
    
  79.     function BadRender() {
    
  80.       throw new Error('Oh no!');
    
  81.     }
    
  82. 
    
  83.     function App() {
    
  84.       return (
    
  85.         <div>
    
  86.           <Yield id="A" />
    
  87.           <Yield id="B" />
    
  88.           <BadRender />
    
  89.           <Yield id="C" />
    
  90.           <Yield id="D" />
    
  91.         </div>
    
  92.       );
    
  93.     }
    
  94. 
    
  95.     const root = ReactNoop.createRoot();
    
  96.     root.render(<App />);
    
  97. 
    
  98.     await waitForThrow('Oh no!');
    
  99.     assertLog([
    
  100.       'A',
    
  101.       'B',
    
  102.       // React will try one more time before giving up.
    
  103.       'A',
    
  104.       'B',
    
  105.     ]);
    
  106.   });
    
  107. 
    
  108.   test('waitForPaint', async () => {
    
  109.     function App({prop}) {
    
  110.       const deferred = useDeferredValue(prop);
    
  111.       const text = `Urgent: ${prop}, Deferred: ${deferred}`;
    
  112.       Scheduler.log(text);
    
  113.       return text;
    
  114.     }
    
  115. 
    
  116.     const root = ReactNoop.createRoot();
    
  117.     root.render(<App prop="A" />);
    
  118. 
    
  119.     await waitForAll(['Urgent: A, Deferred: A']);
    
  120.     expect(root).toMatchRenderedOutput('Urgent: A, Deferred: A');
    
  121. 
    
  122.     // This update will result in two separate paints: an urgent one, and a
    
  123.     // deferred one.
    
  124.     root.render(<App prop="B" />);
    
  125.     // Urgent paint
    
  126.     await waitForPaint(['Urgent: B, Deferred: A']);
    
  127.     expect(root).toMatchRenderedOutput('Urgent: B, Deferred: A');
    
  128. 
    
  129.     // Deferred paint
    
  130.     await waitForPaint(['Urgent: B, Deferred: B']);
    
  131.     expect(root).toMatchRenderedOutput('Urgent: B, Deferred: B');
    
  132.   });
    
  133. 
    
  134.   test('assertLog', async () => {
    
  135.     const Yield = ({id}) => {
    
  136.       Scheduler.log(id);
    
  137.       return id;
    
  138.     };
    
  139. 
    
  140.     function App() {
    
  141.       return (
    
  142.         <div>
    
  143.           <Yield id="A" />
    
  144.           <Yield id="B" />
    
  145.           <Yield id="C" />
    
  146.         </div>
    
  147.       );
    
  148.     }
    
  149. 
    
  150.     const root = ReactNoop.createRoot();
    
  151.     await act(() => {
    
  152.       root.render(<App />);
    
  153.     });
    
  154.     assertLog(['A', 'B', 'C']);
    
  155.   });
    
  156. });