diff --git a/src/ReactTestRendererAct.js b/src/ReactTestRendererAct.js index 37ced3f..a3d1e4e 100644 --- a/src/ReactTestRendererAct.js +++ b/src/ReactTestRendererAct.js @@ -14,23 +14,42 @@ import { } from 'react-reconciler/inline.test'; import ReactSharedInternals from 'shared/ReactSharedInternals'; import warningWithoutStack from 'shared/warningWithoutStack'; +import {warnAboutMissingMockScheduler} from 'shared/ReactFeatureFlags'; import enqueueTask from 'shared/enqueueTask'; +import * as Scheduler from 'scheduler'; const {ReactShouldWarnActingUpdates} = ReactSharedInternals; // this implementation should be exactly the same in // ReactTestUtilsAct.js, ReactTestRendererAct.js, createReactNoop.js -// we track the 'depth' of the act() calls with this counter, -// so we can tell if any async act() calls try to run in parallel. -let actingUpdatesScopeDepth = 0; +let hasWarnedAboutMissingMockScheduler = false; +const flushWork = + Scheduler.unstable_flushWithoutYielding || + function() { + if (warnAboutMissingMockScheduler === true) { + if (hasWarnedAboutMissingMockScheduler === false) { + warningWithoutStack( + null, + 'Starting from React v17, the "scheduler" module will need to be mocked ' + + 'to guarantee consistent behaviour across tests and browsers. To fix this, add the following ' + + "to the top of your tests, or in your framework's global config file -\n\n" + + 'As an example, for jest - \n' + + "jest.mock('scheduler', () => require.requireActual('scheduler/unstable_mock'));\n\n" + + 'For more info, visit https://fb.me/react-mock-scheduler', + ); + hasWarnedAboutMissingMockScheduler = true; + } + } + while (flushPassiveEffects()) {} + }; -function flushEffectsAndMicroTasks(onDone: (err: ?Error) => void) { +function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) { try { - flushPassiveEffects(); + flushWork(); enqueueTask(() => { - if (flushPassiveEffects()) { - flushEffectsAndMicroTasks(onDone); + if (flushWork()) { + flushWorkAndMicroTasks(onDone); } else { onDone(); } @@ -40,6 +59,11 @@ function flushEffectsAndMicroTasks(onDone: (err: ?Error) => void) { } } +// we track the 'depth' of the act() calls with this counter, +// so we can tell if any async act() calls try to run in parallel. + +let actingUpdatesScopeDepth = 0; + function act(callback: () => Thenable) { let previousActingUpdatesScopeDepth; if (__DEV__) { @@ -100,7 +124,7 @@ function act(callback: () => Thenable) { called = true; result.then( () => { - flushEffectsAndMicroTasks((err: ?Error) => { + flushWorkAndMicroTasks((err: ?Error) => { onDone(); if (err) { reject(err); @@ -128,7 +152,7 @@ function act(callback: () => Thenable) { // flush effects until none remain, and cleanup try { - while (flushPassiveEffects()) {} + flushWork(); onDone(); } catch (err) { onDone();