Remove internal act builds from public modules (#21721)

* Move internal version of act to shared module

No reason to have three different copies of this anymore.

I've left the the renderer-specific `act` entry points because legacy
mode tests need to also be wrapped in `batchedUpdates`. Next, I'll update
the tests to use `batchedUpdates` manually when needed.

* Migrates tests to use internal module directly

Instead of the `unstable_concurrentAct` exports. Now we can drop those
from the public builds.

I put it in the jest-react package since that's where we put our other
testing utilities (like `toFlushAndYield`). Not so much so it can be
consumed publicly (nobody uses that package except us), but so it works
with our build tests.

* Remove unused internal fields

These were used by the old act implementation. No longer needed.
This commit is contained in:
Andrew Clark
2021-06-22 14:29:35 -07:00
committed by GitHub
parent 06f7b4f43a
commit d7dce572c7
81 changed files with 574 additions and 842 deletions
+2
View File
@@ -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
@@ -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<mixed> | void) {
export function act(scope: () => Thenable<mixed> | 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<mixed> | 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<mixed> | 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<mixed> | 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 &&
+1 -1
View File
@@ -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};
@@ -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');
});
@@ -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;
@@ -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', () => {
@@ -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);
+1 -1
View File
@@ -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);
@@ -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);
});
@@ -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;
});
+1 -1
View File
@@ -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', () => {
@@ -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;
@@ -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;
@@ -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;
@@ -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 {
@@ -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);
@@ -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 {
+1 -1
View File
@@ -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');
});
@@ -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(<App text="A" />);
});
spyOnDev(console, 'error');
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App text="B" />);
});
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(<App />);
});
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([
@@ -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);
});
}
-3
View File
@@ -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 {
@@ -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
@@ -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);
@@ -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 () => {
-2
View File
@@ -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,
};
@@ -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.
+1 -130
View File
@@ -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<Instance | TextInstance>,
@@ -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<mixed> | 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;
}
-5
View File
@@ -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;
@@ -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(
@@ -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(
@@ -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) {
@@ -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) {
@@ -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(<App />);
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(<App />);
});
// 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(<App />);
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(<App />);
});
// Each level commits separately
+52 -50
View File
@@ -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(<Cache>Hi</Cache>);
});
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(
<Cache>
<Suspense fallback={<Text text="Loading..." />}>
@@ -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(
<Suspense fallback={<Text text="Loading..." />}>
<AsyncText text="A" />
@@ -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(<App showMore={false} />);
});
// Even though there are two new <Cache /> 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(<App />);
});
// Even though there are two new <Cache /> 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(<App showMore={false} />);
});
@@ -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(<App showMore={true} />);
});
expect(Scheduler).toHaveYielded([
@@ -331,7 +333,7 @@ describe('ReactCache', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
seedNextTextCache('A');
root.render(<App showMore={false} />);
});
@@ -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(<App showMore={true} />);
});
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 <Text text="Content" />;
}
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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(
<Cache>
<Suspense fallback={<Text text="Loading..." />}>
@@ -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(
<Suspense fallback={<Text text="Loading..." />}>
<App />
@@ -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(
<Cache>
<Suspense fallback={<Text text="Loading..." />}>
@@ -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(<App showMore={false} />);
});
@@ -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(<App showMore={true} />);
});
@@ -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(<App showMore={false} />);
});
// Now reveal the boundaries. In a real app this would be a navigation.
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App showMore={true} />);
});
@@ -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(<App showMore={false} />);
});
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(
<Suspense fallback={<Text text="Loading..." />}>(empty)</Suspense>,
);
@@ -777,7 +779,7 @@ describe('ReactCache', () => {
expect(Scheduler).toHaveYielded([]);
expect(root).toMatchRenderedOutput('(empty)');
await ReactNoop.act(async () => {
await act(async () => {
startTransition(() => {
root.render(
<Suspense fallback={<Text text="Loading..." />}>
@@ -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(
<Suspense fallback={<Text text="Loading..." />}>
@@ -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(
<Suspense fallback={<Text text="Loading..." />}>
@@ -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(<App showMore={false} />);
});
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']);
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([0]);
await ReactNoop.act(async () => {
await act(async () => {
app.setState({step: 1}, () =>
Scheduler.unstable_yieldValue('Callback 1'),
);
@@ -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 <Text text={value} />;
}
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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 <Text text={value} />;
}
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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 <Text text={value} />;
}
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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 <Text text={value} />;
});
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App />);
});
expect(Scheduler).toHaveYielded(['A', 'A']);
expect(root).toMatchRenderedOutput('AA');
await ReactNoop.act(async () => {
await act(async () => {
setContext('B');
});
expect(Scheduler).toHaveYielded(['B', 'B']);
@@ -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(<Parent />);
});
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(<Parent />);
});
expect(root).toMatchRenderedOutput('Child');
await ReactNoop.act(async () => {
await act(async () => {
root.render(null);
});
expect(Scheduler).toHaveYielded(['Unmount parent', 'Unmount child']);
@@ -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(<App />);
});
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(<App />);
});
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(<App />);
});
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(<App step={0} />);
});
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(<App step={1} />);
@@ -741,12 +743,12 @@ describe('ReactExpiration', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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(<App step={0} />);
});
expect(Scheduler).toHaveYielded(['A0', 'B0', 'C0', 'Effect: 0']);
expect(root).toMatchRenderedOutput('A0B0C0');
await ReactNoop.act(async () => {
await act(async () => {
startTransition(() => {
root.render(<App step={1} />);
});
@@ -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(<App />);
@@ -75,13 +77,13 @@ describe('ReactFlushSync', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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(<App />);
});
@@ -135,7 +137,7 @@ describe('ReactFlushSync', () => {
}
const root = ReactNoop.createLegacyRoot();
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.flushSync(() => {
root.render(<App />);
});
@@ -159,7 +161,7 @@ describe('ReactFlushSync', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
expect(Scheduler).toFlushUntilNextPaint([
'Child',
@@ -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(
<>
<A />
<B />
</>,
);
expect(() => Scheduler.unstable_flushAll()).toThrow('Hello');
ReactTestRenderer.unstable_batchedUpdates(() => {
ReactTestRenderer.create(
<>
<A />
<B />
</>,
);
expect(() => Scheduler.unstable_flushAll()).toThrow('Hello');
});
});
if (__DEV__) {
@@ -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(
<>
<Foo />
@@ -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(
<>
<Foo />
@@ -527,7 +527,7 @@ describe('ReactHooksWithNoopRenderer', () => {
});
// It should not warn again (deduplication).
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<>
<Foo />
@@ -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(<Counter ref={counter} />);
@@ -787,7 +787,7 @@ describe('ReactHooksWithNoopRenderer', () => {
expect(Scheduler).toFlushAndYield(['A:0']);
expect(root).toMatchRenderedOutput(<span prop="A:0" />);
await ReactNoop.act(async () => {
await act(async () => {
if (gate(flags => flags.enableSyncDefaultUpdates)) {
React.startTransition(() => {
root.render(<Foo signal={false} />);
@@ -3492,7 +3492,7 @@ describe('ReactHooksWithNoopRenderer', () => {
}
const root = ReactNoop.createRoot(null);
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<>
<CounterA />
@@ -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(<App />);
});
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 <Text text={`Render: ${count}`} />;
}
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<Test />);
});
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();
});
@@ -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(<Oops />);
@@ -1886,11 +1888,11 @@ describe('ReactIncrementalErrorHandling', () => {
return 'Everything is fine.';
}
await ReactNoop.act(async () => {
await act(async () => {
root.render(<Oops />);
});
await ReactNoop.act(async () => {
await act(async () => {
// Schedule a default pri and a low pri update on the root.
root.render(<Oops />);
React.startTransition(() => {
@@ -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(<Text text="a:1" />, 'a');
ReactNoop.renderToRootWithID(<Text text="b:1" />, 'b');
ReactNoop.renderToRootWithID(<Text text="c:1" />, '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(<Text text="c:2" />, 'c');
@@ -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(<App />);
@@ -664,13 +666,13 @@ describe('ReactIncrementalUpdates', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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(<App />);
});
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(<App prop="A" />);
});
expect(root).toMatchRenderedOutput('0');
// Changing the prop causes the count to increase by 100
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App prop="B" />);
});
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 prop="A" />);
app.setState(state => ({count: state.count + 1}));
});
@@ -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(
<>
<Child />
@@ -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(
<>
<Child />
@@ -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]);
+6 -4
View File
@@ -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(<App />);
});
expect(root).toMatchRenderedOutput('0');
await ReactNoop.act(async () => {
await act(async () => {
setCounter(1);
ReactNoop.discreteUpdates(() => {
root.render(<App />);
@@ -483,12 +485,12 @@ describe('memo', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
expect(root).toMatchRenderedOutput('0');
await ReactNoop.act(async () => {
await act(async () => {
setCounter(1);
ReactNoop.discreteUpdates(() => {
root.render(<App />);
@@ -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(
<App
callback={() => {
@@ -49,7 +53,7 @@ describe('ReactNoop.act()', () => {
}, []);
return ctr;
}
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(<App />);
});
expect(Scheduler).toHaveYielded(['stage 1', 'stage 2']);
@@ -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(<App mode="unstable-defer-without-hiding" />);
expect(Scheduler).toFlushUntilNextPaint(['Normal']);
expect(root).toMatchRenderedOutput(<span prop="Normal" />);
@@ -53,7 +55,7 @@ describe('ReactOffscreen', () => {
);
// Now try after an update
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App mode="visible" />);
});
expect(Scheduler).toHaveYielded(['Normal', 'Deferred']);
@@ -64,7 +66,7 @@ describe('ReactOffscreen', () => {
</>,
);
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App mode="unstable-defer-without-hiding" />);
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(
<>
<LegacyHidden mode="hidden">
@@ -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(
<>
<LegacyHidden mode="hidden">
@@ -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(
<Offscreen mode="hidden">
<Child />
@@ -205,7 +207,7 @@ describe('ReactOffscreen', () => {
expect(root).toMatchRenderedOutput(<span prop="Child" />);
// Unhide the tree. The layout effect is mounted.
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<Offscreen mode="visible">
<Child />
@@ -230,7 +232,7 @@ describe('ReactOffscreen', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<Offscreen mode="visible">
<Child />
@@ -241,7 +243,7 @@ describe('ReactOffscreen', () => {
expect(root).toMatchRenderedOutput(<span prop="Child" />);
// Hide the tree. The layout effect is unmounted.
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<Offscreen mode="hidden">
<Child />
@@ -255,7 +257,7 @@ describe('ReactOffscreen', () => {
expect(root).toMatchRenderedOutput(<span prop="Child" />);
// Unhide the tree. The layout effect is re-mounted.
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<Offscreen mode="visible">
<Child />
@@ -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(
<Offscreen mode="hidden">
@@ -295,7 +297,7 @@ describe('ReactOffscreen', () => {
expect(root).toMatchRenderedOutput(<span prop="Child" />);
// Show the tree. The layout effect is mounted.
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<Offscreen mode="visible">
<Child />
@@ -306,7 +308,7 @@ describe('ReactOffscreen', () => {
expect(root).toMatchRenderedOutput(<span prop="Child" />);
// Hide the tree again. The layout effect is un-mounted.
await ReactNoop.act(async () => {
await act(async () => {
root.render(
<Offscreen mode="hidden">
<Child />
@@ -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(<CleanupEffect />);
});
expect(Scheduler).toHaveYielded([]);
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(<Effects />);
});
expect(Scheduler).toHaveYielded([
@@ -139,7 +141,7 @@ describe('ReactSchedulerIntegration', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App label="A" />);
// Commit the visible content
@@ -244,7 +246,7 @@ describe(
return null;
}
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(<App />);
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(<App />);
@@ -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(<App />);
});
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']);
@@ -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');
@@ -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(
<App>
<AsyncText text="Async" ms={1000} />
@@ -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(
<App>
<AsyncText text="Async" ms={1000} />
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -491,7 +493,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
ReactNoop.act(() => {
act(() => {
ReactNoop.renderLegacySyncRoot(
<App>
<AsyncText text="Async" ms={1000} />
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -614,7 +616,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<App>
<AsyncText text="Async" ms={1000} />
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -763,7 +765,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<App>
<AsyncText text="Async" ms={1000} />
@@ -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(<App />);
});
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(
<App>
<AsyncText text="Async" ms={1000} />
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -994,7 +996,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<App>
<AsyncText text="Async" ms={1000} />
@@ -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(<App />);
});
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(
<App innerChildren={<AsyncText text="InnerAsync_1" ms={1000} />} />,
);
@@ -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(
<App
outerChildren={<AsyncText text="OuterAsync_1" ms={1000} />}
@@ -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(
<App
outerChildren={<AsyncText text="OuterAsync_1" ms={1000} />}
@@ -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(
<App
outerChildren={<AsyncText text="OuterAsync_2" ms={1000} />}
@@ -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(<App />);
});
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(
<App innerChildren={<AsyncText text="InnerAsync_1" ms={1000} />} />,
);
@@ -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(
<App
outerChildren={<AsyncText text="OuterAsync_1" ms={1000} />}
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -1436,7 +1438,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Suspend the outer shell
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<App outerChildren={<AsyncText text="OutsideAsync" ms={1000} />} />,
);
@@ -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(
<App
fallbackChildren={<AsyncText text="FallbackAsync" ms={1000} />}
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -1579,7 +1581,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Suspend both the outer boundary and the fallback
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<App
outerChildren={<AsyncText text="OutsideAsync" ms={1000} />}
@@ -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(<App shouldSuspend={false} />);
});
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(<App shouldSuspend={true} />);
});
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(
<ErrorBoundary fallback={<Text text="Error" />}>
<App />
@@ -1810,7 +1812,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(
<ErrorBoundary fallback={<Text text="Error" />}>
<App>
@@ -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(
<ErrorBoundary fallback={<Text text="Error" />}>
<App />
@@ -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(
<ErrorBoundary fallback={<Text text="Error" />}>
<App>
@@ -2036,7 +2038,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
);
}
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(
<ErrorBoundary fallback={<Text text="Error" />}>
<App />
@@ -2063,7 +2065,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(
<ErrorBoundary fallback={<Text text="Error" />}>
<App>
@@ -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(
<ErrorBoundary fallback={<Text text="Error" />}>
<App />
@@ -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(
<ErrorBoundary fallback={<Text text="Error" />}>
<App>
@@ -2279,7 +2281,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
);
}
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -2295,7 +2297,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<App>
<AsyncText text="Async_1" ms={1000} />
@@ -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(<App />);
});
expect(Scheduler).toHaveYielded([
@@ -2447,7 +2449,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
// Schedule an update that causes React to suspend.
textToRead = 'A';
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App />);
});
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(<App />);
});
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(
<App children={<AsyncText text="Async" ms={1000} />} />,
);
@@ -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(<App />);
});
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(
<App children={<AsyncText text="Async" ms={1000} />} />,
);
@@ -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(<App />);
});
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(
<App children={<AsyncText text="Async" ms={1000} />} />,
);
@@ -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(<App />);
});
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(
<App children={<AsyncText text="Async" ms={1000} />} />,
);
@@ -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(<App />);
});
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(
<App children={<AsyncText text="Async" ms={1000} />} />,
);
@@ -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(
<ErrorBoundary fallback={<Text text="Error" />}>
<App />
@@ -3134,7 +3136,7 @@ describe('ReactSuspenseEffectsSemantics', () => {
]);
// Schedule an update that causes React to suspend.
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(
<ErrorBoundary fallback={<Text text="Error" />}>
<App>
@@ -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([
@@ -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();
}
}
@@ -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(<Foo updateList={true} />));
act(() => ReactNoop.render(<Foo updateList={true} />));
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(<Foo updateList={true} />));
act(() => ReactNoop.render(<Foo updateList={true} />));
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(() => {
@@ -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(<App step={0} shouldSuspend={false} />);
});
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(<App step={1} shouldSuspend={true} />);
@@ -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(<App />);
});
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(<App />);
});
// 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(<App />);
});
// 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(<App />);
});
expect(Scheduler).toHaveYielded(['Suspend! [A]']);
expect(ReactNoop).toMatchRenderedOutput('Loading...');
ReactNoop.act(() => {
act(() => {
ReactNoop.flushSync(() => showB());
});
@@ -2178,12 +2180,12 @@ describe('ReactSuspenseWithNoopRenderer', () => {
</Suspense>
);
}
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.render(<App />);
});
// 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(<App />);
});
// 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(<App />);
});
// 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(<App text="Initial" />);
});
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(<span prop="Initial" />);
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(<App />);
});
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(<Parent />);
});
expect(Scheduler).toHaveYielded(['A']);
expect(root).toMatchRenderedOutput(<span prop="A" />);
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(<Parent />);
});
expect(Scheduler).toHaveYielded(['A']);
expect(root).toMatchRenderedOutput(<span prop="A" />);
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(<App />);
});
expect(Scheduler).toHaveYielded(['A']);
expect(root).toMatchRenderedOutput(<span prop="A" />);
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(<Parent />);
});
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(<span prop="B" />);
// 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(<Parent />);
});
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(<span prop="B" />);
// 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(<Parent step={0} />);
});
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(<Parent step={1} />);
});
@@ -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(<Parent step={0} />);
});
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(<Parent step={1} />);
});
@@ -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(<App />);
@@ -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(<Root />);
});
expect(Scheduler).toHaveYielded(['']);
expect(root).toMatchRenderedOutput(<span prop="" />);
// 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(
<Suspense fallback={<Text text="Loading..." />}>
@@ -3935,7 +3937,7 @@ describe('ReactSuspenseWithNoopRenderer', () => {
expect(Scheduler).toHaveYielded(['A']);
expect(root).toMatchRenderedOutput(<span prop="A" />);
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(
<>
<UpdatingText />
@@ -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(<App show={false} />);
});
expect(Scheduler).toHaveYielded(['Mount Child']);
expect(root).toMatchRenderedOutput(<span prop="Child" />);
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App show={true} />);
});
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(<App show={false} />);
});
expect(Scheduler).toHaveYielded(['Mount Child']);
expect(root).toMatchRenderedOutput(<span prop="Child" />);
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App show={true} />);
});
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']);
@@ -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(
<>
<Suspense fallback={<Text text="Loading..." />} />
@@ -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(<App shouldSuspend={false} step={0} />);
});
expect(Scheduler).toHaveYielded(['A0', 'B0', 'C0']);
expect(root).toMatchRenderedOutput('A0B0C0');
await ReactNoop.act(async () => {
await act(async () => {
// This update will suspend.
startTransition(() => {
root.render(<App shouldSuspend={true} step={1} />);
@@ -911,7 +911,7 @@ describe('ReactTransition', () => {
}
const root = ReactNoop.createRoot();
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
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([
@@ -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 <Text text={state} />;
}
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.flushSync(() => {
root.render(<App />);
});
@@ -61,7 +63,7 @@ describe('ReactUpdatePriority', () => {
return <Text text={`Idle: ${idleState}, Default: ${defaultState}`} />;
}
await ReactNoop.act(async () => {
await act(async () => {
ReactNoop.idleUpdates(() => {
root.render(<App />);
});
@@ -106,13 +108,13 @@ describe('ReactUpdatePriority', () => {
);
}
await ReactNoop.act(async () => {
await act(async () => {
root.render(<App />);
});
expect(Scheduler).toHaveYielded(['A1', 'B1', 'C1']);
expect(root).toMatchRenderedOutput('A1B1C1');
await ReactNoop.act(async () => {
await act(async () => {
startTransition(() => {
setCounter(2);
});
@@ -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 () => {
@@ -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(<Example />, {unstable_isConcurrent: true});
});
@@ -553,7 +555,7 @@ describe('SchedulingProfiler', () => {
return didRender;
}
ReactTestRenderer.unstable_concurrentAct(() => {
act(() => {
ReactTestRenderer.create(<Example />, {unstable_isConcurrent: true});
});
@@ -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() {
@@ -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(<App text={'mount'} />);
});
@@ -70,7 +72,7 @@ describe('StrictEffectsMode defaults', () => {
}
}
ReactNoop.act(() => {
act(() => {
ReactNoop.renderLegacySyncRoot(<App text={'mount'} />);
});
@@ -89,7 +91,7 @@ describe('StrictEffectsMode defaults', () => {
return label;
}
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<>
<ComponentWithEffects label={'one'} />
@@ -103,7 +105,7 @@ describe('StrictEffectsMode defaults', () => {
]);
});
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<>
<ComponentWithEffects label={'one'} />
@@ -143,7 +145,7 @@ describe('StrictEffectsMode defaults', () => {
return label;
}
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<>
<ComponentWithEffects label={'one'} />
@@ -162,7 +164,7 @@ describe('StrictEffectsMode defaults', () => {
]);
});
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<>
<ComponentWithEffects label={'one'} />
@@ -204,7 +206,7 @@ describe('StrictEffectsMode defaults', () => {
return text;
}
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'mount'} />);
});
@@ -217,7 +219,7 @@ describe('StrictEffectsMode defaults', () => {
'useEffect mount',
]);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'update'} />);
});
@@ -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(<App text={'mount'} />);
});
@@ -266,7 +268,7 @@ describe('StrictEffectsMode defaults', () => {
'useEffect Two mount',
]);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'update'} />);
});
@@ -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(<App text={'mount'} />);
});
@@ -317,7 +319,7 @@ describe('StrictEffectsMode defaults', () => {
'useLayoutEffect Two mount',
]);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'update'} />);
});
@@ -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(<App text={'mount'} />);
});
@@ -362,7 +364,7 @@ describe('StrictEffectsMode defaults', () => {
'useEffect mount',
]);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'update'} />);
});
@@ -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(<App />);
});
@@ -432,7 +434,7 @@ describe('StrictEffectsMode defaults', () => {
}
}
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'mount'} />);
});
@@ -442,13 +444,13 @@ describe('StrictEffectsMode defaults', () => {
'componentDidMount',
]);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'update'} />);
});
expect(Scheduler).toHaveYielded(['componentDidUpdate']);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(null);
});
@@ -475,7 +477,7 @@ describe('StrictEffectsMode defaults', () => {
return text;
}
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'mount'} />);
});
@@ -527,7 +529,7 @@ describe('StrictEffectsMode defaults', () => {
return showChild && <Child />;
}
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App />);
});
@@ -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(<App text={'mount'} />);
});
@@ -610,7 +612,7 @@ describe('StrictEffectsMode defaults', () => {
'useEffect mount',
]);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(<App text={'mount'} />);
});
@@ -621,7 +623,7 @@ describe('StrictEffectsMode defaults', () => {
'useEffect mount',
]);
ReactNoop.act(() => {
act(() => {
ReactNoop.render(null);
});
@@ -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');
});
@@ -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 =
@@ -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;
+2 -2
View File
@@ -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');
@@ -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;
@@ -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');
@@ -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');
+2 -128
View File
@@ -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<mixed>): Thenable<void> {
return act_notBatchedInLegacyMode(() => {
@@ -62,6 +57,8 @@ function act(callback: () => Thenable<mixed>): Thenable<void> {
});
}
// TODO: Remove from public bundle
type TestRendererOptions = {
createNodeMock: (element: React$Element<any>) => 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<mixed> | 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,
};
@@ -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;
@@ -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,
};
@@ -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
@@ -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;
@@ -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(
<React.Profiler id="root" onRender={onRender}>
<Component />
@@ -1641,7 +1640,7 @@ describe(`onCommit`, () => {
const setCountRef = React.createRef(null);
let renderer = null;
ReactTestRendererAct(() => {
act(() => {
renderer = ReactTestRenderer.create(
<React.Profiler id="root-mount" onCommit={callback}>
<React.Profiler id="a">
@@ -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(
<React.Profiler id="root-update" onCommit={callback}>
<React.Profiler id="b">
@@ -1739,7 +1738,7 @@ describe(`onCommit`, () => {
// Test an error that happens during an effect
ReactTestRendererAct(() => {
act(() => {
ReactTestRenderer.create(
<React.Profiler id="root" onCommit={callback}>
<ErrorBoundary
@@ -1825,7 +1824,7 @@ describe(`onCommit`, () => {
let renderer = null;
ReactTestRendererAct(() => {
act(() => {
renderer = ReactTestRenderer.create(
<React.Profiler id="root" onCommit={callback}>
<ErrorBoundary
@@ -1867,7 +1866,7 @@ describe(`onCommit`, () => {
// Test an error that happens during an cleanup function
ReactTestRendererAct(() => {
act(() => {
renderer.update(
<React.Profiler id="root" onCommit={callback}>
<ErrorBoundary
@@ -1952,7 +1951,7 @@ describe(`onPostCommit`, () => {
Scheduler.unstable_advanceTime(1);
let renderer;
ReactTestRendererAct(() => {
act(() => {
renderer = ReactTestRenderer.create(
<React.Profiler id="mount-test" onPostCommit={callback}>
<ComponentWithEffects />
@@ -1973,7 +1972,7 @@ describe(`onPostCommit`, () => {
Scheduler.unstable_advanceTime(1);
ReactTestRendererAct(() => {
act(() => {
renderer.update(
<React.Profiler id="update-test" onPostCommit={callback}>
<ComponentWithEffects />
@@ -1994,7 +1993,7 @@ describe(`onPostCommit`, () => {
Scheduler.unstable_advanceTime(1);
ReactTestRendererAct(() => {
act(() => {
renderer.update(
<React.Profiler id="unmount-test" onPostCommit={callback} />,
);
@@ -2036,7 +2035,7 @@ describe(`onPostCommit`, () => {
Scheduler.unstable_advanceTime(1);
ReactTestRendererAct(() => {
act(() => {
ReactTestRenderer.create(
<React.Profiler id="mount-test" onPostCommit={callback}>
<ComponentWithEffects />
@@ -2084,7 +2083,7 @@ describe(`onPostCommit`, () => {
const setCountRef = React.createRef(null);
let renderer = null;
ReactTestRendererAct(() => {
act(() => {
renderer = ReactTestRenderer.create(
<React.Profiler id="root-mount" onPostCommit={callback}>
<React.Profiler id="a">
@@ -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(
<React.Profiler id="root-update" onPostCommit={callback}>
<React.Profiler id="b">
@@ -2182,7 +2181,7 @@ describe(`onPostCommit`, () => {
// Test an error that happens during an effect
ReactTestRendererAct(() => {
act(() => {
ReactTestRenderer.create(
<React.Profiler id="root" onPostCommit={callback}>
<ErrorBoundary
@@ -2269,7 +2268,7 @@ describe(`onPostCommit`, () => {
let renderer = null;
ReactTestRendererAct(() => {
act(() => {
renderer = ReactTestRenderer.create(
<React.Profiler id="root" onPostCommit={callback}>
<ErrorBoundary
@@ -2311,7 +2310,7 @@ describe(`onPostCommit`, () => {
// Test an error that happens during an cleanup function
ReactTestRendererAct(() => {
act(() => {
renderer.update(
<React.Profiler id="root" onPostCommit={callback}>
<ErrorBoundary
@@ -2428,7 +2427,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2489,7 +2488,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduledTwo = jest.fn();
const onNestedUpdateScheduledThree = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="one"
@@ -2537,7 +2536,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.renderToRootWithID(
<React.Profiler
id="test"
@@ -2577,7 +2576,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2603,7 +2602,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2614,7 +2613,7 @@ describe(`onNestedUpdateScheduled`, () => {
});
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(
<React.Profiler
id="test"
@@ -2664,7 +2663,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2681,7 +2680,7 @@ describe(`onNestedUpdateScheduled`, () => {
expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1);
expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test');
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2716,7 +2715,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2756,7 +2755,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2768,7 +2767,7 @@ describe(`onNestedUpdateScheduled`, () => {
expect(Scheduler).toHaveYielded(['Component:false:false']);
expect(onNestedUpdateScheduled).not.toHaveBeenCalled();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2803,7 +2802,7 @@ describe(`onNestedUpdateScheduled`, () => {
const onNestedUpdateScheduled = jest.fn();
ReactNoop.act(() => {
act(() => {
ReactNoop.render(
<React.Profiler
id="test"
@@ -2814,7 +2813,7 @@ describe(`onNestedUpdateScheduled`, () => {
});
expect(Scheduler).toHaveYielded(['Component:false']);
ReactNoop.act(() => {
act(() => {
updateFnRef.current();
});
expect(Scheduler).toHaveYielded(['Component:true']);
@@ -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__;
@@ -1,7 +1,7 @@
/// <reference path="./testDefinitions/PropTypes.d.ts" />
/// <reference path="./testDefinitions/React.d.ts" />
/// <reference path="./testDefinitions/ReactDOM.d.ts" />
/// <reference path="./testDefinitions/ReactDOMTestUtils.d.ts" />
/// <reference path="./testDefinitions/ReactInternalAct.d.ts" />
/*!
* 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() {
@@ -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
}
@@ -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,
@@ -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;
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -734,7 +734,7 @@ const bundles = [
moduleType: ISOMORPHIC,
entry: 'jest-react',
global: 'JestReact',
externals: [],
externals: ['react', 'scheduler', 'scheduler/unstable_mock'],
},
/******* ESLint Plugin for Hooks *******/