Repository: facebook/react
Pull request: Delete test-utils implementation of `act`

Since it's dev-only now, we can use the one provided by the reconciler.

Changed files:
filename: packages/react-dom/src/client/ReactDOM.js
patch: @@ -28,8 +28,8 @@ import {
   flushSync,
   flushControlled,
   injectIntoDevTools,
-  flushPassiveEffects,
   IsThisRendererActing,
+  act,
   attemptSynchronousHydration,
   attemptDiscreteHydration,
   attemptContinuousHydration,
@@ -155,18 +155,18 @@ function renderSubtreeIntoContainer(
 }
 
 const Internals = {
-  // Keep in sync with ReactTestUtils.js, and ReactTestUtilsAct.js.
+  // Keep in sync with ReactTestUtils.js.
   // This is an array for better minification.
   Events: [
     getInstanceFromNode,
     getNodeFromInstance,
     getFiberCurrentPropsFromNode,
     enqueueStateRestore,
     restoreStateIfNeeded,
-    flushPassiveEffects,
-    // TODO: This is related to `act`, not events. Move to separate key?
-    IsThisRendererActing,
   ],
+  act,
+  // TODO: Temporary. Only used by our internal version of `act. Will remove.
+  IsThisRendererActing,
 };
 
 export {

filename: packages/react-dom/src/test-utils/ReactTestUtils.js
patch: @@ -18,25 +18,24 @@ import {
 import {SyntheticEvent} from '../events/SyntheticEvent';
 import invariant from 'shared/invariant';
 import {ELEMENT_NODE} from '../shared/HTMLNodeType';
-import {act} from './ReactTestUtilsPublicAct';
 import {unstable_concurrentAct} from './ReactTestUtilsInternalAct';
 import {
   rethrowCaughtError,
   invokeGuardedCallbackAndCatchFirstError,
 } from 'shared/ReactErrorUtils';
 import isArray from 'shared/isArray';
 
-// Keep in sync with ReactDOM.js, and ReactTestUtilsAct.js:
-const EventInternals =
-  ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
+// Keep in sync with ReactDOM.js:
+const SecretInternals =
+  ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+const EventInternals = SecretInternals.Events;
 const getInstanceFromNode = EventInternals[0];
 const getNodeFromInstance = EventInternals[1];
 const getFiberCurrentPropsFromNode = EventInternals[2];
 const enqueueStateRestore = EventInternals[3];
 const restoreStateIfNeeded = EventInternals[4];
-// const flushPassiveEffects = EventInternals[5];
-// TODO: This is related to `act`, not events. Move to separate key?
-// const IsThisRendererActing = EventInternals[6];
+
+const act = SecretInternals.act;
 
 function Event(suffix) {}
 

filename: packages/react-dom/src/test-utils/ReactTestUtilsInternalAct.js
patch: @@ -14,16 +14,9 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
 import enqueueTask from 'shared/enqueueTask';
 import * as Scheduler from 'scheduler';
 
-// Keep in sync with ReactDOM.js, and ReactTestUtils.js:
-const EventInternals =
-  ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
-// const getInstanceFromNode = EventInternals[0];
-// const getNodeFromInstance = EventInternals[1];
-// const getFiberCurrentPropsFromNode = EventInternals[2];
-// const enqueueStateRestore = EventInternals[3];
-// const restoreStateIfNeeded = EventInternals[4];
-// const flushPassiveEffects = EventInternals[5];
-const IsThisRendererActing = EventInternals[6];
+const SecretInternals =
+  ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+const IsThisRendererActing = SecretInternals.IsThisRendererActing;
 
 const batchedUpdates = ReactDOM.unstable_batchedUpdates;
 

filename: packages/react-dom/src/test-utils/ReactTestUtilsPublicAct.js
patch: @@ -1,214 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-
-import type {Thenable} from 'shared/ReactTypes';
-
-import * as ReactDOM from 'react-dom';
-import ReactSharedInternals from 'shared/ReactSharedInternals';
-import enqueueTask from 'shared/enqueueTask';
-import * as Scheduler from 'scheduler';
-import invariant from 'shared/invariant';
-
-// Keep in sync with ReactDOM.js, and ReactTestUtils.js:
-const EventInternals =
-  ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
-// const getInstanceFromNode = EventInternals[0];
-// const getNodeFromInstance = EventInternals[1];
-// const getFiberCurrentPropsFromNode = EventInternals[2];
-// const enqueueStateRestore = EventInternals[3];
-// const restoreStateIfNeeded = EventInternals[4];
-const flushPassiveEffects = EventInternals[5];
-const IsThisRendererActing = EventInternals[6];
-
-const batchedUpdates = ReactDOM.unstable_batchedUpdates;
-
-const {IsSomeRendererActing} = ReactSharedInternals;
-
-// This is the public version of `ReactTestUtils.act`. It is implemented in
-// "userspace" (i.e. not the reconciler), so that it doesn't add to the
-// production bundle size.
-// TODO: Remove this implementation of `act` in favor of the one exported by
-// the reconciler. To do this, we must first drop support for `act` in
-// production mode.
-
-// TODO: Remove support for the mock scheduler build, which was only added for
-// the purposes of internal testing. Internal tests should use
-// `unstable_concurrentAct` instead.
-const isSchedulerMocked =
-  typeof Scheduler.unstable_flushAllWithoutAsserting === 'function';
-const flushWork =
-  Scheduler.unstable_flushAllWithoutAsserting ||
-  function() {
-    let didFlushWork = false;
-    while (flushPassiveEffects()) {
-      didFlushWork = true;
-    }
-
-    return didFlushWork;
-  };
-
-function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) {
-  try {
-    flushWork();
-    enqueueTask(() => {
-      if (flushWork()) {
-        flushWorkAndMicroTasks(onDone);
-      } else {
-        onDone();
-      }
-    });
-  } catch (err) {
-    onDone(err);
-  }
-}
-
-// we track the 'depth' of the act() calls with this counter,
-// so we can tell if any async act() calls try to run in parallel.
-
-let actingUpdatesScopeDepth = 0;
-
-export function act(callback: () => Thenable<mixed>): Thenable<void> {
-  if (!__DEV__) {
-    invariant(
-      false,
-      'act(...) is not supported in production builds of React.',
-    );
-  }
-  const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
-  actingUpdatesScopeDepth++;
-
-  const previousIsSomeRendererActing = IsSomeRendererActing.current;
-  const previousIsThisRendererActing = IsThisRendererActing.current;
-  IsSomeRendererActing.current = true;
-  IsThisRendererActing.current = true;
-
-  function onDone() {
-    actingUpdatesScopeDepth--;
-    IsSomeRendererActing.current = previousIsSomeRendererActing;
-    IsThisRendererActing.current = previousIsThisRendererActing;
-    if (__DEV__) {
-      if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
-        // if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
-        console.error(
-          'You seem to have overlapping act() calls, this is not supported. ' +
-            'Be sure to await previous act() calls before making a new one. ',
-        );
-      }
-    }
-  }
-
-  let result;
-  try {
-    result = batchedUpdates(callback);
-  } catch (error) {
-    // on sync errors, we still want to 'cleanup' and decrement actingUpdatesScopeDepth
-    onDone();
-    throw error;
-  }
-
-  if (
-    result !== null &&
-    typeof result === 'object' &&
-    typeof result.then === 'function'
-  ) {
-    // setup a boolean that gets set to true only
-    // once this act() call is await-ed
-    let called = false;
-    if (__DEV__) {
-      if (typeof Promise !== 'undefined') {
-        //eslint-disable-next-line no-undef
-        Promise.resolve()
-          .then(() => {})
-          .then(() => {
-            if (called === false) {
-              console.error(
-                'You called act(async () => ...) without await. ' +
-                  'This could lead to unexpected testing behaviour, interleaving multiple act ' +
-                  'calls and mixing their scopes. You should - await act(async () => ...);',
-              );
-            }
-          });
-      }
-    }
-
-    // in the async case, the returned thenable runs the callback, flushes
-    // effects and  microtasks in a loop until flushPassiveEffects() === false,
-    // and cleans up
-    return {
-      then(resolve, reject) {
-        called = true;
-        result.then(
-          () => {
-            if (
-              actingUpdatesScopeDepth > 1 ||
-              (isSchedulerMocked === true &&
-                previousIsSomeRendererActing === true)
-            ) {
-              onDone();
-              resolve();
-              return;
-            }
-            // we're about to exit the act() scope,
-            // now's the time to flush tasks/effects
-            flushWorkAndMicroTasks((err: ?Error) => {
-              onDone();
-              if (err) {
-                reject(err);
-              } else {
-                resolve();
-              }
-            });
-          },
-          err => {
-            onDone();
-            reject(err);
-          },
-        );
-      },
-    };
-  } else {
-    if (__DEV__) {
-      if (result !== undefined) {
-        console.error(
-          'The callback passed to act(...) function ' +
-            'must return undefined, or a Promise. You returned %s',
-          result,
-        );
-      }
-    }
-
-    // flush effects until none remain, and cleanup
-    try {
-      if (
-        actingUpdatesScopeDepth === 1 &&
-        (isSchedulerMocked === false || previousIsSomeRendererActing === false)
-      ) {
-        // we're about to exit the act() scope,
-        // now's the time to flush effects
-        flushWork();
-      }
-      onDone();
-    } catch (err) {
-      onDone();
-      throw err;
-    }
-
-    // in the sync case, the returned thenable only warns *if* await-ed
-    return {
-      then(resolve) {
-        if (__DEV__) {
-          console.error(
-            'Do not await the result of calling act(...) with sync logic, it is not a Promise.',
-          );
-        }
-        resolve();
-      },
-    };
-  }
-}