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.  * @flow strict
    
  8.  */
    
  9. 
    
  10. // This version of `act` is only used by our tests. Unlike the public version
    
  11. // of `act`, it's designed to work identically in both production and
    
  12. // development. It may have slightly different behavior from the public
    
  13. // version, too, since our constraints in our test suite are not the same as
    
  14. // those of developers using React — we're testing React itself, as opposed to
    
  15. // building an app with React.
    
  16. 
    
  17. import type {Thenable} from 'shared/ReactTypes';
    
  18. 
    
  19. import * as Scheduler from 'scheduler/unstable_mock';
    
  20. 
    
  21. import enqueueTask from './enqueueTask';
    
  22. 
    
  23. let actingUpdatesScopeDepth: number = 0;
    
  24. 
    
  25. async function waitForMicrotasks() {
    
  26.   return new Promise(resolve => {
    
  27.     enqueueTask(() => resolve());
    
  28.   });
    
  29. }
    
  30. 
    
  31. export async function act<T>(scope: () => Thenable<T>): Thenable<T> {
    
  32.   if (Scheduler.unstable_flushUntilNextPaint === undefined) {
    
  33.     throw Error(
    
  34.       'This version of `act` requires a special mock build of Scheduler.',
    
  35.     );
    
  36.   }
    
  37. 
    
  38.   // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
    
  39.   if (!jest.isMockFunction(setTimeout)) {
    
  40.     throw Error(
    
  41.       "This version of `act` requires Jest's timer mocks " +
    
  42.         '(i.e. jest.useFakeTimers).',
    
  43.     );
    
  44.   }
    
  45. 
    
  46.   const previousIsActEnvironment = global.IS_REACT_ACT_ENVIRONMENT;
    
  47.   const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
    
  48.   actingUpdatesScopeDepth++;
    
  49.   if (actingUpdatesScopeDepth === 1) {
    
  50.     // Because this is not the "real" `act`, we set this to `false` so React
    
  51.     // knows not to fire `act` warnings.
    
  52.     global.IS_REACT_ACT_ENVIRONMENT = false;
    
  53.   }
    
  54. 
    
  55.   // Create the error object before doing any async work, to get a better
    
  56.   // stack trace.
    
  57.   const error = new Error();
    
  58.   Error.captureStackTrace(error, act);
    
  59. 
    
  60.   // Call the provided scope function after an async gap. This is an extra
    
  61.   // precaution to ensure that our tests do not accidentally rely on the act
    
  62.   // scope adding work to the queue synchronously. We don't do this in the
    
  63.   // public version of `act`, though we maybe should in the future.
    
  64.   await waitForMicrotasks();
    
  65. 
    
  66.   try {
    
  67.     const result = await scope();
    
  68. 
    
  69.     do {
    
  70.       // Wait until end of current task/microtask.
    
  71.       await waitForMicrotasks();
    
  72. 
    
  73.       // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
    
  74.       if (jest.isEnvironmentTornDown()) {
    
  75.         error.message =
    
  76.           'The Jest environment was torn down before `act` completed. This ' +
    
  77.           'probably means you forgot to `await` an `act` call.';
    
  78.         throw error;
    
  79.       }
    
  80. 
    
  81.       if (!Scheduler.unstable_hasPendingWork()) {
    
  82.         // $FlowFixMe[cannot-resolve-name]: Flow doesn't know about global Jest object
    
  83.         const j = jest;
    
  84.         if (j.getTimerCount() > 0) {
    
  85.           // There's a pending timer. Flush it now. We only do this in order to
    
  86.           // force Suspense fallbacks to display; the fact that it's a timer
    
  87.           // is an implementation detail. If there are other timers scheduled,
    
  88.           // those will also fire now, too, which is not ideal. (The public
    
  89.           // version of `act` doesn't do this.) For this reason, we should try
    
  90.           // to avoid using timers in our internal tests.
    
  91.           j.runOnlyPendingTimers();
    
  92.           // If a committing a fallback triggers another update, it might not
    
  93.           // get scheduled until a microtask. So wait one more time.
    
  94.           await waitForMicrotasks();
    
  95.         }
    
  96.         if (Scheduler.unstable_hasPendingWork()) {
    
  97.           // Committing a fallback scheduled additional work. Continue flushing.
    
  98.         } else {
    
  99.           // There's no pending work, even after both the microtask queue
    
  100.           // and the timer queue are empty. Stop flushing.
    
  101.           break;
    
  102.         }
    
  103.       }
    
  104.       // flushUntilNextPaint stops when React yields execution. Allow microtasks
    
  105.       // queue to flush before continuing.
    
  106.       Scheduler.unstable_flushUntilNextPaint();
    
  107.     } while (true);
    
  108. 
    
  109.     return result;
    
  110.   } finally {
    
  111.     const depth = actingUpdatesScopeDepth;
    
  112.     if (depth === 1) {
    
  113.       global.IS_REACT_ACT_ENVIRONMENT = previousIsActEnvironment;
    
  114.     }
    
  115.     actingUpdatesScopeDepth = depth - 1;
    
  116. 
    
  117.     if (actingUpdatesScopeDepth !== previousActingUpdatesScopeDepth) {
    
  118.       // if it's _less than_ previousActingUpdatesScopeDepth, then we can
    
  119.       // assume the 'other' one has warned
    
  120.       Scheduler.unstable_clearLog();
    
  121.       error.message =
    
  122.         'You seem to have overlapping act() calls, this is not supported. ' +
    
  123.         'Be sure to await previous act() calls before making a new one. ';
    
  124.       throw error;
    
  125.     }
    
  126.   }
    
  127. }