@samitouri / QOS-React / commits / 422e0bb360

Delete test-utils implementation of `act` (#21703)

* Delete test-utils implementation of `act` Since it's dev-only now, we can use the one provided by the reconciler. * Move act related stuff out of EventInternals

Andrew Clark committed Jun 22, 2021 at 17:21 UTC 422e0bb3604dd7d3f6158df87b05932a43c89017
4 files changed +14 -236
packages/react-dom/src/client/ReactDOM.js
+5 -5
@@ -28,8 +28,8 @@ import {
28 flushSync,
29 flushControlled,
30 injectIntoDevTools,
31 - flushPassiveEffects,
31 IsThisRendererActing,
32 + act,
33 attemptSynchronousHydration,
34 attemptDiscreteHydration,
35 attemptContinuousHydration,
@@ -155,7 +155,7 @@ function renderSubtreeIntoContainer(
155 }
156
157 const Internals = {
158 - // Keep in sync with ReactTestUtils.js, and ReactTestUtilsAct.js.
158 + // Keep in sync with ReactTestUtils.js.
159 // This is an array for better minification.
160 Events: [
161 getInstanceFromNode,
@@ -163,10 +163,10 @@ const Internals = {
163 getFiberCurrentPropsFromNode,
164 enqueueStateRestore,
165 restoreStateIfNeeded,
166 - flushPassiveEffects,
167 - // TODO: This is related to `act`, not events. Move to separate key?
168 - IsThisRendererActing,
166 ],
167 + act,
168 + // TODO: Temporary. Only used by our internal version of `act. Will remove.
169 + IsThisRendererActing,
170 };
171
172 export {
packages/react-dom/src/test-utils/ReactTestUtils.js
+6 -7
@@ -18,7 +18,6 @@ import {
18 import {SyntheticEvent} from '../events/SyntheticEvent';
19 import invariant from 'shared/invariant';
20 import {ELEMENT_NODE} from '../shared/HTMLNodeType';
21 -import {act} from './ReactTestUtilsPublicAct';
21 import {unstable_concurrentAct} from './ReactTestUtilsInternalAct';
22 import {
23 rethrowCaughtError,
@@ -26,17 +25,17 @@ import {
25 } from 'shared/ReactErrorUtils';
26 import isArray from 'shared/isArray';
27
29 -// Keep in sync with ReactDOM.js, and ReactTestUtilsAct.js:
30 -const EventInternals =
31 - ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
28 +// Keep in sync with ReactDOM.js:
29 +const SecretInternals =
30 + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
31 +const EventInternals = SecretInternals.Events;
32 const getInstanceFromNode = EventInternals[0];
33 const getNodeFromInstance = EventInternals[1];
34 const getFiberCurrentPropsFromNode = EventInternals[2];
35 const enqueueStateRestore = EventInternals[3];
36 const restoreStateIfNeeded = EventInternals[4];
37 -// const flushPassiveEffects = EventInternals[5];
38 -// TODO: This is related to `act`, not events. Move to separate key?
39 -// const IsThisRendererActing = EventInternals[6];
37 +
38 +const act = SecretInternals.act;
39
40 function Event(suffix) {}
41
packages/react-dom/src/test-utils/ReactTestUtilsInternalAct.js
+3 -10
@@ -14,16 +14,9 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
14 import enqueueTask from 'shared/enqueueTask';
15 import * as Scheduler from 'scheduler';
16
17 -// Keep in sync with ReactDOM.js, and ReactTestUtils.js:
18 -const EventInternals =
19 - ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
20 -// const getInstanceFromNode = EventInternals[0];
21 -// const getNodeFromInstance = EventInternals[1];
22 -// const getFiberCurrentPropsFromNode = EventInternals[2];
23 -// const enqueueStateRestore = EventInternals[3];
24 -// const restoreStateIfNeeded = EventInternals[4];
25 -// const flushPassiveEffects = EventInternals[5];
26 -const IsThisRendererActing = EventInternals[6];
17 +const SecretInternals =
18 + ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
19 +const IsThisRendererActing = SecretInternals.IsThisRendererActing;
20
21 const batchedUpdates = ReactDOM.unstable_batchedUpdates;
22
packages/react-dom/src/test-utils/ReactTestUtilsPublicAct.js deleted
-214
@@ -1,214 +0,0 @@
1 -/**
2 - * Copyright (c) Facebook, Inc. and its 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
8 - */
9 -
10 -import type {Thenable} from 'shared/ReactTypes';
11 -
12 -import * as ReactDOM from 'react-dom';
13 -import ReactSharedInternals from 'shared/ReactSharedInternals';
14 -import enqueueTask from 'shared/enqueueTask';
15 -import * as Scheduler from 'scheduler';
16 -import invariant from 'shared/invariant';
17 -
18 -// Keep in sync with ReactDOM.js, and ReactTestUtils.js:
19 -const EventInternals =
20 - ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Events;
21 -// const getInstanceFromNode = EventInternals[0];
22 -// const getNodeFromInstance = EventInternals[1];
23 -// const getFiberCurrentPropsFromNode = EventInternals[2];
24 -// const enqueueStateRestore = EventInternals[3];
25 -// const restoreStateIfNeeded = EventInternals[4];
26 -const flushPassiveEffects = EventInternals[5];
27 -const IsThisRendererActing = EventInternals[6];
28 -
29 -const batchedUpdates = ReactDOM.unstable_batchedUpdates;
30 -
31 -const {IsSomeRendererActing} = ReactSharedInternals;
32 -
33 -// This is the public version of `ReactTestUtils.act`. It is implemented in
34 -// "userspace" (i.e. not the reconciler), so that it doesn't add to the
35 -// production bundle size.
36 -// TODO: Remove this implementation of `act` in favor of the one exported by
37 -// the reconciler. To do this, we must first drop support for `act` in
38 -// production mode.
39 -
40 -// TODO: Remove support for the mock scheduler build, which was only added for
41 -// the purposes of internal testing. Internal tests should use
42 -// `unstable_concurrentAct` instead.
43 -const isSchedulerMocked =
44 - typeof Scheduler.unstable_flushAllWithoutAsserting === 'function';
45 -const flushWork =
46 - Scheduler.unstable_flushAllWithoutAsserting ||
47 - function() {
48 - let didFlushWork = false;
49 - while (flushPassiveEffects()) {
50 - didFlushWork = true;
51 - }
52 -
53 - return didFlushWork;
54 - };
55 -
56 -function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) {
57 - try {
58 - flushWork();
59 - enqueueTask(() => {
60 - if (flushWork()) {
61 - flushWorkAndMicroTasks(onDone);
62 - } else {
63 - onDone();
64 - }
65 - });
66 - } catch (err) {
67 - onDone(err);
68 - }
69 -}
70 -
71 -// we track the 'depth' of the act() calls with this counter,
72 -// so we can tell if any async act() calls try to run in parallel.
73 -
74 -let actingUpdatesScopeDepth = 0;
75 -
76 -export function act(callback: () => Thenable<mixed>): Thenable<void> {
77 - if (!__DEV__) {
78 - invariant(
79 - false,
80 - 'act(...) is not supported in production builds of React.',
81 - );
82 - }
83 - const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
84 - actingUpdatesScopeDepth++;
85 -
86 - const previousIsSomeRendererActing = IsSomeRendererActing.current;
87 - const previousIsThisRendererActing = IsThisRendererActing.current;
88 - IsSomeRendererActing.current = true;
89 - IsThisRendererActing.current = true;
90 -
91 - function onDone() {
92 - actingUpdatesScopeDepth--;
93 - IsSomeRendererActing.current = previousIsSomeRendererActing;
94 - IsThisRendererActing.current = previousIsThisRendererActing;
95 - if (__DEV__) {
96 - if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
97 - // if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
98 - console.error(
99 - 'You seem to have overlapping act() calls, this is not supported. ' +
100 - 'Be sure to await previous act() calls before making a new one. ',
101 - );
102 - }
103 - }
104 - }
105 -
106 - let result;
107 - try {
108 - result = batchedUpdates(callback);
109 - } catch (error) {
110 - // on sync errors, we still want to 'cleanup' and decrement actingUpdatesScopeDepth
111 - onDone();
112 - throw error;
113 - }
114 -
115 - if (
116 - result !== null &&
117 - typeof result === 'object' &&
118 - typeof result.then === 'function'
119 - ) {
120 - // setup a boolean that gets set to true only
121 - // once this act() call is await-ed
122 - let called = false;
123 - if (__DEV__) {
124 - if (typeof Promise !== 'undefined') {
125 - //eslint-disable-next-line no-undef
126 - Promise.resolve()
127 - .then(() => {})
128 - .then(() => {
129 - if (called === false) {
130 - console.error(
131 - 'You called act(async () => ...) without await. ' +
132 - 'This could lead to unexpected testing behaviour, interleaving multiple act ' +
133 - 'calls and mixing their scopes. You should - await act(async () => ...);',
134 - );
135 - }
136 - });
137 - }
138 - }
139 -
140 - // in the async case, the returned thenable runs the callback, flushes
141 - // effects and microtasks in a loop until flushPassiveEffects() === false,
142 - // and cleans up
143 - return {
144 - then(resolve, reject) {
145 - called = true;
146 - result.then(
147 - () => {
148 - if (
149 - actingUpdatesScopeDepth > 1 ||
150 - (isSchedulerMocked === true &&
151 - previousIsSomeRendererActing === true)
152 - ) {
153 - onDone();
154 - resolve();
155 - return;
156 - }
157 - // we're about to exit the act() scope,
158 - // now's the time to flush tasks/effects
159 - flushWorkAndMicroTasks((err: ?Error) => {
160 - onDone();
161 - if (err) {
162 - reject(err);
163 - } else {
164 - resolve();
165 - }
166 - });
167 - },
168 - err => {
169 - onDone();
170 - reject(err);
171 - },
172 - );
173 - },
174 - };
175 - } else {
176 - if (__DEV__) {
177 - if (result !== undefined) {
178 - console.error(
179 - 'The callback passed to act(...) function ' +
180 - 'must return undefined, or a Promise. You returned %s',
181 - result,
182 - );
183 - }
184 - }
185 -
186 - // flush effects until none remain, and cleanup
187 - try {
188 - if (
189 - actingUpdatesScopeDepth === 1 &&
190 - (isSchedulerMocked === false || previousIsSomeRendererActing === false)
191 - ) {
192 - // we're about to exit the act() scope,
193 - // now's the time to flush effects
194 - flushWork();
195 - }
196 - onDone();
197 - } catch (err) {
198 - onDone();
199 - throw err;
200 - }
201 -
202 - // in the sync case, the returned thenable only warns *if* await-ed
203 - return {
204 - then(resolve) {
205 - if (__DEV__) {
206 - console.error(
207 - 'Do not await the result of calling act(...) with sync logic, it is not a Promise.',
208 - );
209 - }
210 - resolve();
211 - },
212 - };
213 - }
214 -}