diff --git a/packages/jest-react/src/JestReact.js b/packages/jest-react/src/JestReact.js index 1f26cbee3a328..b4688f1ff980a 100644 --- a/packages/jest-react/src/JestReact.js +++ b/packages/jest-react/src/JestReact.js @@ -10,6 +10,8 @@ import {REACT_ELEMENT_TYPE, REACT_FRAGMENT_TYPE} from 'shared/ReactSymbols'; import invariant from 'shared/invariant'; import isArray from 'shared/isArray'; +export {act} from './internalAct'; + function captureAssertion(fn) { // Trick to use a Jest matcher inside another Jest matcher. `fn` contains an // assertion; if it throws, we capture the error and return it, so the stack diff --git a/packages/react-dom/src/test-utils/ReactTestUtilsInternalAct.js b/packages/jest-react/src/internalAct.js similarity index 79% rename from packages/react-dom/src/test-utils/ReactTestUtilsInternalAct.js rename to packages/jest-react/src/internalAct.js index 6afe4af8aa49e..486d84c31f64a 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtilsInternalAct.js +++ b/packages/jest-react/src/internalAct.js @@ -4,36 +4,27 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @flow + * @flow strict */ -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'; - -const SecretInternals = - ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; -const IsThisRendererActing = SecretInternals.IsThisRendererActing; - -const batchedUpdates = ReactDOM.unstable_batchedUpdates; - -const {IsSomeRendererActing, ReactCurrentActQueue} = ReactSharedInternals; - // This version of `act` is only used by our tests. Unlike the public version // of `act`, it's designed to work identically in both production and // development. It may have slightly different behavior from the public // version, too, since our constraints in our test suite are not the same as // those of developers using React — we're testing React itself, as opposed to // building an app with React. -// TODO: Replace the internal "concurrent" implementations of `act` with a -// single shared module. + +import type {Thenable} from 'shared/ReactTypes'; + +import * as Scheduler from 'scheduler/unstable_mock'; + +import ReactSharedInternals from 'shared/ReactSharedInternals'; +import enqueueTask from 'shared/enqueueTask'; +const {ReactCurrentActQueue} = ReactSharedInternals; let actingUpdatesScopeDepth = 0; -export function unstable_concurrentAct(scope: () => Thenable | void) { +export function act(scope: () => Thenable | void) { if (Scheduler.unstable_flushAllWithoutAsserting === undefined) { throw Error( 'This version of `act` requires a special mock build of Scheduler.', @@ -47,10 +38,6 @@ export function unstable_concurrentAct(scope: () => Thenable | void) { } const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; - const previousIsSomeRendererActing = IsSomeRendererActing.current; - const previousIsThisRendererActing = IsThisRendererActing.current; - IsSomeRendererActing.current = true; - IsThisRendererActing.current = true; actingUpdatesScopeDepth++; if (__DEV__ && actingUpdatesScopeDepth === 1) { ReactCurrentActQueue.disableActWarning = true; @@ -61,8 +48,6 @@ export function unstable_concurrentAct(scope: () => Thenable | void) { ReactCurrentActQueue.disableActWarning = false; } actingUpdatesScopeDepth--; - IsSomeRendererActing.current = previousIsSomeRendererActing; - IsThisRendererActing.current = previousIsThisRendererActing; if (__DEV__) { if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) { @@ -80,7 +65,7 @@ export function unstable_concurrentAct(scope: () => Thenable | void) { // returned and 2) we could use async/await. Since it's only our used in // our test suite, we should be able to. try { - const thenable = batchedUpdates(scope); + const thenable = scope(); if ( typeof thenable === 'object' && thenable !== null && diff --git a/packages/react-client/src/__tests__/ReactFlight-test.js b/packages/react-client/src/__tests__/ReactFlight-test.js index 4961cbcff72a0..8d0fbe1609d98 100644 --- a/packages/react-client/src/__tests__/ReactFlight-test.js +++ b/packages/react-client/src/__tests__/ReactFlight-test.js @@ -26,7 +26,7 @@ describe('ReactFlight', () => { ReactNoop = require('react-noop-renderer'); ReactNoopFlightServer = require('react-noop-renderer/flight-server'); ReactNoopFlightClient = require('react-noop-renderer/flight-client'); - act = ReactNoop.act; + act = require('jest-react').act; ErrorBoundary = class extends React.Component { state = {hasError: false, error: null}; diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index 2d09e2864d4b6..1a35fd284c906 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -22,7 +22,7 @@ describe('ReactHooksInspectionIntegration', () => { React = require('react'); ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); - act = ReactTestRenderer.unstable_concurrentAct; + act = require('jest-react').act; ReactDebugTools = require('react-debug-tools'); }); diff --git a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js index 44fbf9fd470c2..be6a3d7b86044 100644 --- a/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js +++ b/packages/react-devtools-shared/src/__tests__/inspectedElement-test.js @@ -26,7 +26,6 @@ describe('InspectedElement', () => { let InspectedElementContext; let InspectedElementContextController; let StoreContext; - let TestUtils; let TreeContextController; let TestUtilsAct; @@ -45,10 +44,9 @@ describe('InspectedElement', () => { React = require('react'); ReactDOM = require('react-dom'); PropTypes = require('prop-types'); - TestUtils = require('react-dom/test-utils'); - TestUtilsAct = TestUtils.unstable_concurrentAct; + TestUtilsAct = require('jest-react').act; TestRenderer = utils.requireTestRenderer(); - TestRendererAct = TestUtils.unstable_concurrentAct; + TestRendererAct = require('jest-react').act; BridgeContext = require('react-devtools-shared/src/devtools/views/context') .BridgeContext; diff --git a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js index 4a365acb0ef3c..7468eb48d1cdd 100644 --- a/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js +++ b/packages/react-devtools-shared/src/__tests__/storeComponentFilters-test.js @@ -13,14 +13,14 @@ import type Store from 'react-devtools-shared/src/devtools/store'; describe('Store component filters', () => { let React; let ReactDOM; - let TestUtils; let Types; let bridge: FrontendBridge; let store: Store; let utils; + let internalAct; const act = (callback: Function) => { - TestUtils.unstable_concurrentAct(() => { + internalAct(() => { callback(); }); jest.runAllTimers(); // Flush Bridge operations @@ -35,9 +35,9 @@ describe('Store component filters', () => { React = require('react'); ReactDOM = require('react-dom'); - TestUtils = require('react-dom/test-utils'); Types = require('react-devtools-shared/src/types'); utils = require('./utils'); + internalAct = require('jest-react').act; }); it('should throw if filters are updated while profiling', () => { diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js index d9ecced72e8a6..ef2873a80bd7f 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js @@ -28,7 +28,7 @@ describe('ReactDOMFiberAsync', () => { container = document.createElement('div'); React = require('react'); ReactDOM = require('react-dom'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; Scheduler = require('scheduler'); document.body.appendChild(container); diff --git a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js index 23c7491c319c9..7aed4305876b6 100644 --- a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js @@ -23,7 +23,7 @@ describe('ReactDOMHooks', () => { React = require('react'); ReactDOM = require('react-dom'); Scheduler = require('scheduler'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; container = document.createElement('div'); document.body.appendChild(container); diff --git a/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js b/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js index d8d7c710ff57b..702f213d7a2ed 100644 --- a/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js @@ -24,7 +24,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => { React = require('react'); ReactDOM = require('react-dom'); Scheduler = require('scheduler'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; document.body.appendChild(container); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMNestedEvents-test.js b/packages/react-dom/src/__tests__/ReactDOMNestedEvents-test.js index 7c46355525e7e..6fb1b1072bdf1 100644 --- a/packages/react-dom/src/__tests__/ReactDOMNestedEvents-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMNestedEvents-test.js @@ -13,7 +13,6 @@ describe('ReactDOMNestedEvents', () => { let React; let ReactDOM; let Scheduler; - let TestUtils; let act; let useState; @@ -22,8 +21,7 @@ describe('ReactDOMNestedEvents', () => { React = require('react'); ReactDOM = require('react-dom'); Scheduler = require('scheduler'); - TestUtils = require('react-dom/test-utils'); - act = TestUtils.unstable_concurrentAct; + act = require('jest-react').act; useState = React.useState; }); diff --git a/packages/react-dom/src/__tests__/ReactDOMRoot-test.js b/packages/react-dom/src/__tests__/ReactDOMRoot-test.js index 6fb631fb4dbfb..0c264240976ed 100644 --- a/packages/react-dom/src/__tests__/ReactDOMRoot-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMRoot-test.js @@ -25,7 +25,7 @@ describe('ReactDOMRoot', () => { ReactDOM = require('react-dom'); ReactDOMServer = require('react-dom/server'); Scheduler = require('scheduler'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; }); it('renders children', () => { diff --git a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js index 7d6e894a9bdbe..cfd23f843c140 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.js @@ -44,7 +44,7 @@ function initModules() { ReactDOMServer = require('react-dom/server'); ReactTestUtils = require('react-dom/test-utils'); Scheduler = require('scheduler'); - act = ReactTestUtils.unstable_concurrentAct; + act = require('jest-react').act; useState = React.useState; useReducer = React.useReducer; useEffect = React.useEffect; diff --git a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js index 8e3c99ccc283c..a78298878b373 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js @@ -80,7 +80,7 @@ describe('ReactDOMServerPartialHydration', () => { React = require('react'); ReactDOM = require('react-dom'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; ReactDOMServer = require('react-dom/server'); Scheduler = require('scheduler'); Suspense = React.Suspense; diff --git a/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js index 73269b2262e51..76d9b43d07f61 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerSelectiveHydration-test.internal.js @@ -14,7 +14,6 @@ import {createEventTarget} from 'dom-event-testing-library'; let React; let ReactDOM; let ReactDOMServer; -let ReactTestUtils; let Scheduler; let Suspense; let act; @@ -118,8 +117,7 @@ describe('ReactDOMServerSelectiveHydration', () => { React = require('react'); ReactDOM = require('react-dom'); ReactDOMServer = require('react-dom/server'); - ReactTestUtils = require('react-dom/test-utils'); - act = ReactTestUtils.unstable_concurrentAct; + act = require('jest-react').act; Scheduler = require('scheduler'); Suspense = React.Suspense; diff --git a/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js index c987ec3b8bb0a..60ab2edbdcf2b 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerSuspense-test.internal.js @@ -25,7 +25,7 @@ function initModules() { ReactDOM = require('react-dom'); ReactDOMServer = require('react-dom/server'); ReactTestUtils = require('react-dom/test-utils'); - act = ReactTestUtils.unstable_concurrentAct; + act = require('jest-react').act; // Make them available to the helpers. return { diff --git a/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js b/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js index 44f6aeebe6711..35204db4ef513 100644 --- a/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMSuspensePlaceholder-test.js @@ -13,7 +13,6 @@ let React; let ReactDOM; let Suspense; let ReactCache; -let ReactTestUtils; let Scheduler; let TextResource; let act; @@ -26,9 +25,8 @@ describe('ReactDOMSuspensePlaceholder', () => { React = require('react'); ReactDOM = require('react-dom'); ReactCache = require('react-cache'); - ReactTestUtils = require('react-dom/test-utils'); Scheduler = require('scheduler'); - act = ReactTestUtils.unstable_concurrentAct; + act = require('jest-react').act; Suspense = React.Suspense; container = document.createElement('div'); document.body.appendChild(container); diff --git a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js index 85c7a2311e0c2..c5a1403ddc52a 100644 --- a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js @@ -45,7 +45,7 @@ describe('ReactErrorBoundaries', () => { ReactFeatureFlags.skipUnmountedBoundaries = true; ReactDOM = require('react-dom'); React = require('react'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; Scheduler = require('scheduler'); BrokenConstructor = class extends React.Component { diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index fd883f7e32d44..a49b62062d32e 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -21,7 +21,7 @@ describe('ReactUpdates', () => { React = require('react'); ReactDOM = require('react-dom'); ReactTestUtils = require('react-dom/test-utils'); - act = ReactTestUtils.unstable_concurrentAct; + act = require('jest-react').act; Scheduler = require('scheduler'); }); diff --git a/packages/react-dom/src/__tests__/ReactWrongReturnPointer-test.js b/packages/react-dom/src/__tests__/ReactWrongReturnPointer-test.js index ac6e37374f0a8..66cf344814dc8 100644 --- a/packages/react-dom/src/__tests__/ReactWrongReturnPointer-test.js +++ b/packages/react-dom/src/__tests__/ReactWrongReturnPointer-test.js @@ -10,6 +10,7 @@ let React; let ReactNoop; let Scheduler; +let act; let Suspense; let SuspenseList; let getCacheForType; @@ -20,6 +21,7 @@ beforeEach(() => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; Suspense = React.Suspense; SuspenseList = React.SuspenseList; @@ -180,12 +182,12 @@ test('warns in DEV if return pointer is inconsistent', async () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); spyOnDev(console, 'error'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(console.error.calls.count()).toBe(1); @@ -225,7 +227,7 @@ test('regression (#20932): return pointer is correct before entering deleted tre } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([ @@ -233,11 +235,11 @@ test('regression (#20932): return pointer is correct before entering deleted tre 'Loading Async...', 'Loading Tail...', ]); - await ReactNoop.act(async () => { + await act(async () => { resolveText(0); }); expect(Scheduler).toHaveYielded([0, 'Tail']); - await ReactNoop.act(async () => { + await act(async () => { setAsyncText(x => x + 1); }); expect(Scheduler).toHaveYielded([ diff --git a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js index eec0de44fb5b4..81be4cb30d72d 100644 --- a/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js +++ b/packages/react-dom/src/__tests__/utils/ReactDOMServerIntegrationTestUtils.js @@ -15,10 +15,11 @@ const shouldIgnoreConsoleError = require('../../../../../scripts/jest/shouldIgno module.exports = function(initModules) { let ReactDOM; let ReactDOMServer; - let ReactTestUtils; + let act; function resetModules() { - ({ReactDOM, ReactDOMServer, ReactTestUtils} = initModules()); + ({ReactDOM, ReactDOMServer} = initModules()); + act = require('jest-react').act; } function shouldUseDocument(reactElement) { @@ -50,11 +51,11 @@ module.exports = function(initModules) { function asyncReactDOMRender(reactElement, domElement, forceHydrate) { return new Promise(resolve => { if (forceHydrate) { - ReactTestUtils.unstable_concurrentAct(() => { + act(() => { ReactDOM.hydrate(reactElement, domElement); }); } else { - ReactTestUtils.unstable_concurrentAct(() => { + act(() => { ReactDOM.render(reactElement, domElement); }); } diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js index e603121d82c08..f2affc78a58cb 100644 --- a/packages/react-dom/src/client/ReactDOM.js +++ b/packages/react-dom/src/client/ReactDOM.js @@ -28,7 +28,6 @@ import { flushSync, flushControlled, injectIntoDevTools, - IsThisRendererActing, attemptSynchronousHydration, attemptDiscreteHydration, attemptContinuousHydration, @@ -164,8 +163,6 @@ const Internals = { restoreStateIfNeeded, batchedUpdates, ], - // TODO: Temporary. Only used by our internal version of `act. Will remove. - IsThisRendererActing, }; export { diff --git a/packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js b/packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js index b4765bc8ad384..4f2df6fffc495 100644 --- a/packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js +++ b/packages/react-dom/src/events/__tests__/DOMPluginEventSystem-test.internal.js @@ -16,7 +16,6 @@ let ReactFeatureFlags; let ReactDOM; let ReactDOMServer; let Scheduler; -let ReactTestUtils; let act; function dispatchEvent(element, type) { @@ -67,7 +66,7 @@ describe('DOMPluginEventSystem', () => { ReactDOM = require('react-dom'); Scheduler = require('scheduler'); ReactDOMServer = require('react-dom/server'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; container = document.createElement('div'); document.body.appendChild(container); startNativeEventListenerClearDown(); @@ -1253,8 +1252,7 @@ describe('DOMPluginEventSystem', () => { ReactDOM = require('react-dom'); Scheduler = require('scheduler'); ReactDOMServer = require('react-dom/server'); - ReactTestUtils = require('react-dom/test-utils'); - act = ReactTestUtils.unstable_concurrentAct; + act = require('jest-react').act; }); // @gate www diff --git a/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js b/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js index 507de50f14086..b1a5649624aeb 100644 --- a/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js +++ b/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js @@ -11,9 +11,9 @@ let React; let ReactDOM; -let TestUtils; let ReactFeatureFlags; let Scheduler; +let act; const setUntrackedChecked = Object.getOwnPropertyDescriptor( HTMLInputElement.prototype, @@ -56,7 +56,7 @@ describe('ChangeEventPlugin', () => { }; React = require('react'); ReactDOM = require('react-dom'); - TestUtils = require('react-dom/test-utils'); + act = require('jest-react').act; Scheduler = require('scheduler'); container = document.createElement('div'); document.body.appendChild(container); @@ -727,7 +727,6 @@ describe('ChangeEventPlugin', () => { }); it('mouse enter/leave should be user-blocking but not discrete', async () => { - const {unstable_concurrentAct: act} = TestUtils; const {useState} = React; const root = ReactDOM.createRoot(container); diff --git a/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js b/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js index 73c1e90f4ae5e..ba830d939c5f5 100644 --- a/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js +++ b/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js @@ -237,7 +237,7 @@ describe('SimpleEventPlugin', function() { ReactDOM = require('react-dom'); Scheduler = require('scheduler'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; }); it('flushes pending interactive work before exiting event handler', async () => { diff --git a/packages/react-dom/src/test-utils/ReactTestUtils.js b/packages/react-dom/src/test-utils/ReactTestUtils.js index e721dd30e7a34..cc93dc866eaa8 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtils.js +++ b/packages/react-dom/src/test-utils/ReactTestUtils.js @@ -18,7 +18,6 @@ import { import {SyntheticEvent} from '../events/SyntheticEvent'; import invariant from 'shared/invariant'; import {ELEMENT_NODE} from '../shared/HTMLNodeType'; -import {unstable_concurrentAct} from './ReactTestUtilsInternalAct'; import { rethrowCaughtError, invokeGuardedCallbackAndCatchFirstError, @@ -732,5 +731,4 @@ export { nativeTouchData, Simulate, act, - unstable_concurrentAct, }; diff --git a/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js b/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js index 62eb6630de2ee..df151bbf72c24 100644 --- a/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js +++ b/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js @@ -15,7 +15,6 @@ let React; let ReactFeatureFlags; let ReactDOM; let useFocusWithin; -let ReactTestRenderer; let act; let Scheduler; @@ -27,9 +26,8 @@ function initializeModules(hasPointerEvents) { ReactFeatureFlags.enableCreateEventHandleAPI = true; React = require('react'); ReactDOM = require('react-dom'); - ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); - act = ReactTestRenderer.unstable_concurrentAct; + act = require('jest-react').act; // TODO: This import throws outside of experimental mode. Figure out better // strategy for gated imports. diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js index 59cea7cd5d971..8dbadafd2c22a 100644 --- a/packages/react-noop-renderer/src/createReactNoop.js +++ b/packages/react-noop-renderer/src/createReactNoop.js @@ -16,7 +16,7 @@ import type {Fiber} from 'react-reconciler/src/ReactInternalTypes'; import type {UpdateQueue} from 'react-reconciler/src/ReactUpdateQueue'; -import type {ReactNodeList, Thenable} from 'shared/ReactTypes'; +import type {ReactNodeList} from 'shared/ReactTypes'; import type {RootTag} from 'react-reconciler/src/ReactRootTags'; import * as Scheduler from 'scheduler/unstable_mock'; @@ -29,10 +29,6 @@ import { LegacyRoot, } from 'react-reconciler/constants'; -import ReactSharedInternals from 'shared/ReactSharedInternals'; -import enqueueTask from 'shared/enqueueTask'; -const {IsSomeRendererActing, ReactCurrentActQueue} = ReactSharedInternals; - type Container = { rootID: string, children: Array, @@ -927,8 +923,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { flushPassiveEffects: NoopRenderer.flushPassiveEffects, - act: noopAct, - // Logs the current state of the tree. dumpTree(rootID: string = DEFAULT_ROOT_ID) { const root = roots.get(rootID); @@ -1042,129 +1036,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) { }, }; - // This version of `act` is only used by our tests. Unlike the public version - // of `act`, it's designed to work identically in both production and - // development. It may have slightly different behavior from the public - // version, too, since our constraints in our test suite are not the same as - // those of developers using React — we're testing React itself, as opposed to - // building an app with React. - // TODO: Replace the internal "concurrent" implementations of `act` with a - // single shared module. - - const {batchedUpdates, IsThisRendererActing} = NoopRenderer; - let actingUpdatesScopeDepth = 0; - - function noopAct(scope: () => Thenable | void) { - if (Scheduler.unstable_flushAllWithoutAsserting === undefined) { - throw Error( - 'This version of `act` requires a special mock build of Scheduler.', - ); - } - if (setTimeout._isMockFunction !== true) { - throw Error( - "This version of `act` requires Jest's timer mocks " + - '(i.e. jest.useFakeTimers).', - ); - } - - const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; - const previousIsSomeRendererActing = IsSomeRendererActing.current; - const previousIsThisRendererActing = IsThisRendererActing.current; - IsSomeRendererActing.current = true; - IsThisRendererActing.current = true; - actingUpdatesScopeDepth++; - if (__DEV__ && actingUpdatesScopeDepth === 1) { - ReactCurrentActQueue.disableActWarning = true; - } - - const unwind = () => { - if (__DEV__ && actingUpdatesScopeDepth === 1) { - ReactCurrentActQueue.disableActWarning = false; - } - 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. ', - ); - } - } - }; - - // TODO: This would be way simpler if 1) we required a promise to be - // returned and 2) we could use async/await. Since it's only our used in - // our test suite, we should be able to. - try { - const thenable = batchedUpdates(scope); - if ( - typeof thenable === 'object' && - thenable !== null && - typeof thenable.then === 'function' - ) { - return { - then(resolve: () => void, reject: (error: mixed) => void) { - thenable.then( - () => { - flushActWork( - () => { - unwind(); - resolve(); - }, - error => { - unwind(); - reject(error); - }, - ); - }, - error => { - unwind(); - reject(error); - }, - ); - }, - }; - } else { - try { - // TODO: Let's not support non-async scopes at all in our tests. Need to - // migrate existing tests. - let didFlushWork; - do { - didFlushWork = Scheduler.unstable_flushAllWithoutAsserting(); - } while (didFlushWork); - } finally { - unwind(); - } - } - } catch (error) { - unwind(); - throw error; - } - } - - function flushActWork(resolve, reject) { - // Flush suspended fallbacks - // $FlowFixMe: Flow doesn't know about global Jest object - jest.runOnlyPendingTimers(); - enqueueTask(() => { - try { - const didFlushWork = Scheduler.unstable_flushAllWithoutAsserting(); - if (didFlushWork) { - flushActWork(resolve, reject); - } else { - resolve(); - } - } catch (error) { - reject(error); - } - }); - } - return ReactNoop; } diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js index 6675ed78d5ffb..7f1a53522da53 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.js @@ -26,7 +26,6 @@ import { flushControlled as flushControlled_old, flushSync as flushSync_old, flushPassiveEffects as flushPassiveEffects_old, - IsThisRendererActing as IsThisRendererActing_old, getPublicRootInstance as getPublicRootInstance_old, attemptSynchronousHydration as attemptSynchronousHydration_old, attemptDiscreteHydration as attemptDiscreteHydration_old, @@ -66,7 +65,6 @@ import { flushControlled as flushControlled_new, flushSync as flushSync_new, flushPassiveEffects as flushPassiveEffects_new, - IsThisRendererActing as IsThisRendererActing_new, getPublicRootInstance as getPublicRootInstance_new, attemptSynchronousHydration as attemptSynchronousHydration_new, attemptDiscreteHydration as attemptDiscreteHydration_new, @@ -125,9 +123,6 @@ export const flushSync = enableNewReconciler ? flushSync_new : flushSync_old; export const flushPassiveEffects = enableNewReconciler ? flushPassiveEffects_new : flushPassiveEffects_old; -export const IsThisRendererActing = enableNewReconciler - ? IsThisRendererActing_new - : IsThisRendererActing_old; export const getPublicRootInstance = enableNewReconciler ? getPublicRootInstance_new : getPublicRootInstance_old; diff --git a/packages/react-reconciler/src/ReactFiberReconciler.new.js b/packages/react-reconciler/src/ReactFiberReconciler.new.js index 9e831157bf5fc..1c549125a43dd 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.new.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.new.js @@ -60,7 +60,6 @@ import { discreteUpdates, flushDiscreteUpdates, flushPassiveEffects, - IsThisRendererActing, } from './ReactFiberWorkLoop.new'; import { createUpdate, @@ -337,7 +336,6 @@ export { flushControlled, flushSync, flushPassiveEffects, - IsThisRendererActing, }; export function getPublicRootInstance( diff --git a/packages/react-reconciler/src/ReactFiberReconciler.old.js b/packages/react-reconciler/src/ReactFiberReconciler.old.js index 8accca3deb359..f57b1f84814c4 100644 --- a/packages/react-reconciler/src/ReactFiberReconciler.old.js +++ b/packages/react-reconciler/src/ReactFiberReconciler.old.js @@ -60,7 +60,6 @@ import { discreteUpdates, flushDiscreteUpdates, flushPassiveEffects, - IsThisRendererActing, } from './ReactFiberWorkLoop.old'; import { createUpdate, @@ -337,7 +336,6 @@ export { flushControlled, flushSync, flushPassiveEffects, - IsThisRendererActing, }; export function getPublicRootInstance( diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js index b4f889c569afe..b21c7b2e33f90 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.new.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.new.js @@ -2767,9 +2767,6 @@ function warnAboutRenderPhaseUpdatesInDEV(fiber) { } } -// a 'shared' variable that changes when act() opens/closes in tests. -export const IsThisRendererActing = {current: (false: boolean)}; - export function restorePendingUpdaters(root: FiberRoot, lanes: Lanes): void { if (enableUpdaterTracking) { if (isDevToolsPresent) { diff --git a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js index d2ccf9e6826af..399ea10393ef5 100644 --- a/packages/react-reconciler/src/ReactFiberWorkLoop.old.js +++ b/packages/react-reconciler/src/ReactFiberWorkLoop.old.js @@ -2767,9 +2767,6 @@ function warnAboutRenderPhaseUpdatesInDEV(fiber) { } } -// a 'shared' variable that changes when act() opens/closes in tests. -export const IsThisRendererActing = {current: (false: boolean)}; - export function restorePendingUpdaters(root: FiberRoot, lanes: Lanes): void { if (enableUpdaterTracking) { if (isDevToolsPresent) { diff --git a/packages/react-reconciler/src/__tests__/ReactCPUSuspense-test.js b/packages/react-reconciler/src/__tests__/ReactCPUSuspense-test.js index 1de9050caa4a6..85d3fbbab534b 100644 --- a/packages/react-reconciler/src/__tests__/ReactCPUSuspense-test.js +++ b/packages/react-reconciler/src/__tests__/ReactCPUSuspense-test.js @@ -1,6 +1,7 @@ let React; let ReactNoop; let Scheduler; +let act; let Suspense; let useState; let textCache; @@ -16,6 +17,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; Suspense = React.Suspense; useState = React.useState; @@ -123,7 +125,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); expect(Scheduler).toFlushUntilNextPaint(['Outer', 'Loading...']); expect(root).toMatchRenderedOutput( @@ -165,7 +167,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Initial mount const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); // Inner contents finish in separate commit from outer @@ -178,7 +180,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Update - await ReactNoop.act(async () => { + await act(async () => { setCount(1); }); // Entire update finishes in a single commit @@ -208,7 +210,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); expect(Scheduler).toFlushUntilNextPaint(['Outer', 'Loading...']); expect(root).toMatchRenderedOutput( @@ -228,7 +230,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Resolve the data and finish rendering - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Inner'); }); expect(Scheduler).toHaveYielded(['Inner']); @@ -264,7 +266,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); // Each level commits separately diff --git a/packages/react-reconciler/src/__tests__/ReactCache-test.js b/packages/react-reconciler/src/__tests__/ReactCache-test.js index 01488a8b3a7ba..4f6caa4c6a80e 100644 --- a/packages/react-reconciler/src/__tests__/ReactCache-test.js +++ b/packages/react-reconciler/src/__tests__/ReactCache-test.js @@ -3,6 +3,7 @@ let ReactNoop; let Cache; let getCacheForType; let Scheduler; +let act; let Suspense; let useCacheRefresh; let startTransition; @@ -19,6 +20,7 @@ describe('ReactCache', () => { ReactNoop = require('react-noop-renderer'); Cache = React.unstable_Cache; Scheduler = require('scheduler'); + act = require('jest-react').act; Suspense = React.Suspense; getCacheForType = React.unstable_getCacheForType; useCacheRefresh = React.unstable_useCacheRefresh; @@ -152,7 +154,7 @@ describe('ReactCache', () => { // @gate experimental || www test('render Cache component', async () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(Hi); }); expect(root).toMatchRenderedOutput('Hi'); @@ -161,7 +163,7 @@ describe('ReactCache', () => { // @gate experimental || www test('mount new data', async () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( }> @@ -173,7 +175,7 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A']); @@ -183,7 +185,7 @@ describe('ReactCache', () => { // @gate experimental || www test('root acts as implicit cache boundary', async () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( }> @@ -193,7 +195,7 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A']); @@ -220,7 +222,7 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); // Even though there are two new trees, they should share the same @@ -232,7 +234,7 @@ describe('ReactCache', () => { ]); expect(root).toMatchRenderedOutput('Loading...Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A', 'A']); @@ -256,7 +258,7 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); // Even though there are two new trees, they should share the same @@ -264,7 +266,7 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A', 'A']); @@ -290,7 +292,7 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { seedNextTextCache('A'); root.render(); }); @@ -298,7 +300,7 @@ describe('ReactCache', () => { expect(root).toMatchRenderedOutput('A [v1]'); // Add a new cache boundary - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([ @@ -331,7 +333,7 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { seedNextTextCache('A'); root.render(); }); @@ -339,7 +341,7 @@ describe('ReactCache', () => { expect(root).toMatchRenderedOutput('A [v1]'); // Add a new cache boundary - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([ @@ -349,7 +351,7 @@ describe('ReactCache', () => { 'Loading...', ]); expect(root).toMatchRenderedOutput('A [v1]Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v2]']); @@ -396,13 +398,13 @@ describe('ReactCache', () => { return ; } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading shell...']); expect(root).toMatchRenderedOutput('Loading shell...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded([ @@ -419,7 +421,7 @@ describe('ReactCache', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('B'); }); expect(Scheduler).toHaveYielded(['Content']); @@ -441,7 +443,7 @@ describe('ReactCache', () => { // Mount initial data const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( }> @@ -453,20 +455,20 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v1]']); expect(root).toMatchRenderedOutput('A [v1]'); // Fefresh for new data. - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => refresh()); }); expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('A [v1]'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); // Note that the version has updated @@ -484,7 +486,7 @@ describe('ReactCache', () => { // Mount initial data const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( }> @@ -494,20 +496,20 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v1]']); expect(root).toMatchRenderedOutput('A [v1]'); // Refresh for new data. - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => refresh()); }); expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('A [v1]'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); // Note that the version has updated @@ -525,7 +527,7 @@ describe('ReactCache', () => { // Mount initial data const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( }> @@ -537,14 +539,14 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v1]']); expect(root).toMatchRenderedOutput('A [v1]'); // Refresh for new data. - await ReactNoop.act(async () => { + await act(async () => { // Refresh the cache with seeded data, like you would receive from a // server mutation. // TODO: Seeding multiple typed caches. Should work by calling `refresh` @@ -585,7 +587,7 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { seedNextTextCache('A'); root.render(); }); @@ -593,7 +595,7 @@ describe('ReactCache', () => { expect(root).toMatchRenderedOutput('A [v1]'); // Add a new cache boundary - await ReactNoop.act(async () => { + await act(async () => { seedNextTextCache('A'); root.render(); }); @@ -606,7 +608,7 @@ describe('ReactCache', () => { // Now refresh the shell. This should also cause the "Show More" contents to // refresh, since its cache is nested inside the outer one. - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => refreshShell()); }); expect(Scheduler).toHaveYielded([ @@ -616,7 +618,7 @@ describe('ReactCache', () => { ]); expect(root).toMatchRenderedOutput('A [v1]A [v2]'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v3]', 'A [v3]']); @@ -657,12 +659,12 @@ describe('ReactCache', () => { // treated like sibling providers that happen to share an underlying // cache, as opposed to consumers of the root-level cache. const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); // Now reveal the boundaries. In a real app this would be a navigation. - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); @@ -675,7 +677,7 @@ describe('ReactCache', () => { ]); expect(root).toMatchRenderedOutput('Loading...Loading...'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v1]', 'A [v1]']); @@ -683,12 +685,12 @@ describe('ReactCache', () => { // Refresh the first boundary. It should not refresh the second boundary, // even though they previously shared the same underlying cache. - await ReactNoop.act(async () => { + await act(async () => { await refreshFirstBoundary(); }); expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v2]']); @@ -723,7 +725,7 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([ @@ -732,7 +734,7 @@ describe('ReactCache', () => { 'Loading...', ]); - await ReactNoop.act(async () => { + await act(async () => { // This will resolve the content in the first cache resolveMostRecentTextCache('A'); resolveMostRecentTextCache('B'); @@ -750,7 +752,7 @@ describe('ReactCache', () => { ]); // Now resolve the second tree - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v2]']); @@ -769,7 +771,7 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( }>(empty), ); @@ -777,7 +779,7 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded([]); expect(root).toMatchRenderedOutput('(empty)'); - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { root.render( }> @@ -789,7 +791,7 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('(empty)'); - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { root.render( }> @@ -806,14 +808,14 @@ describe('ReactCache', () => { expect(root).toMatchRenderedOutput('(empty)'); // Resolve the request - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v1]', 'A [v1]']); expect(root).toMatchRenderedOutput('A [v1]A [v1]'); // Now do another transition - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { root.render( }> @@ -834,7 +836,7 @@ describe('ReactCache', () => { ]); expect(root).toMatchRenderedOutput('A [v1]A [v1]'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A [v1]', 'A [v1]', 'A [v2]']); @@ -877,13 +879,13 @@ describe('ReactCache', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['0']); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { showMore(); }); @@ -891,7 +893,7 @@ describe('ReactCache', () => { expect(Scheduler).toHaveYielded(['Cache miss! [A]', 'Loading...']); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { updateUnrelated(1); }); expect(Scheduler).toHaveYielded([ @@ -903,7 +905,7 @@ describe('ReactCache', () => { ]); expect(root).toMatchRenderedOutput('1'); - await ReactNoop.act(async () => { + await act(async () => { resolveMostRecentTextCache('A'); }); expect(Scheduler).toHaveYielded(['A']); diff --git a/packages/react-reconciler/src/__tests__/ReactClassSetStateCallback-test.js b/packages/react-reconciler/src/__tests__/ReactClassSetStateCallback-test.js index 13d9ce838c03b..0f97bb5997186 100644 --- a/packages/react-reconciler/src/__tests__/ReactClassSetStateCallback-test.js +++ b/packages/react-reconciler/src/__tests__/ReactClassSetStateCallback-test.js @@ -1,6 +1,7 @@ let React; let ReactNoop; let Scheduler; +let act; describe('ReactClassSetStateCallback', () => { beforeEach(() => { @@ -9,6 +10,7 @@ describe('ReactClassSetStateCallback', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; }); function Text({text}) { @@ -27,12 +29,12 @@ describe('ReactClassSetStateCallback', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([0]); - await ReactNoop.act(async () => { + await act(async () => { app.setState({step: 1}, () => Scheduler.unstable_yieldValue('Callback 1'), ); diff --git a/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js b/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js index 0dcc18f074ac9..f568e40ccad7c 100644 --- a/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js +++ b/packages/react-reconciler/src/__tests__/ReactContextPropagation-test.js @@ -1,6 +1,7 @@ let React; let ReactNoop; let Scheduler; +let act; let useState; let useContext; let Suspense; @@ -16,6 +17,7 @@ describe('ReactLazyContextPropagation', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; useState = React.useState; useContext = React.useContext; Suspense = React.Suspense; @@ -195,13 +197,13 @@ describe('ReactLazyContextPropagation', () => { return ; } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([0]); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { setValue(1); }); expect(Scheduler).toHaveYielded([1]); @@ -237,13 +239,13 @@ describe('ReactLazyContextPropagation', () => { return ; } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([0]); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { setValue(1); }); expect(Scheduler).toHaveYielded([1]); @@ -280,13 +282,13 @@ describe('ReactLazyContextPropagation', () => { return ; } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([0]); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { setValue(1); }); expect(Scheduler).toHaveYielded([1]); @@ -318,13 +320,13 @@ describe('ReactLazyContextPropagation', () => { return ; }); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Consumer', 0]); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { // Intentionally calling setState to some other arbitrary value before // setting it back to the current one. That way an update is scheduled, // but we'll bail out during render when nothing has changed. @@ -380,13 +382,13 @@ describe('ReactLazyContextPropagation', () => { } await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { // Intentionally not wrapping in startTransition, so that the fallback // the fallback displays despite this being a refresh. setContext('B'); @@ -394,7 +396,7 @@ describe('ReactLazyContextPropagation', () => { expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...', 'B']); expect(root).toMatchRenderedOutput('Loading...B'); - await ReactNoop.act(async () => { + await act(async () => { await resolveText('B'); }); expect(Scheduler).toHaveYielded(['B']); @@ -460,13 +462,13 @@ describe('ReactLazyContextPropagation', () => { } await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A', 'A']); expect(root).toMatchRenderedOutput('AAA'); - await ReactNoop.act(async () => { + await act(async () => { // Intentionally not wrapping in startTransition, so that the fallback // the fallback displays despite this being a refresh. setContext('B'); @@ -474,7 +476,7 @@ describe('ReactLazyContextPropagation', () => { expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...', 'B']); expect(root).toMatchRenderedOutput('Loading...B'); - await ReactNoop.act(async () => { + await act(async () => { await resolveText('B'); }); expect(Scheduler).toHaveYielded(['B', 'B']); @@ -521,13 +523,13 @@ describe('ReactLazyContextPropagation', () => { } await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { // Intentionally not wrapping in startTransition, so that the fallback // the fallback displays despite this being a refresh. setContext('B'); @@ -535,7 +537,7 @@ describe('ReactLazyContextPropagation', () => { expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...', 'B']); expect(root).toMatchRenderedOutput('Loading...B'); - await ReactNoop.act(async () => { + await act(async () => { await resolveText('B'); }); expect(Scheduler).toHaveYielded(['B']); @@ -575,13 +577,13 @@ describe('ReactLazyContextPropagation', () => { } await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { setContext('B'); }); expect(Scheduler).toHaveYielded(['B', 'B']); @@ -636,13 +638,13 @@ describe('ReactLazyContextPropagation', () => { } await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A', 'A']); expect(root).toMatchRenderedOutput('AAA'); - await ReactNoop.act(async () => { + await act(async () => { setContext('B'); }); expect(Scheduler).toHaveYielded(['B', 'B', 'B']); @@ -677,13 +679,13 @@ describe('ReactLazyContextPropagation', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { setContext('B'); }); expect(Scheduler).toHaveYielded(['B', 'B']); @@ -731,13 +733,13 @@ describe('ReactLazyContextPropagation', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { setContext('B'); }); expect(Scheduler).toHaveYielded(['B', 'B']); @@ -794,19 +796,19 @@ describe('ReactLazyContextPropagation', () => { const root = ReactNoop.createRoot(); await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { setContext('B'); }); expect(Scheduler).toHaveYielded(['Suspend! [B]', 'Loading...']); expect(root).toMatchRenderedOutput('Loading...'); - await ReactNoop.act(async () => { + await act(async () => { await resolveText('B'); }); expect(Scheduler).toHaveYielded(['B', 'B']); @@ -855,13 +857,13 @@ describe('ReactLazyContextPropagation', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { setContext('B'); }); expect(Scheduler).toHaveYielded(['B', 'B']); @@ -904,13 +906,13 @@ describe('ReactLazyContextPropagation', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A', 'A']); expect(root).toMatchRenderedOutput('AA'); - await ReactNoop.act(async () => { + await act(async () => { setContext('B'); }); expect(Scheduler).toHaveYielded(['B', 'B']); diff --git a/packages/react-reconciler/src/__tests__/ReactEffectOrdering-test.js b/packages/react-reconciler/src/__tests__/ReactEffectOrdering-test.js index 6e9ffcfb894f5..05a8b84a7f781 100644 --- a/packages/react-reconciler/src/__tests__/ReactEffectOrdering-test.js +++ b/packages/react-reconciler/src/__tests__/ReactEffectOrdering-test.js @@ -15,6 +15,7 @@ let React; let ReactNoop; let Scheduler; +let act; let useEffect; let useLayoutEffect; @@ -26,6 +27,7 @@ describe('ReactHooksWithNoopRenderer', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; useEffect = React.useEffect; useLayoutEffect = React.useLayoutEffect; }); @@ -47,11 +49,11 @@ describe('ReactHooksWithNoopRenderer', () => { return 'Child'; } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(root).toMatchRenderedOutput('Child'); - await ReactNoop.act(async () => { + await act(async () => { root.render(null); }); expect(Scheduler).toHaveYielded(['Unmount parent', 'Unmount child']); @@ -74,11 +76,11 @@ describe('ReactHooksWithNoopRenderer', () => { return 'Child'; } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(root).toMatchRenderedOutput('Child'); - await ReactNoop.act(async () => { + await act(async () => { root.render(null); }); expect(Scheduler).toHaveYielded(['Unmount parent', 'Unmount child']); diff --git a/packages/react-reconciler/src/__tests__/ReactExpiration-test.js b/packages/react-reconciler/src/__tests__/ReactExpiration-test.js index 8497aa6c9ef6b..202348a21bb7b 100644 --- a/packages/react-reconciler/src/__tests__/ReactExpiration-test.js +++ b/packages/react-reconciler/src/__tests__/ReactExpiration-test.js @@ -12,6 +12,7 @@ let React; let ReactNoop; let Scheduler; +let act; let readText; let resolveText; let startTransition; @@ -25,6 +26,7 @@ describe('ReactExpiration', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; startTransition = React.startTransition; useState = React.useState; useEffect = React.useEffect; @@ -496,14 +498,14 @@ describe('ReactExpiration', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Sync pri: 0', 'Normal pri: 0']); expect(root).toMatchRenderedOutput('Sync pri: 0, Normal pri: 0'); // First demonstrate what happens when there's no starvation - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { updateNormalPri(); @@ -527,7 +529,7 @@ describe('ReactExpiration', () => { expect(root).toMatchRenderedOutput('Sync pri: 1, Normal pri: 1'); // Do the same thing, but starve the first update - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { updateNormalPri(); @@ -575,14 +577,14 @@ describe('ReactExpiration', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Sync pri: 0', 'Idle pri: 0']); expect(root).toMatchRenderedOutput('Sync pri: 0, Idle pri: 0'); // First demonstrate what happens when there's no starvation - await ReactNoop.act(async () => { + await act(async () => { updateIdlePri(); expect(Scheduler).toFlushAndYieldThrough(['Sync pri: 0']); updateSyncPri(); @@ -598,7 +600,7 @@ describe('ReactExpiration', () => { expect(root).toMatchRenderedOutput('Sync pri: 1, Idle pri: 1'); // Do the same thing, but starve the first update - await ReactNoop.act(async () => { + await act(async () => { updateIdlePri(); expect(Scheduler).toFlushAndYieldThrough(['Sync pri: 1']); @@ -638,13 +640,13 @@ describe('ReactExpiration', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A0', 'B0', 'C']); expect(root).toMatchRenderedOutput('A0B0C'); - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { setA(1); }); @@ -682,14 +684,14 @@ describe('ReactExpiration', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { await resolveText('A0'); root.render(); }); expect(Scheduler).toHaveYielded(['A0', 'B', 'C']); expect(root).toMatchRenderedOutput('A0BC'); - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { root.render(); @@ -741,12 +743,12 @@ describe('ReactExpiration', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A0', 'B0']); - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { setA(1); }); @@ -782,13 +784,13 @@ describe('ReactExpiration', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A0', 'B0', 'C0', 'Effect: 0']); expect(root).toMatchRenderedOutput('A0B0C0'); - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { root.render(); }); diff --git a/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js b/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js index fc1ac7f3377b3..a3a74d739a9a3 100644 --- a/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js +++ b/packages/react-reconciler/src/__tests__/ReactFlushSync-test.js @@ -1,6 +1,7 @@ let React; let ReactNoop; let Scheduler; +let act; let useState; let useEffect; let startTransition; @@ -12,6 +13,7 @@ describe('ReactFlushSync', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; useState = React.useState; useEffect = React.useEffect; startTransition = React.startTransition; @@ -36,7 +38,7 @@ describe('ReactFlushSync', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { root.render(); @@ -75,13 +77,13 @@ describe('ReactFlushSync', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['0, 0']); expect(root).toMatchRenderedOutput('0, 0'); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.flushSync(() => { startTransition(() => { // This should be async even though flushSync is on the stack, because @@ -112,7 +114,7 @@ describe('ReactFlushSync', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.flushSync(() => { root.render(); }); @@ -135,7 +137,7 @@ describe('ReactFlushSync', () => { } const root = ReactNoop.createLegacyRoot(); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.flushSync(() => { root.render(); }); @@ -159,7 +161,7 @@ describe('ReactFlushSync', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); expect(Scheduler).toFlushUntilNextPaint([ 'Child', diff --git a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js index ce9236e114b96..c14588788b38b 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactHooks-test.internal.js @@ -31,7 +31,7 @@ describe('ReactHooks', () => { ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); ReactDOMServer = require('react-dom/server'); - act = ReactTestRenderer.unstable_concurrentAct; + act = require('jest-react').act; }); if (__DEV__) { @@ -1775,13 +1775,15 @@ describe('ReactHooks', () => { } await act(async () => { - ReactTestRenderer.create( - <> - - - , - ); - expect(() => Scheduler.unstable_flushAll()).toThrow('Hello'); + ReactTestRenderer.unstable_batchedUpdates(() => { + ReactTestRenderer.create( + <> + + + , + ); + expect(() => Scheduler.unstable_flushAll()).toThrow('Hello'); + }); }); if (__DEV__) { diff --git a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js index e43804ab50068..fc5e61cd78ee6 100644 --- a/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js +++ b/packages/react-reconciler/src/__tests__/ReactHooksWithNoopRenderer-test.js @@ -42,6 +42,7 @@ describe('ReactHooksWithNoopRenderer', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; useState = React.useState; useReducer = React.useReducer; useEffect = React.useEffect; @@ -55,7 +56,6 @@ describe('ReactHooksWithNoopRenderer', () => { useTransition = React.useTransition; useDeferredValue = React.useDeferredValue; Suspense = React.Suspense; - act = ReactNoop.act; ContinuousEventPriority = require('react-reconciler/constants') .ContinuousEventPriority; @@ -500,7 +500,7 @@ describe('ReactHooksWithNoopRenderer', () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -511,7 +511,7 @@ describe('ReactHooksWithNoopRenderer', () => { expect(Scheduler).toHaveYielded(['Foo [0]', 'Bar']); // Bar will update Foo during its render phase. React should warn. - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -527,7 +527,7 @@ describe('ReactHooksWithNoopRenderer', () => { }); // It should not warn again (deduplication). - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -675,7 +675,7 @@ describe('ReactHooksWithNoopRenderer', () => { // Test that it works on update, too. This time the log is a bit different // because we started with reducerB instead of reducerA. - ReactNoop.act(() => { + act(() => { counter.current.dispatch('reset'); }); ReactNoop.render(); @@ -787,7 +787,7 @@ describe('ReactHooksWithNoopRenderer', () => { expect(Scheduler).toFlushAndYield(['A:0']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { root.render(); @@ -3492,7 +3492,7 @@ describe('ReactHooksWithNoopRenderer', () => { } const root = ReactNoop.createRoot(null); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -3507,7 +3507,7 @@ describe('ReactHooksWithNoopRenderer', () => { 'Commit B: 0', ]); - await ReactNoop.act(async () => { + await act(async () => { setCounterA(1); // In the same batch, update B twice. To trigger the condition we're @@ -3714,7 +3714,7 @@ describe('ReactHooksWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([ @@ -3724,7 +3724,7 @@ describe('ReactHooksWithNoopRenderer', () => { 'Mount B', ]); - await ReactNoop.act(async () => { + await act(async () => { await resolveText('A'); }); expect(Scheduler).toHaveYielded([ @@ -3733,7 +3733,7 @@ describe('ReactHooksWithNoopRenderer', () => { 'Suspend! [B]', ]); - await ReactNoop.act(async () => { + await act(async () => { root.render(null); }); // In the regression, SuspenseList would cause the children to "forget" that @@ -3760,25 +3760,25 @@ describe('ReactHooksWithNoopRenderer', () => { return ; } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded(['Render: 0', 'Effect: 0']); - ReactNoop.act(() => { + act(() => { handleClick(); }); expect(Scheduler).toHaveYielded(['Render: 0']); - ReactNoop.act(() => { + act(() => { handleClick(); }); expect(Scheduler).toHaveYielded(['Render: 0']); - ReactNoop.act(() => { + act(() => { handleClick(); }); diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js index ed4c945ea7f39..2d6ad2a97524e 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js @@ -15,6 +15,7 @@ let PropTypes; let React; let ReactNoop; let Scheduler; +let act; describe('ReactIncrementalErrorHandling', () => { beforeEach(() => { @@ -25,6 +26,7 @@ describe('ReactIncrementalErrorHandling', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; }); function div(...children) { @@ -1843,7 +1845,7 @@ describe('ReactIncrementalErrorHandling', () => { throw Error('Oops'); } - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { root.render(); @@ -1886,11 +1888,11 @@ describe('ReactIncrementalErrorHandling', () => { return 'Everything is fine.'; } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); - await ReactNoop.act(async () => { + await act(async () => { // Schedule a default pri and a low pri update on the root. root.render(); React.startTransition(() => { diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.js index 71dfe3529bfb3..b603b03c696f5 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalScheduling-test.js @@ -13,6 +13,7 @@ let React; let ReactNoop; let Scheduler; +let act; describe('ReactIncrementalScheduling', () => { beforeEach(() => { @@ -21,6 +22,7 @@ describe('ReactIncrementalScheduling', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; }); function span(prop) { @@ -94,7 +96,7 @@ describe('ReactIncrementalScheduling', () => { return text; } - ReactNoop.act(() => { + act(() => { ReactNoop.renderToRootWithID(, 'a'); ReactNoop.renderToRootWithID(, 'b'); ReactNoop.renderToRootWithID(, 'c'); @@ -106,7 +108,7 @@ describe('ReactIncrementalScheduling', () => { expect(ReactNoop.getChildrenAsJSX('c')).toEqual('c:1'); // Schedule deferred work in the reverse order - ReactNoop.act(() => { + act(() => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { ReactNoop.renderToRootWithID(, 'c'); diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js b/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js index cd560ae91ca37..200d6453010bd 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalUpdates-test.js @@ -14,6 +14,7 @@ let React; let ReactNoop; let Scheduler; let ContinuousEventPriority; +let act; describe('ReactIncrementalUpdates', () => { beforeEach(() => { @@ -22,6 +23,7 @@ describe('ReactIncrementalUpdates', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; ContinuousEventPriority = require('react-reconciler/constants') .ContinuousEventPriority; }); @@ -556,7 +558,7 @@ describe('ReactIncrementalUpdates', () => { return null; } - ReactNoop.act(() => { + act(() => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { ReactNoop.render(); @@ -664,13 +666,13 @@ describe('ReactIncrementalUpdates', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Committed: ']); expect(root).toMatchRenderedOutput(''); - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { pushToLog('A'); @@ -725,13 +727,13 @@ describe('ReactIncrementalUpdates', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([]); expect(root).toMatchRenderedOutput(''); - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { pushToLog('A'); @@ -788,20 +790,20 @@ describe('ReactIncrementalUpdates', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(root).toMatchRenderedOutput('0'); // Changing the prop causes the count to increase by 100 - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(root).toMatchRenderedOutput('100'); // Now increment the count by 1 with a state update. And, in the same // batch, change the prop back to its original value. - await ReactNoop.act(async () => { + await act(async () => { root.render(); app.setState(state => ({count: state.count + 1})); }); diff --git a/packages/react-reconciler/src/__tests__/ReactInterleavedUpdates-test.js b/packages/react-reconciler/src/__tests__/ReactInterleavedUpdates-test.js index bab36c770e716..c9e66fe0399e5 100644 --- a/packages/react-reconciler/src/__tests__/ReactInterleavedUpdates-test.js +++ b/packages/react-reconciler/src/__tests__/ReactInterleavedUpdates-test.js @@ -4,6 +4,7 @@ let Scheduler; let startTransition; let useState; let useEffect; +let act; describe('ReactInterleavedUpdates', () => { beforeEach(() => { @@ -12,6 +13,7 @@ describe('ReactInterleavedUpdates', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; startTransition = React.startTransition; useState = React.useState; useEffect = React.useEffect; @@ -42,7 +44,7 @@ describe('ReactInterleavedUpdates', () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -54,7 +56,7 @@ describe('ReactInterleavedUpdates', () => { expect(Scheduler).toHaveYielded([0, 0, 0]); expect(root).toMatchRenderedOutput('000'); - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { updateChildren(1); @@ -107,7 +109,7 @@ describe('ReactInterleavedUpdates', () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -119,7 +121,7 @@ describe('ReactInterleavedUpdates', () => { expect(Scheduler).toHaveYielded([0, 0, 0]); expect(root).toMatchRenderedOutput('000'); - await ReactNoop.act(async () => { + await act(async () => { updateChildren(1); // Partially render the children. Only the first one. expect(Scheduler).toFlushAndYieldThrough([1]); diff --git a/packages/react-reconciler/src/__tests__/ReactMemo-test.js b/packages/react-reconciler/src/__tests__/ReactMemo-test.js index 89bf6e2cd4e60..639daeb1a98d1 100644 --- a/packages/react-reconciler/src/__tests__/ReactMemo-test.js +++ b/packages/react-reconciler/src/__tests__/ReactMemo-test.js @@ -17,6 +17,7 @@ let React; let ReactNoop; let Suspense; let Scheduler; +let act; describe('memo', () => { beforeEach(() => { @@ -26,6 +27,7 @@ describe('memo', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; ({Suspense} = React); }); @@ -447,12 +449,12 @@ describe('memo', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { setCounter(1); ReactNoop.discreteUpdates(() => { root.render(); @@ -483,12 +485,12 @@ describe('memo', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(root).toMatchRenderedOutput('0'); - await ReactNoop.act(async () => { + await act(async () => { setCounter(1); ReactNoop.discreteUpdates(() => { root.render(); diff --git a/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js b/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js index 6fad734ad5781..a1f5a92dcebf0 100644 --- a/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js +++ b/packages/react-reconciler/src/__tests__/ReactNoopRendererAct-test.js @@ -7,13 +7,17 @@ * @jest-environment node */ -// sanity tests for ReactNoop.act() +// sanity tests for act() const React = require('react'); const ReactNoop = require('react-noop-renderer'); const Scheduler = require('scheduler'); +const act = require('jest-react').act; -describe('ReactNoop.act()', () => { +// TODO: These tests are no longer specific to the noop renderer +// implementation. They test the internal implementation we use in the React +// test suite. +describe('internal act()', () => { it('can use act to flush effects', async () => { function App(props) { React.useEffect(props.callback); @@ -21,7 +25,7 @@ describe('ReactNoop.act()', () => { } const calledLog = []; - ReactNoop.act(() => { + act(() => { ReactNoop.render( { @@ -49,7 +53,7 @@ describe('ReactNoop.act()', () => { }, []); return ctr; } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded(['stage 1', 'stage 2']); diff --git a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js index ec6ee2c407ea6..327e72fdc9724 100644 --- a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js +++ b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js @@ -1,6 +1,7 @@ let React; let ReactNoop; let Scheduler; +let act; let LegacyHidden; let Offscreen; let useState; @@ -13,6 +14,7 @@ describe('ReactOffscreen', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; LegacyHidden = React.unstable_LegacyHidden; Offscreen = React.unstable_Offscreen; useState = React.useState; @@ -39,7 +41,7 @@ describe('ReactOffscreen', () => { // Test the initial mount const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); expect(Scheduler).toFlushUntilNextPaint(['Normal']); expect(root).toMatchRenderedOutput(); @@ -53,7 +55,7 @@ describe('ReactOffscreen', () => { ); // Now try after an update - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Normal', 'Deferred']); @@ -64,7 +66,7 @@ describe('ReactOffscreen', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { root.render(); expect(Scheduler).toFlushUntilNextPaint(['Normal']); expect(root).toMatchRenderedOutput( @@ -93,7 +95,7 @@ describe('ReactOffscreen', () => { } const root = ReactNoop.createLegacyRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -116,7 +118,7 @@ describe('ReactOffscreen', () => { ); // Test that the children can be updated - await ReactNoop.act(async () => { + await act(async () => { setState('B'); }); expect(Scheduler).toHaveYielded(['B']); @@ -138,7 +140,7 @@ describe('ReactOffscreen', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -162,7 +164,7 @@ describe('ReactOffscreen', () => { ); // Test that the children can be updated - await ReactNoop.act(async () => { + await act(async () => { setState('B'); }); expect(Scheduler).toHaveYielded(['B']); @@ -190,7 +192,7 @@ describe('ReactOffscreen', () => { const root = ReactNoop.createRoot(); // Mount hidden tree. - await ReactNoop.act(async () => { + await act(async () => { root.render( @@ -205,7 +207,7 @@ describe('ReactOffscreen', () => { expect(root).toMatchRenderedOutput(); // Unhide the tree. The layout effect is mounted. - await ReactNoop.act(async () => { + await act(async () => { root.render( @@ -230,7 +232,7 @@ describe('ReactOffscreen', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( @@ -241,7 +243,7 @@ describe('ReactOffscreen', () => { expect(root).toMatchRenderedOutput(); // Hide the tree. The layout effect is unmounted. - await ReactNoop.act(async () => { + await act(async () => { root.render( @@ -255,7 +257,7 @@ describe('ReactOffscreen', () => { expect(root).toMatchRenderedOutput(); // Unhide the tree. The layout effect is re-mounted. - await ReactNoop.act(async () => { + await act(async () => { root.render( @@ -280,7 +282,7 @@ describe('ReactOffscreen', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { // Start the tree hidden. The layout effect is not mounted. root.render( @@ -295,7 +297,7 @@ describe('ReactOffscreen', () => { expect(root).toMatchRenderedOutput(); // Show the tree. The layout effect is mounted. - await ReactNoop.act(async () => { + await act(async () => { root.render( @@ -306,7 +308,7 @@ describe('ReactOffscreen', () => { expect(root).toMatchRenderedOutput(); // Hide the tree again. The layout effect is un-mounted. - await ReactNoop.act(async () => { + await act(async () => { root.render( diff --git a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js index 5f527d75755a7..fc315ae0da87b 100644 --- a/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSchedulerIntegration-test.js @@ -13,6 +13,7 @@ let React; let ReactNoop; let Scheduler; +let act; let NormalPriority; let IdlePriority; let runWithPriority; @@ -25,6 +26,7 @@ describe('ReactSchedulerIntegration', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; NormalPriority = Scheduler.unstable_NormalPriority; IdlePriority = Scheduler.unstable_IdlePriority; runWithPriority = Scheduler.unstable_runWithPriority; @@ -71,11 +73,11 @@ describe('ReactSchedulerIntegration', () => { }); return null; } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -139,7 +141,7 @@ describe('ReactSchedulerIntegration', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); // Commit the visible content @@ -244,7 +246,7 @@ describe( return null; } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); expect(Scheduler).toFlushUntilNextPaint([]); expect(Scheduler).toFlushUntilNextPaint([]); @@ -273,7 +275,7 @@ describe( ); } - await ReactNoop.act(async () => { + await act(async () => { // Partially render the tree, then yield startTransition(() => { ReactNoop.render(); diff --git a/packages/react-reconciler/src/__tests__/ReactSubtreeFlagsWarning-test.js b/packages/react-reconciler/src/__tests__/ReactSubtreeFlagsWarning-test.js index c2c872dc41fae..8dd183fd4e42f 100644 --- a/packages/react-reconciler/src/__tests__/ReactSubtreeFlagsWarning-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSubtreeFlagsWarning-test.js @@ -1,6 +1,7 @@ let React; let ReactNoop; let Scheduler; +let act; let Suspense; let useEffect; let getCacheForType; @@ -15,6 +16,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; Suspense = React.Suspense; useEffect = React.useEffect; @@ -155,7 +157,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // On initial mount, the suspended component is committed in an incomplete // state, without a passive static effect flag. - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Suspend! [Async]']); @@ -164,7 +166,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // When the promise resolves, a passive static effect flag is added. In the // regression, the "missing expected static flag" would fire, because the // previous fiber did not have one. - await ReactNoop.act(async () => { + await act(async () => { resolveText('Async'); }); expect(Scheduler).toHaveYielded(['Async', 'Effect']); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js index e7e167972404f..e00f5e119c5b1 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js @@ -19,7 +19,7 @@ describe('ReactSuspense', () => { ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; React = require('react'); ReactTestRenderer = require('react-test-renderer'); - act = ReactTestRenderer.unstable_concurrentAct; + act = require('jest-react').act; Scheduler = require('scheduler'); ReactCache = require('react-cache'); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseEffectsSemantics-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseEffectsSemantics-test.js index 1cf5d3014f882..b081f82e332c4 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseEffectsSemantics-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseEffectsSemantics-test.js @@ -10,6 +10,7 @@ let React; let ReactNoop; let Scheduler; +let act; let Suspense; let getCacheForType; let caches; @@ -23,6 +24,7 @@ describe('ReactSuspenseEffectsSemantics', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; Suspense = React.Suspense; getCacheForType = React.unstable_getCacheForType; @@ -253,7 +255,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount and suspend. - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( @@ -280,7 +282,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -302,7 +304,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Outside'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -370,7 +372,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount and suspend. - ReactNoop.act(() => { + act(() => { ReactNoop.renderLegacySyncRoot( @@ -402,7 +404,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -419,7 +421,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Outside'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.renderLegacySyncRoot(null); }); expect(Scheduler).toHaveYielded([ @@ -467,7 +469,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - ReactNoop.act(() => { + act(() => { ReactNoop.renderLegacySyncRoot(); }); expect(Scheduler).toHaveYielded([ @@ -491,7 +493,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - ReactNoop.act(() => { + act(() => { ReactNoop.renderLegacySyncRoot( @@ -527,7 +529,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -544,7 +546,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Outside'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.renderLegacySyncRoot(null); }); expect(Scheduler).toHaveYielded([ @@ -590,7 +592,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -614,7 +616,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - ReactNoop.act(() => { + act(() => { ReactNoop.render( @@ -652,7 +654,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -673,7 +675,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Outside'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -742,7 +744,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -763,7 +765,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - ReactNoop.act(() => { + act(() => { ReactNoop.render( @@ -801,7 +803,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -821,7 +823,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Outside'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -863,7 +865,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -880,7 +882,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([span('Outer', [span('Inner')])]); // Schedule an update that causes React to suspend. - ReactNoop.act(() => { + act(() => { ReactNoop.render( @@ -911,7 +913,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -930,7 +932,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Outer', [span('Inner')]), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -975,7 +977,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -994,7 +996,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - ReactNoop.act(() => { + act(() => { ReactNoop.render( @@ -1028,7 +1030,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -1046,7 +1048,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Outer', [span('MemoizedInner')]), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -1078,7 +1080,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -1092,7 +1094,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([span('Outer'), span('Inner')]); // Suspend the inner Suspense subtree (only inner effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } />, ); @@ -1115,7 +1117,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Suspend the outer Suspense subtree (outer effects and inner fallback effects should be destroyed) // (This check also ensures we don't destroy effects for mounted inner fallback.) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } @@ -1144,7 +1146,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Show the inner Susepnse subtree (no effects should be recreated) - await ReactNoop.act(async () => { + await act(async () => { await resolveText('InnerAsync_1'); }); expect(Scheduler).toHaveYielded([ @@ -1161,7 +1163,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Suspend the inner Suspense subtree (no effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } @@ -1186,7 +1188,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Show the outer Susepnse subtree (only outer effects should be recreated) - await ReactNoop.act(async () => { + await act(async () => { await resolveText('OuterAsync_1'); }); expect(Scheduler).toHaveYielded([ @@ -1210,7 +1212,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Show the inner Susepnse subtree (only inner effects should be recreated) - await ReactNoop.act(async () => { + await act(async () => { await resolveText('InnerAsync_2'); }); expect(Scheduler).toHaveYielded([ @@ -1230,7 +1232,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Suspend the outer Suspense subtree (all effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } @@ -1260,7 +1262,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Show the outer Suspense subtree (all effects should be recreated) - await ReactNoop.act(async () => { + await act(async () => { await resolveText('OuterAsync_2'); }); expect(Scheduler).toHaveYielded([ @@ -1301,7 +1303,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -1315,7 +1317,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([span('Outer'), span('Inner')]); // Suspend the inner Suspense subtree (only inner effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } />, ); @@ -1338,7 +1340,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Suspend the outer Suspense subtree (outer effects and inner fallback effects should be destroyed) // (This check also ensures we don't destroy effects for mounted inner fallback.) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } @@ -1367,7 +1369,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolve both suspended trees. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('OuterAsync_1'); await resolveText('InnerAsync_1'); }); @@ -1419,7 +1421,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -1436,7 +1438,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Suspend the outer shell - ReactNoop.act(() => { + act(() => { ReactNoop.render( } />, ); @@ -1472,7 +1474,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Suspend the fallback and verify that it's effects get cleaned up as well - ReactNoop.act(() => { + act(() => { ReactNoop.render( } @@ -1514,7 +1516,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving both resources should cleanup fallabck effects and recreate main effects - await ReactNoop.act(async () => { + await act(async () => { await resolveText('FallbackAsync'); await resolveText('OutsideAsync'); }); @@ -1562,7 +1564,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -1579,7 +1581,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Suspend both the outer boundary and the fallback - ReactNoop.act(() => { + act(() => { ReactNoop.render( } @@ -1612,7 +1614,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the inside fallback - await ReactNoop.act(async () => { + await act(async () => { await resolveText('FallbackAsync'); }); expect(Scheduler).toHaveYielded([ @@ -1634,7 +1636,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the outer fallback only - await ReactNoop.act(async () => { + await act(async () => { await resolveText('OutsideAsync'); }); expect(Scheduler).toHaveYielded([ @@ -1679,7 +1681,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -1697,7 +1699,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Suspending a component in the middle of the tree // should still properly cleanup effects deeper in the tree - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -1724,7 +1726,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving should cleanup. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Suspend'); }); expect(Scheduler).toHaveYielded([ @@ -1783,7 +1785,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -1810,7 +1812,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -1841,7 +1843,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Resolve the pending suspense and throw componentDidMountShouldThrow = true; - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -1920,7 +1922,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -1947,7 +1949,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that suspends and triggers our error code. - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -2036,7 +2038,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -2063,7 +2065,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -2094,7 +2096,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Resolve the pending suspense and throw useLayoutEffectShouldThrow = true; - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -2172,7 +2174,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -2199,7 +2201,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that suspends and triggers our error code. - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -2279,7 +2281,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -2295,7 +2297,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - ReactNoop.act(() => { + act(() => { ReactNoop.render( @@ -2330,7 +2332,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async_1'); }); expect(Scheduler).toHaveYielded([ @@ -2346,7 +2348,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async_2'); }); expect(Scheduler).toHaveYielded([ @@ -2369,7 +2371,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Class'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -2428,7 +2430,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -2447,7 +2449,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Schedule an update that causes React to suspend. textToRead = 'A'; - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -2480,7 +2482,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Resolving the suspended resource should re-create inner layout effects. textToRead = 'B'; - await ReactNoop.act(async () => { + await act(async () => { await resolveText('A'); }); expect(Scheduler).toHaveYielded([ @@ -2497,7 +2499,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('B'); }); expect(Scheduler).toHaveYielded([ @@ -2514,7 +2516,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('Class'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -2602,7 +2604,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - ReactNoop.act(() => { + act(() => { ReactNoop.renderLegacySyncRoot(); }); expect(Scheduler).toHaveYielded([ @@ -2620,7 +2622,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([]); // Suspend the inner Suspense subtree (only inner effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.renderLegacySyncRoot( } />, ); @@ -2641,7 +2643,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([span('Fallback')]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -2653,7 +2655,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); expect(ReactNoop.getChildren()).toEqual([span('Async')]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.renderLegacySyncRoot(null); }); expect(Scheduler).toHaveYielded([ @@ -2681,7 +2683,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -2700,7 +2702,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Suspend the inner Suspense subtree (only inner effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } />, ); @@ -2726,7 +2728,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -2750,7 +2752,7 @@ describe('ReactSuspenseEffectsSemantics', () => { span('refCallback'), ]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -2787,7 +2789,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -2805,7 +2807,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([]); // Suspend the inner Suspense subtree (only inner effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } />, ); @@ -2829,7 +2831,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([span('Fallback')]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -2851,7 +2853,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); expect(ReactNoop.getChildren()).toEqual([span('Async')]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -2892,7 +2894,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -2910,7 +2912,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([]); // Suspend the inner Suspense subtree (only inner effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } />, ); @@ -2934,7 +2936,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([span('Fallback')]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -2956,7 +2958,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); expect(ReactNoop.getChildren()).toEqual([span('Async')]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -3011,7 +3013,7 @@ describe('ReactSuspenseEffectsSemantics', () => { } // Mount - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded([ @@ -3023,7 +3025,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([]); // Suspend the inner Suspense subtree (only inner effects should be destroyed) - ReactNoop.act(() => { + act(() => { ReactNoop.render( } />, ); @@ -3040,7 +3042,7 @@ describe('ReactSuspenseEffectsSemantics', () => { expect(ReactNoop.getChildren()).toEqual([span('Fallback')]); // Resolving the suspended resource should re-create inner layout effects. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ @@ -3055,7 +3057,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); expect(ReactNoop.getChildren()).toEqual([span('Async')]); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(null); }); expect(Scheduler).toHaveYielded([ @@ -3107,7 +3109,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -3134,7 +3136,7 @@ describe('ReactSuspenseEffectsSemantics', () => { ]); // Schedule an update that causes React to suspend. - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render( }> @@ -3165,7 +3167,7 @@ describe('ReactSuspenseEffectsSemantics', () => { // Resolve the pending suspense and throw useRefCallbackShouldThrow = true; - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Async'); }); expect(Scheduler).toHaveYielded([ diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js index a0a0d08a2c42b..957d5f37c70f2 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseFuzz-test.internal.js @@ -2,6 +2,7 @@ let React; let Suspense; let ReactNoop; let Scheduler; +let act; let ReactFeatureFlags; let Random; @@ -27,6 +28,7 @@ describe('ReactSuspenseFuzz', () => { Suspense = React.Suspense; ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; Random = require('random-seed'); }); @@ -143,7 +145,11 @@ describe('ReactSuspenseFuzz', () => { if ((elapsedTime += 1000) > 1000000) { throw new Error('Something did not resolve properly.'); } - ReactNoop.act(() => jest.advanceTimersByTime(1000)); + act(() => { + ReactNoop.batchedUpdates(() => { + jest.advanceTimersByTime(1000); + }); + }); Scheduler.unstable_flushAllWithoutAsserting(); } } diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js index f50b3a6a7e440..ddd20f35edad7 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseList-test.js @@ -1,6 +1,7 @@ let React; let ReactNoop; let Scheduler; +let act; let Profiler; let Suspense; let SuspenseList; @@ -12,6 +13,7 @@ describe('ReactSuspenseList', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; Profiler = React.Profiler; Suspense = React.Suspense; SuspenseList = React.SuspenseList; @@ -284,7 +286,7 @@ describe('ReactSuspenseList', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { C.resolve(); }); @@ -298,7 +300,7 @@ describe('ReactSuspenseList', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { B.resolve(); }); @@ -2203,7 +2205,7 @@ describe('ReactSuspenseList', () => { ); // Update the row adjacent to the list - ReactNoop.act(() => updateAdjacent('C')); + act(() => updateAdjacent('C')); expect(Scheduler).toHaveYielded(['C']); @@ -2259,7 +2261,7 @@ describe('ReactSuspenseList', () => { const previousInst = setAsyncB; // During an update we suspend on B. - ReactNoop.act(() => setAsyncB(true)); + act(() => setAsyncB(true)); expect(Scheduler).toHaveYielded([ 'Suspend! [B]', @@ -2277,7 +2279,7 @@ describe('ReactSuspenseList', () => { // Before we resolve we'll rerender the whole list. // This should leave the tree intact. - ReactNoop.act(() => ReactNoop.render()); + act(() => ReactNoop.render()); expect(Scheduler).toHaveYielded(['A', 'Suspend! [B]', 'Loading B']); @@ -2347,7 +2349,7 @@ describe('ReactSuspenseList', () => { const previousInst = setAsyncB; // During an update we suspend on B. - ReactNoop.act(() => setAsyncB(true)); + act(() => setAsyncB(true)); expect(Scheduler).toHaveYielded([ 'Suspend! [B]', @@ -2365,7 +2367,7 @@ describe('ReactSuspenseList', () => { // Before we resolve we'll rerender the whole list. // This should leave the tree intact. - ReactNoop.act(() => ReactNoop.render()); + act(() => ReactNoop.render()); expect(Scheduler).toHaveYielded(['A', 'Suspend! [B]', 'Loading B']); @@ -2425,7 +2427,7 @@ describe('ReactSuspenseList', () => { expect(ReactNoop).toMatchRenderedOutput(null); - await ReactNoop.act(async () => { + await act(async () => { // Add a few items at the end. if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js index 4110772513b8b..fdd1a46dbb1e3 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js @@ -2,6 +2,7 @@ let React; let Fragment; let ReactNoop; let Scheduler; +let act; let Suspense; let getCacheForType; @@ -16,6 +17,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { Fragment = React.Fragment; ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; Suspense = React.Suspense; getCacheForType = React.unstable_getCacheForType; @@ -671,14 +673,14 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Mount the Suspense boundary without suspending, so that the subsequent // updates suspend with a delay. - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); await advanceTimers(1000); expect(Scheduler).toHaveYielded(['Sibling', 'Step 0']); // Schedule an update at several distinct expiration times - await ReactNoop.act(async () => { + await act(async () => { if (gate(flags => flags.enableSyncDefaultUpdates)) { React.startTransition(() => { root.render(); @@ -1228,7 +1230,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toHaveYielded(['Suspend! [Result]', 'Loading...']); expect(ReactNoop.getChildren()).toEqual([span('Loading...')]); - await ReactNoop.act(async () => { + await act(async () => { resolveText('Result'); }); @@ -1298,7 +1300,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { resolveText('Step: 2'); }); expect(Scheduler).toHaveYielded(['Step: 2']); @@ -1371,7 +1373,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { resolveText('B'); }); @@ -1417,7 +1419,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ]); expect(ReactNoop.getChildren()).toEqual([span('Loading...')]); - await ReactNoop.act(async () => { + await act(async () => { resolveText('Hi'); }); @@ -1464,7 +1466,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { 'Loading...', ]); expect(ReactNoop.getChildren()).toEqual([span('Loading...')]); - await ReactNoop.act(async () => { + await act(async () => { resolveText('Hi'); }); expect(Scheduler).toHaveYielded(['Hi']); @@ -1510,7 +1512,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ]); - await ReactNoop.act(async () => { + await act(async () => { resolveText('Hi'); }); expect(Scheduler).toHaveYielded(['Hi']); @@ -1553,7 +1555,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { 'Child is hidden: true', ]); - await ReactNoop.act(async () => { + await act(async () => { resolveText('Hi'); }); @@ -1626,20 +1628,20 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createLegacyRoot(null); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Mount']); expect(root).toMatchRenderedOutput('Child'); // Suspend the child. This puts it into an inconsistent state. - await ReactNoop.act(async () => { + await act(async () => { setShouldSuspend(true); }); expect(root).toMatchRenderedOutput('Loading...'); // Unmount everying - await ReactNoop.act(async () => { + await act(async () => { root.render(null); }); expect(Scheduler).toHaveYielded(['Unmount']); @@ -1801,7 +1803,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { resolveText('B'); }); @@ -1837,7 +1839,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { 'Effect [Loading...]', ]); - await ReactNoop.act(async () => { + await act(async () => { resolveText('B2'); }); @@ -2091,12 +2093,12 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); // TODO: assert toErrorDev() when the warning is implemented again. - ReactNoop.act(() => { + act(() => { ReactNoop.flushSync(() => _setShow(true)); }); }); @@ -2118,12 +2120,12 @@ describe('ReactSuspenseWithNoopRenderer', () => { } } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); // TODO: assert toErrorDev() when the warning is implemented again. - ReactNoop.act(() => { + act(() => { ReactNoop.flushSync(() => show()); }); }); @@ -2145,14 +2147,14 @@ describe('ReactSuspenseWithNoopRenderer', () => { } } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded(['Suspend! [A]']); expect(ReactNoop).toMatchRenderedOutput('Loading...'); - ReactNoop.act(() => { + act(() => { ReactNoop.flushSync(() => showB()); }); @@ -2178,12 +2180,12 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); // TODO: assert toErrorDev() when the warning is implemented again. - ReactNoop.act(() => { + act(() => { ReactNoop.flushSync(() => _setShow(true)); }); }, @@ -2205,12 +2207,12 @@ describe('ReactSuspenseWithNoopRenderer', () => { } } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); // also make sure lowpriority is okay - await ReactNoop.act(async () => show(true)); + await act(async () => show(true)); expect(Scheduler).toHaveYielded(['Suspend! [A]']); await resolveText('A'); @@ -2231,12 +2233,12 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.render(); }); // also make sure lowpriority is okay - await ReactNoop.act(async () => _setShow(true)); + await act(async () => _setShow(true)); expect(Scheduler).toHaveYielded(['Suspend! [A]']); await resolveText('A'); @@ -2499,7 +2501,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toFlushAndYield([]); // Initial render. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('A')); expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']); @@ -2515,7 +2517,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(ReactNoop.getChildren()).toEqual([span('A')]); // Start transition. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('B')); expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']); @@ -2554,7 +2556,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toFlushAndYield([]); // Initial render. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('A')); expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']); @@ -2570,7 +2572,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(ReactNoop.getChildren()).toEqual([span('A')]); // Start transition. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('B')); expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']); @@ -2658,7 +2660,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toFlushAndYield([]); // Initial render. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('A')); expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']); @@ -2674,7 +2676,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(ReactNoop.getChildren()).toEqual([span('A')]); // Start transition. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('B')); expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']); @@ -2692,7 +2694,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(ReactNoop.getChildren()).toEqual([span('B')]); // Start a long (infinite) transition. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('C')); expect(Scheduler).toFlushAndYield(['Suspend! [C]', 'Loading...']); @@ -2728,7 +2730,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toFlushAndYield([]); // Initial render. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('A')); expect(Scheduler).toFlushAndYield(['Suspend! [A]', 'Loading...']); @@ -2744,7 +2746,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(ReactNoop.getChildren()).toEqual([span('A')]); // Start transition. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('B')); expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']); @@ -2761,7 +2763,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(ReactNoop.getChildren()).toEqual([span('B')]); // Start a long (infinite) transition. - await ReactNoop.act(async () => { + await act(async () => { React.startTransition(() => transitionToPage('C')); expect(Scheduler).toFlushAndYield(['Suspend! [C]', 'Loading...']); @@ -2884,19 +2886,19 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Suspend! [Initial]']); // Resolve initial render - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Initial'); }); expect(Scheduler).toHaveYielded(['Initial']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { // Update. Since showing a fallback would hide content that's already // visible, it should suspend for a JND without committing. if (gate(flags => flags.enableSyncDefaultUpdates)) { @@ -2953,13 +2955,13 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Foo']); - await ReactNoop.act(async () => { + await act(async () => { foo.setState({suspend: true}); // In the regression that this covers, we would neglect to reset the @@ -3110,13 +3112,13 @@ describe('ReactSuspenseWithNoopRenderer', () => { } await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { // Schedule two updates that originate inside the Suspense boundary. // The first one causes the boundary to suspend. The second one is at // lower priority and unsuspends the tree. @@ -3164,13 +3166,13 @@ describe('ReactSuspenseWithNoopRenderer', () => { } await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { // Schedule two updates that originate inside the Suspense boundary. // The first one causes the boundary to suspend. The second one is at // lower priority and unsuspends it by hiding the async component. @@ -3233,13 +3235,13 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Resolve the initial tree await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { // Schedule an update inside the Suspense boundary that suspends. setAppText('B'); expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']); @@ -3255,7 +3257,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Schedule a default pri update on the boundary, and a lower pri update // on the fallback. We're testing to make sure the fallback can still // update even though the primary tree is suspended. - await ReactNoop.act(async () => { + await act(async () => { setAppText('C'); React.startTransition(() => { setFallbackText('Still loading...'); @@ -3318,7 +3320,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Mount an initial tree. Resolve A so that it doesn't suspend. await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A']); @@ -3327,7 +3329,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Schedule another update. This will "flip" the alternate pairs. await resolveText('B'); - await ReactNoop.act(async () => { + await act(async () => { setText('B'); }); expect(Scheduler).toHaveYielded(['B']); @@ -3335,14 +3337,14 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(root).toMatchRenderedOutput(); // Schedule another update. This time, we'll suspend. - await ReactNoop.act(async () => { + await act(async () => { setText('C'); }); expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']); // Commit. This will insert a fragment fiber to wrap around the component // that triggered the update. - await ReactNoop.act(async () => { + await act(async () => { await advanceTimers(250); }); // The fragment fiber is part of the current tree, but the setState return @@ -3357,7 +3359,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Update again. This should unsuspend the tree. await resolveText('D'); - await ReactNoop.act(async () => { + await act(async () => { setText('D'); }); // Even though the fragment fiber is not part of the return path, we should @@ -3395,7 +3397,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Mount an initial tree. Resolve A so that it doesn't suspend. await seedNextTextCache('A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A']); @@ -3404,7 +3406,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Schedule another update. This will "flip" the alternate pairs. await resolveText('B'); - await ReactNoop.act(async () => { + await act(async () => { setText('B'); }); expect(Scheduler).toHaveYielded(['B']); @@ -3412,14 +3414,14 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(root).toMatchRenderedOutput(); // Schedule another update. This time, we'll suspend. - await ReactNoop.act(async () => { + await act(async () => { setText('C'); }); expect(Scheduler).toHaveYielded(['Suspend! [C]', 'Loading...']); // Commit. This will insert a fragment fiber to wrap around the component // that triggered the update. - await ReactNoop.act(async () => { + await act(async () => { await advanceTimers(250); }); // The fragment fiber is part of the current tree, but the setState return @@ -3432,7 +3434,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { // Schedule a normal pri update. This will suspend again. setText('D'); @@ -3504,7 +3506,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Mount an initial tree. Resolve A so that it doesn't suspend. await seedNextTextCache('Inner text: A'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([ @@ -3524,7 +3526,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Update. This causes the inner component to suspend. - await ReactNoop.act(async () => { + await act(async () => { setText('B'); }); expect(Scheduler).toHaveYielded([ @@ -3547,7 +3549,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Schedule a high pri update on the parent. - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.discreteUpdates(() => { root.render(); }); @@ -3574,7 +3576,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Now finish resolving the inner text - await ReactNoop.act(async () => { + await act(async () => { await resolveText('Inner text: B'); }); expect(Scheduler).toHaveYielded([ @@ -3643,7 +3645,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Mount an initial tree. Resolve A so that it doesn't suspend. await seedNextTextCache('Inner: A0'); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Outer: A0', 'Inner: A0', 'Commit Child']); @@ -3655,7 +3657,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Update. This causes the inner component to suspend. - await ReactNoop.act(async () => { + await act(async () => { setText('B'); }); expect(Scheduler).toHaveYielded([ @@ -3675,7 +3677,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Schedule a high pri update on the parent. This will unblock the content. await resolveText('Inner: B1'); - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.discreteUpdates(() => { root.render(); }); @@ -3731,7 +3733,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { await seedNextTextCache('A'); await seedNextTextCache('B'); root.render(); @@ -3744,7 +3746,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { // Triggers suspense at normal pri setTextA('A1'); // Triggers in an unrelated tree at a different pri @@ -3847,14 +3849,14 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['']); expect(root).toMatchRenderedOutput(); // Update to "a". That will suspend. - await ReactNoop.act(async () => { + await act(async () => { setTextWithShortTransition('a'); expect(Scheduler).toFlushAndYield([ 'Pending...', @@ -3872,7 +3874,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Update to "b". That will suspend, too. - await ReactNoop.act(async () => { + await act(async () => { setTextWithLongTransition('b'); expect(Scheduler).toFlushAndYield([ // Neither is resolved yet. @@ -3891,7 +3893,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Resolve "a". But "b" is still pending. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('a'); expect(Scheduler).toFlushAndYield(['Suspend! [b]', 'Loading...']); @@ -3903,7 +3905,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); // Resolve "b". This should remove the pending state. - await ReactNoop.act(async () => { + await act(async () => { await resolveText('b'); }); expect(Scheduler).toHaveYielded(['b']); @@ -3924,7 +3926,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { await seedNextTextCache('A'); root.render( }> @@ -3935,7 +3937,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toHaveYielded(['A']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { setText('B'); ReactNoop.idleUpdates(() => { setText('B'); @@ -3951,7 +3953,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { expect(Scheduler).toFlushAndYield(['Suspend! [B]']); }); - await ReactNoop.act(async () => { + await act(async () => { setText('B'); await resolveText('B'); }); @@ -3971,7 +3973,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> @@ -3989,7 +3991,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { // Resolve the promise. This will trigger a retry. await resolveText('Async'); // Before the retry happens, schedule a new update. @@ -4039,13 +4041,13 @@ describe('ReactSuspenseWithNoopRenderer', () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Mount Child']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Suspend! [Async]', 'Loading...']); @@ -4056,7 +4058,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { root.render(null); }); expect(Scheduler).toHaveYielded(['Unmount Child']); @@ -4087,13 +4089,13 @@ describe('ReactSuspenseWithNoopRenderer', () => { const root = ReactNoop.createLegacyRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Mount Child']); expect(root).toMatchRenderedOutput(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['Suspend! [Async]', 'Loading...']); @@ -4104,7 +4106,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { , ); - await ReactNoop.act(async () => { + await act(async () => { root.render(null); }); expect(Scheduler).toHaveYielded(['Unmount Child']); diff --git a/packages/react-reconciler/src/__tests__/ReactTransition-test.js b/packages/react-reconciler/src/__tests__/ReactTransition-test.js index cc6d0d00fc6ef..4443b15f6db33 100644 --- a/packages/react-reconciler/src/__tests__/ReactTransition-test.js +++ b/packages/react-reconciler/src/__tests__/ReactTransition-test.js @@ -36,7 +36,7 @@ describe('ReactTransition', () => { Suspense = React.Suspense; startTransition = React.startTransition; getCacheForType = React.unstable_getCacheForType; - act = ReactNoop.act; + act = require('jest-react').act; caches = []; seededCache = null; @@ -551,7 +551,7 @@ describe('ReactTransition', () => { test('interrupt a refresh transition if a new transition is scheduled', async () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render( <> } /> @@ -562,7 +562,7 @@ describe('ReactTransition', () => { expect(Scheduler).toHaveYielded(['Initial']); expect(root).toMatchRenderedOutput('Initial'); - await ReactNoop.act(async () => { + await act(async () => { // Start a refresh transition startTransition(() => { root.render( @@ -729,13 +729,13 @@ describe('ReactTransition', () => { const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A0', 'B0', 'C0']); expect(root).toMatchRenderedOutput('A0B0C0'); - await ReactNoop.act(async () => { + await act(async () => { // This update will suspend. startTransition(() => { root.render(); @@ -911,7 +911,7 @@ describe('ReactTransition', () => { } const root = ReactNoop.createRoot(); - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded([ @@ -921,7 +921,7 @@ describe('ReactTransition', () => { ]); expect(root).toMatchRenderedOutput('Transition pri: 0, Normal pri: 0'); - await ReactNoop.act(async () => { + await act(async () => { updateTransitionPri(); expect(Scheduler).toFlushAndYieldThrough([ diff --git a/packages/react-reconciler/src/__tests__/ReactUpdatePriority-test.js b/packages/react-reconciler/src/__tests__/ReactUpdatePriority-test.js index 918dd97983366..a63beb1ed5db7 100644 --- a/packages/react-reconciler/src/__tests__/ReactUpdatePriority-test.js +++ b/packages/react-reconciler/src/__tests__/ReactUpdatePriority-test.js @@ -5,6 +5,7 @@ let ContinuousEventPriority; let startTransition; let useState; let useEffect; +let act; describe('ReactUpdatePriority', () => { beforeEach(() => { @@ -13,6 +14,7 @@ describe('ReactUpdatePriority', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; ContinuousEventPriority = require('react-reconciler/constants') .ContinuousEventPriority; startTransition = React.startTransition; @@ -36,7 +38,7 @@ describe('ReactUpdatePriority', () => { return ; } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.flushSync(() => { root.render(); }); @@ -61,7 +63,7 @@ describe('ReactUpdatePriority', () => { return ; } - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.idleUpdates(() => { root.render(); }); @@ -106,13 +108,13 @@ describe('ReactUpdatePriority', () => { ); } - await ReactNoop.act(async () => { + await act(async () => { root.render(); }); expect(Scheduler).toHaveYielded(['A1', 'B1', 'C1']); expect(root).toMatchRenderedOutput('A1B1C1'); - await ReactNoop.act(async () => { + await act(async () => { startTransition(() => { setCounter(2); }); diff --git a/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js b/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js index 66dd7d12b4927..7770c070667d6 100644 --- a/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactUpdaters-test.internal.js @@ -12,7 +12,6 @@ let React; let ReactFeatureFlags; let ReactDOM; -let ReactTestUtils; let Scheduler; let mockDevToolsHook; let allSchedulerTags; @@ -65,10 +64,9 @@ describe('updaters', () => { React = require('react'); ReactDOM = require('react-dom'); - ReactTestUtils = require('react-dom/test-utils'); Scheduler = require('scheduler'); - act = ReactTestUtils.unstable_concurrentAct; + act = require('jest-react').act; }); it('should report the (host) root as the scheduler for root-level render', async () => { diff --git a/packages/react-reconciler/src/__tests__/SchedulingProfiler-test.internal.js b/packages/react-reconciler/src/__tests__/SchedulingProfiler-test.internal.js index 77e7726a18a1d..b5d544d0a48d7 100644 --- a/packages/react-reconciler/src/__tests__/SchedulingProfiler-test.internal.js +++ b/packages/react-reconciler/src/__tests__/SchedulingProfiler-test.internal.js @@ -26,6 +26,7 @@ describe('SchedulingProfiler', () => { let ReactTestRenderer; let ReactNoop; let Scheduler; + let act; let clearedMarks; let featureDetectionMarkName = null; @@ -86,6 +87,7 @@ describe('SchedulingProfiler', () => { ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; const SchedulingProfiler = require('react-reconciler/src/SchedulingProfiler'); formatLanes = SchedulingProfiler.formatLanes; @@ -518,7 +520,7 @@ describe('SchedulingProfiler', () => { return didMount; } - ReactTestRenderer.unstable_concurrentAct(() => { + act(() => { ReactTestRenderer.create(, {unstable_isConcurrent: true}); }); @@ -553,7 +555,7 @@ describe('SchedulingProfiler', () => { return didRender; } - ReactTestRenderer.unstable_concurrentAct(() => { + act(() => { ReactTestRenderer.create(, {unstable_isConcurrent: true}); }); diff --git a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js index 13f7a9ac543c2..a6210a82e3569 100644 --- a/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js +++ b/packages/react-reconciler/src/__tests__/StrictEffectsMode-test.js @@ -20,7 +20,7 @@ describe('StrictEffectsMode', () => { React = require('react'); ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); - act = ReactTestRenderer.unstable_concurrentAct; + act = require('jest-react').act; }); function supportsDoubleInvokeEffects() { diff --git a/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js b/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js index 469f43348beaf..e443aa0a23190 100644 --- a/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js +++ b/packages/react-reconciler/src/__tests__/StrictEffectsModeDefaults-test.internal.js @@ -12,6 +12,7 @@ let React; let ReactNoop; let Scheduler; +let act; describe('StrictEffectsMode defaults', () => { beforeEach(() => { @@ -20,6 +21,7 @@ describe('StrictEffectsMode defaults', () => { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); + act = require('jest-react').act; const ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.enableStrictEffects = __DEV__; @@ -41,7 +43,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - ReactNoop.act(() => { + act(() => { ReactNoop.renderLegacySyncRoot(); }); @@ -70,7 +72,7 @@ describe('StrictEffectsMode defaults', () => { } } - ReactNoop.act(() => { + act(() => { ReactNoop.renderLegacySyncRoot(); }); @@ -89,7 +91,7 @@ describe('StrictEffectsMode defaults', () => { return label; } - ReactNoop.act(() => { + act(() => { ReactNoop.render( <> @@ -103,7 +105,7 @@ describe('StrictEffectsMode defaults', () => { ]); }); - ReactNoop.act(() => { + act(() => { ReactNoop.render( <> @@ -143,7 +145,7 @@ describe('StrictEffectsMode defaults', () => { return label; } - ReactNoop.act(() => { + act(() => { ReactNoop.render( <> @@ -162,7 +164,7 @@ describe('StrictEffectsMode defaults', () => { ]); }); - ReactNoop.act(() => { + act(() => { ReactNoop.render( <> @@ -204,7 +206,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -217,7 +219,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -228,7 +230,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(null); }); @@ -253,7 +255,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -266,7 +268,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect Two mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -277,7 +279,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect Two mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(null); }); @@ -304,7 +306,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -317,7 +319,7 @@ describe('StrictEffectsMode defaults', () => { 'useLayoutEffect Two mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -328,7 +330,7 @@ describe('StrictEffectsMode defaults', () => { 'useLayoutEffect Two mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(null); }); @@ -351,7 +353,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -362,7 +364,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -371,7 +373,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(null); }); @@ -402,7 +404,7 @@ describe('StrictEffectsMode defaults', () => { } } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -432,7 +434,7 @@ describe('StrictEffectsMode defaults', () => { } } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -442,13 +444,13 @@ describe('StrictEffectsMode defaults', () => { 'componentDidMount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); expect(Scheduler).toHaveYielded(['componentDidUpdate']); - ReactNoop.act(() => { + act(() => { ReactNoop.render(null); }); @@ -475,7 +477,7 @@ describe('StrictEffectsMode defaults', () => { return text; } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -527,7 +529,7 @@ describe('StrictEffectsMode defaults', () => { return showChild && ; } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -540,7 +542,7 @@ describe('StrictEffectsMode defaults', () => { 'App useEffect mount', ]); - ReactNoop.act(() => { + act(() => { _setShowChild(true); }); @@ -594,7 +596,7 @@ describe('StrictEffectsMode defaults', () => { ); } - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -610,7 +612,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(); }); @@ -621,7 +623,7 @@ describe('StrictEffectsMode defaults', () => { 'useEffect mount', ]); - ReactNoop.act(() => { + act(() => { ReactNoop.render(null); }); diff --git a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js index 47f9181105552..1b56f3fc125cd 100644 --- a/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js +++ b/packages/react-reconciler/src/__tests__/useMutableSource-test.internal.js @@ -30,7 +30,7 @@ function loadModules() { React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); - act = ReactNoop.act; + act = require('jest-react').act; // Stable entrypoints export with "unstable_" prefix. createMutableSource = @@ -1443,7 +1443,7 @@ describe('useMutableSource', () => { // Now mutate A. Both hooks should update. // This is at high priority so that it doesn't get batched with default // priority updates that might fire during the passive effect - await ReactNoop.act(async () => { + await act(async () => { ReactNoop.discreteUpdates(() => { mutateA('a1'); }); diff --git a/packages/react-reconciler/src/__tests__/useMutableSourceHydration-test.js b/packages/react-reconciler/src/__tests__/useMutableSourceHydration-test.js index 671a813f37ad0..7f46d1cb00552 100644 --- a/packages/react-reconciler/src/__tests__/useMutableSourceHydration-test.js +++ b/packages/react-reconciler/src/__tests__/useMutableSourceHydration-test.js @@ -26,7 +26,7 @@ describe('useMutableSourceHydration', () => { ReactDOMServer = require('react-dom/server'); Scheduler = require('scheduler'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; // Stable entrypoints export with "unstable_" prefix. createMutableSource = diff --git a/packages/react-reconciler/src/__tests__/useRef-test.internal.js b/packages/react-reconciler/src/__tests__/useRef-test.internal.js index ccfc6d0d4b2ae..ba08d91331050 100644 --- a/packages/react-reconciler/src/__tests__/useRef-test.internal.js +++ b/packages/react-reconciler/src/__tests__/useRef-test.internal.js @@ -31,7 +31,7 @@ describe('useRef', () => { const ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.debugRenderPhaseSideEffectsForStrictMode = false; - act = ReactNoop.act; + act = require('jest-react').act; useCallback = React.useCallback; useEffect = React.useEffect; useLayoutEffect = React.useLayoutEffect; diff --git a/packages/react-refresh/src/__tests__/ReactFresh-test.js b/packages/react-refresh/src/__tests__/ReactFresh-test.js index 8a26c85395f36..0a31aa9c62f72 100644 --- a/packages/react-refresh/src/__tests__/ReactFresh-test.js +++ b/packages/react-refresh/src/__tests__/ReactFresh-test.js @@ -29,7 +29,7 @@ describe('ReactFresh', () => { ReactFreshRuntime.injectIntoGlobalHook(global); ReactDOM = require('react-dom'); Scheduler = require('scheduler'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; createReactClass = require('create-react-class/factory')( React.Component, React.isValidElement, @@ -3782,7 +3782,7 @@ describe('ReactFresh', () => { React = require('react'); ReactDOM = require('react-dom'); Scheduler = require('scheduler'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; // Important! Inject into the global hook *after* ReactDOM runs: ReactFreshRuntime = require('react-refresh/runtime'); diff --git a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js index 231dd6b04219e..09edf1d897288 100644 --- a/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js +++ b/packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js @@ -30,7 +30,7 @@ describe('ReactFreshIntegration', () => { ReactFreshRuntime = require('react-refresh/runtime'); ReactFreshRuntime.injectIntoGlobalHook(global); ReactDOM = require('react-dom'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; container = document.createElement('div'); document.body.appendChild(container); exportsObj = undefined; diff --git a/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js b/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js index 64a3d7645f173..75ac4ef8850a2 100644 --- a/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js +++ b/packages/react-server-dom-relay/src/__tests__/ReactFlightDOMRelay-test.internal.js @@ -18,7 +18,7 @@ describe('ReactFlightDOMRelay', () => { beforeEach(() => { jest.resetModules(); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; React = require('react'); ReactDOM = require('react-dom'); ReactDOMFlightRelayServer = require('react-server-dom-relay/server'); diff --git a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js index 020c06a1fef3b..12a50fce2187e 100644 --- a/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js +++ b/packages/react-server-dom-webpack/src/__tests__/ReactFlightDOM-test.js @@ -36,7 +36,7 @@ describe('ReactFlightDOM', () => { jest.resetModules(); webpackModules = {}; webpackMap = {}; - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; Stream = require('stream'); React = require('react'); ReactDOM = require('react-dom'); diff --git a/packages/react-test-renderer/src/ReactTestRenderer.js b/packages/react-test-renderer/src/ReactTestRenderer.js index 469807090ec62..d8b6b08611fef 100644 --- a/packages/react-test-renderer/src/ReactTestRenderer.js +++ b/packages/react-test-renderer/src/ReactTestRenderer.js @@ -21,7 +21,6 @@ import { flushSync, injectIntoDevTools, batchedUpdates, - IsThisRendererActing, } from 'react-reconciler/src/ReactFiberReconciler'; import {findCurrentFiberUsingSlowPath} from 'react-reconciler/src/ReactFiberTreeReflection'; import { @@ -46,15 +45,11 @@ import invariant from 'shared/invariant'; import isArray from 'shared/isArray'; import getComponentNameFromType from 'shared/getComponentNameFromType'; import ReactVersion from 'shared/ReactVersion'; -import ReactSharedInternals from 'shared/ReactSharedInternals'; -import enqueueTask from 'shared/enqueueTask'; import {getPublicInstance} from './ReactTestHostConfig'; import {ConcurrentRoot, LegacyRoot} from 'react-reconciler/src/ReactRootTags'; import {allowConcurrentByDefault} from 'shared/ReactFeatureFlags'; -const {IsSomeRendererActing, ReactCurrentActQueue} = ReactSharedInternals; - const act_notBatchedInLegacyMode = React.unstable_act; function act(callback: () => Thenable): Thenable { return act_notBatchedInLegacyMode(() => { @@ -62,6 +57,8 @@ function act(callback: () => Thenable): Thenable { }); } +// TODO: Remove from public bundle + type TestRendererOptions = { createNodeMock: (element: React$Element) => any, unstable_isConcurrent: boolean, @@ -601,133 +598,10 @@ injectIntoDevTools({ rendererPackageName: 'react-test-renderer', }); -let actingUpdatesScopeDepth = 0; - -// This version of `act` is only used by our tests. Unlike the public version -// of `act`, it's designed to work identically in both production and -// development. It may have slightly different behavior from the public -// version, too, since our constraints in our test suite are not the same as -// those of developers using React — we're testing React itself, as opposed to -// building an app with React. -// TODO: Migrate our tests to use ReactNoop. Although we would need to figure -// out a solution for Relay, which has some Concurrent Mode tests. -// TODO: Replace the internal "concurrent" implementations of `act` with a -// single shared module. -function unstable_concurrentAct(scope: () => Thenable | void) { - if (Scheduler.unstable_flushAllWithoutAsserting === undefined) { - throw Error( - 'This version of `act` requires a special mock build of Scheduler.', - ); - } - if (setTimeout._isMockFunction !== true) { - throw Error( - "This version of `act` requires Jest's timer mocks " + - '(i.e. jest.useFakeTimers).', - ); - } - - const previousActingUpdatesScopeDepth = actingUpdatesScopeDepth; - const previousIsSomeRendererActing = IsSomeRendererActing.current; - const previousIsThisRendererActing = IsThisRendererActing.current; - IsSomeRendererActing.current = true; - IsThisRendererActing.current = true; - actingUpdatesScopeDepth++; - if (__DEV__ && actingUpdatesScopeDepth === 1) { - ReactCurrentActQueue.disableActWarning = true; - } - - const unwind = () => { - if (__DEV__ && actingUpdatesScopeDepth === 1) { - ReactCurrentActQueue.disableActWarning = false; - } - 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. ', - ); - } - } - }; - - // TODO: This would be way simpler if 1) we required a promise to be - // returned and 2) we could use async/await. Since it's only our used in - // our test suite, we should be able to. - try { - const thenable = batchedUpdates(scope); - if ( - typeof thenable === 'object' && - thenable !== null && - typeof thenable.then === 'function' - ) { - return { - then(resolve: () => void, reject: (error: mixed) => void) { - thenable.then( - () => { - flushActWork( - () => { - unwind(); - resolve(); - }, - error => { - unwind(); - reject(error); - }, - ); - }, - error => { - unwind(); - reject(error); - }, - ); - }, - }; - } else { - try { - // TODO: Let's not support non-async scopes at all in our tests. Need to - // migrate existing tests. - let didFlushWork; - do { - didFlushWork = Scheduler.unstable_flushAllWithoutAsserting(); - } while (didFlushWork); - } finally { - unwind(); - } - } - } catch (error) { - unwind(); - throw error; - } -} - -function flushActWork(resolve, reject) { - // Flush suspended fallbacks - // $FlowFixMe: Flow doesn't know about global Jest object - jest.runOnlyPendingTimers(); - enqueueTask(() => { - try { - const didFlushWork = Scheduler.unstable_flushAllWithoutAsserting(); - if (didFlushWork) { - flushActWork(resolve, reject); - } else { - resolve(); - } - } catch (error) { - reject(error); - } - }); -} - export { Scheduler as _Scheduler, create, /* eslint-disable-next-line camelcase */ batchedUpdates as unstable_batchedUpdates, act, - unstable_concurrentAct, }; diff --git a/packages/react/src/IsSomeRendererActing.js b/packages/react/src/IsSomeRendererActing.js deleted file mode 100644 index b2462fc6c24ce..0000000000000 --- a/packages/react/src/IsSomeRendererActing.js +++ /dev/null @@ -1,17 +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 - */ - -/** - * Used by act() to track whether you're inside an act() scope. - */ - -const IsSomeRendererActing = { - current: (false: boolean), -}; -export default IsSomeRendererActing; diff --git a/packages/react/src/ReactSharedInternals.js b/packages/react/src/ReactSharedInternals.js index e95ea15848751..3443fb276633c 100644 --- a/packages/react/src/ReactSharedInternals.js +++ b/packages/react/src/ReactSharedInternals.js @@ -11,13 +11,11 @@ import ReactCurrentBatchConfig from './ReactCurrentBatchConfig'; import ReactCurrentActQueue from './ReactCurrentActQueue'; import ReactCurrentOwner from './ReactCurrentOwner'; import ReactDebugCurrentFrame from './ReactDebugCurrentFrame'; -import IsSomeRendererActing from './IsSomeRendererActing'; const ReactSharedInternals = { ReactCurrentDispatcher, ReactCurrentBatchConfig, ReactCurrentOwner, - IsSomeRendererActing, // Used by renderers to avoid bundling object-assign twice in UMD bundles: assign, }; diff --git a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee index 24adba7561c6e..3cf0e40b65dbc 100644 --- a/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee +++ b/packages/react/src/__tests__/ReactCoffeeScriptClass-test.coffee @@ -20,7 +20,7 @@ describe 'ReactCoffeeScriptClass', -> beforeEach -> React = require 'react' ReactDOM = require 'react-dom' - act = require('react-dom/test-utils').unstable_concurrentAct + act = require('jest-react').act PropTypes = require 'prop-types' container = document.createElement 'div' root = ReactDOM.createRoot container diff --git a/packages/react/src/__tests__/ReactES6Class-test.js b/packages/react/src/__tests__/ReactES6Class-test.js index 8ce57867fcb0c..3c15930a3798a 100644 --- a/packages/react/src/__tests__/ReactES6Class-test.js +++ b/packages/react/src/__tests__/ReactES6Class-test.js @@ -29,7 +29,7 @@ describe('ReactES6Class', () => { PropTypes = require('prop-types'); React = require('react'); ReactDOM = require('react-dom'); - act = require('react-dom/test-utils').unstable_concurrentAct; + act = require('jest-react').act; container = document.createElement('div'); root = ReactDOM.createRoot(container); attachedListener = null; diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index 18fa18a365e91..af0a920030092 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -15,7 +15,7 @@ let ReactFeatureFlags; let ReactNoop; let Scheduler; let ReactTestRenderer; -let ReactTestRendererAct; +let act; let AdvanceTime; function loadModules({ @@ -36,15 +36,14 @@ function loadModules({ React = require('react'); Scheduler = require('scheduler'); + act = require('jest-react').act; if (useNoopRenderer) { ReactNoop = require('react-noop-renderer'); ReactTestRenderer = null; - ReactTestRendererAct = null; } else { ReactNoop = null; ReactTestRenderer = require('react-test-renderer'); - ReactTestRendererAct = ReactTestRenderer.unstable_concurrentAct; } AdvanceTime = class extends React.Component { @@ -346,7 +345,7 @@ describe(`onRender`, () => { Scheduler.unstable_advanceTime(20); // 30 -> 50 // Updating a sibling should not report a re-render. - ReactTestRendererAct(updateProfilerSibling); + act(updateProfilerSibling); expect(callback).not.toHaveBeenCalled(); }); @@ -672,7 +671,7 @@ describe(`onRender`, () => { const onRender = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( @@ -1641,7 +1640,7 @@ describe(`onCommit`, () => { const setCountRef = React.createRef(null); let renderer = null; - ReactTestRendererAct(() => { + act(() => { renderer = ReactTestRenderer.create( @@ -1668,7 +1667,7 @@ describe(`onCommit`, () => { expect(call[2]).toBe(1010); // durations expect(call[3]).toBe(2); // commit start time (before mutations or effects) - ReactTestRendererAct(() => setCountRef.current(count => count + 1)); + act(() => setCountRef.current(count => count + 1)); expect(callback).toHaveBeenCalledTimes(2); @@ -1680,7 +1679,7 @@ describe(`onCommit`, () => { expect(call[2]).toBe(110); // durations expect(call[3]).toBe(1013); // commit start time (before mutations or effects) - ReactTestRendererAct(() => { + act(() => { renderer.update( @@ -1739,7 +1738,7 @@ describe(`onCommit`, () => { // Test an error that happens during an effect - ReactTestRendererAct(() => { + act(() => { ReactTestRenderer.create( { let renderer = null; - ReactTestRendererAct(() => { + act(() => { renderer = ReactTestRenderer.create( { // Test an error that happens during an cleanup function - ReactTestRendererAct(() => { + act(() => { renderer.update( { Scheduler.unstable_advanceTime(1); let renderer; - ReactTestRendererAct(() => { + act(() => { renderer = ReactTestRenderer.create( @@ -1973,7 +1972,7 @@ describe(`onPostCommit`, () => { Scheduler.unstable_advanceTime(1); - ReactTestRendererAct(() => { + act(() => { renderer.update( @@ -1994,7 +1993,7 @@ describe(`onPostCommit`, () => { Scheduler.unstable_advanceTime(1); - ReactTestRendererAct(() => { + act(() => { renderer.update( , ); @@ -2036,7 +2035,7 @@ describe(`onPostCommit`, () => { Scheduler.unstable_advanceTime(1); - ReactTestRendererAct(() => { + act(() => { ReactTestRenderer.create( @@ -2084,7 +2083,7 @@ describe(`onPostCommit`, () => { const setCountRef = React.createRef(null); let renderer = null; - ReactTestRendererAct(() => { + act(() => { renderer = ReactTestRenderer.create( @@ -2111,7 +2110,7 @@ describe(`onPostCommit`, () => { expect(call[2]).toBe(1010); // durations expect(call[3]).toBe(2); // commit start time (before mutations or effects) - ReactTestRendererAct(() => setCountRef.current(count => count + 1)); + act(() => setCountRef.current(count => count + 1)); expect(callback).toHaveBeenCalledTimes(2); @@ -2123,7 +2122,7 @@ describe(`onPostCommit`, () => { expect(call[2]).toBe(110); // durations expect(call[3]).toBe(1013); // commit start time (before mutations or effects) - ReactTestRendererAct(() => { + act(() => { renderer.update( @@ -2182,7 +2181,7 @@ describe(`onPostCommit`, () => { // Test an error that happens during an effect - ReactTestRendererAct(() => { + act(() => { ReactTestRenderer.create( { let renderer = null; - ReactTestRendererAct(() => { + act(() => { renderer = ReactTestRenderer.create( { // Test an error that happens during an cleanup function - ReactTestRendererAct(() => { + act(() => { renderer.update( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { const onNestedUpdateScheduledTwo = jest.fn(); const onNestedUpdateScheduledThree = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.renderToRootWithID( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { }); expect(Scheduler).toHaveYielded(['Component:false']); - ReactNoop.act(() => { + act(() => { updateFnRef.current(); }); expect(Scheduler).toHaveYielded(['Component:true']); @@ -2633,7 +2632,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1); expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test'); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { expect(Scheduler).toHaveYielded(['Component:false:false']); expect(onNestedUpdateScheduled).not.toHaveBeenCalled(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { const onNestedUpdateScheduled = jest.fn(); - ReactNoop.act(() => { + act(() => { ReactNoop.render( { }); expect(Scheduler).toHaveYielded(['Component:false']); - ReactNoop.act(() => { + act(() => { updateFnRef.current(); }); expect(Scheduler).toHaveYielded(['Component:true']); diff --git a/packages/react/src/__tests__/ReactStrictMode-test.internal.js b/packages/react/src/__tests__/ReactStrictMode-test.internal.js index 62d63f48cd0d8..081be41e1bc88 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.internal.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.internal.js @@ -19,8 +19,7 @@ describe('ReactStrictMode', () => { React = require('react'); ReactDOM = require('react-dom'); - const TestUtils = require('react-dom/test-utils'); - act = TestUtils.unstable_concurrentAct; + act = require('jest-react').act; const ReactFeatureFlags = require('shared/ReactFeatureFlags'); ReactFeatureFlags.enableStrictEffects = __DEV__; diff --git a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts index c0c2da07785e7..d9456404bb5ed 100644 --- a/packages/react/src/__tests__/ReactTypeScriptClass-test.ts +++ b/packages/react/src/__tests__/ReactTypeScriptClass-test.ts @@ -1,7 +1,7 @@ /// /// /// -/// +/// /*! * Copyright (c) Facebook, Inc. and its affiliates. @@ -14,6 +14,7 @@ import React = require('react'); import ReactDOM = require('react-dom'); import ReactDOMTestUtils = require('react-dom/test-utils'); import PropTypes = require('prop-types'); +import internalAct = require('jest-react'); // Before Each @@ -21,7 +22,7 @@ let container; let root; let attachedListener = null; let renderedName = null; -let act = ReactDOMTestUtils.unstable_concurrentAct; +let act = internalAct.act; class Inner extends React.Component { getName() { diff --git a/packages/react/src/__tests__/testDefinitions/ReactDOMTestUtils.d.ts b/packages/react/src/__tests__/testDefinitions/ReactInternalAct.d.ts similarity index 77% rename from packages/react/src/__tests__/testDefinitions/ReactDOMTestUtils.d.ts rename to packages/react/src/__tests__/testDefinitions/ReactInternalAct.d.ts index 49ecaf208e054..8217aab8150f0 100644 --- a/packages/react/src/__tests__/testDefinitions/ReactDOMTestUtils.d.ts +++ b/packages/react/src/__tests__/testDefinitions/ReactInternalAct.d.ts @@ -12,6 +12,6 @@ * just helpers for the unit test. */ -declare module 'react-dom/test-utils' { - export function unstable_concurrentAct(cb : () => any) : any +declare module 'jest-react' { + export function act(cb : () => any) : any } diff --git a/packages/react/src/forks/ReactSharedInternals.umd.js b/packages/react/src/forks/ReactSharedInternals.umd.js index 8082fd0eef033..2620c61d92e6d 100644 --- a/packages/react/src/forks/ReactSharedInternals.umd.js +++ b/packages/react/src/forks/ReactSharedInternals.umd.js @@ -10,13 +10,11 @@ import * as Scheduler from 'scheduler'; import ReactCurrentDispatcher from '../ReactCurrentDispatcher'; import ReactCurrentOwner from '../ReactCurrentOwner'; import ReactDebugCurrentFrame from '../ReactDebugCurrentFrame'; -import IsSomeRendererActing from '../IsSomeRendererActing'; import ReactCurrentBatchConfig from '../ReactCurrentBatchConfig'; const ReactSharedInternals = { ReactCurrentDispatcher, ReactCurrentOwner, - IsSomeRendererActing, ReactCurrentBatchConfig, // Used by renderers to avoid bundling object-assign twice in UMD bundles: assign, diff --git a/packages/use-subscription/src/__tests__/useSubscription-test.js b/packages/use-subscription/src/__tests__/useSubscription-test.js index 579076af551f6..60d6eb20ddfc1 100644 --- a/packages/use-subscription/src/__tests__/useSubscription-test.js +++ b/packages/use-subscription/src/__tests__/useSubscription-test.js @@ -27,7 +27,7 @@ describe('useSubscription', () => { ReactTestRenderer = require('react-test-renderer'); Scheduler = require('scheduler'); - act = ReactTestRenderer.unstable_concurrentAct; + act = require('jest-react').act; BehaviorSubject = require('rxjs').BehaviorSubject; ReplaySubject = require('rxjs').ReplaySubject; diff --git a/scripts/jest/typescript/preprocessor.js b/scripts/jest/typescript/preprocessor.js index d5457ff2ccd76..dbf910754f9b2 100644 --- a/scripts/jest/typescript/preprocessor.js +++ b/scripts/jest/typescript/preprocessor.js @@ -42,7 +42,7 @@ function compile(content, contentFilename) { let source; const libRegex = /lib\.(.+\.)?d\.ts$/; const jestRegex = /jest\.d\.ts/; - const reactRegex = /(?:React|ReactDOM|ReactDOMTestUtils|PropTypes)(?:\.d)?\.ts$/; + const reactRegex = /(?:React|ReactDOM|ReactInternalAct|PropTypes)(?:\.d)?\.ts$/; // `path.normalize` is used to turn forward slashes in // the file path into backslashes on Windows. diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index a19b6510c3ced..fb64c0e6e07f4 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -734,7 +734,7 @@ const bundles = [ moduleType: ISOMORPHIC, entry: 'jest-react', global: 'JestReact', - externals: [], + externals: ['react', 'scheduler', 'scheduler/unstable_mock'], }, /******* ESLint Plugin for Hooks *******/