diff --git a/fixtures/dom/src/__tests__/nested-act-test.js b/fixtures/dom/src/__tests__/nested-act-test.js
index a0500f47e9603..c7a191943abdf 100644
--- a/fixtures/dom/src/__tests__/nested-act-test.js
+++ b/fixtures/dom/src/__tests__/nested-act-test.js
@@ -8,18 +8,23 @@
*/
let React;
-let TestUtils;
+let ReactDOM;
let TestRenderer;
global.__DEV__ = process.env.NODE_ENV !== 'production';
+jest.mock('react-dom', () =>
+ require.requireActual('react-dom/cjs/react-dom-testing.development.js')
+);
+// we'll replace the above with react/testing and react-dom/testing right before the next minor
+
expect.extend(require('../toWarnDev'));
describe('unmocked scheduler', () => {
beforeEach(() => {
jest.resetModules();
React = require('react');
- TestUtils = require('react-dom/test-utils');
+ ReactDOM = require('react-dom');
TestRenderer = require('react-test-renderer');
});
@@ -33,7 +38,7 @@ describe('unmocked scheduler', () => {
}
// in legacy mode, this tests whether an act only flushes its own effects
TestRenderer.act(() => {
- TestUtils.act(() => {
+ ReactDOM.act(() => {
TestRenderer.create();
});
expect(log).toEqual([]);
@@ -42,7 +47,7 @@ describe('unmocked scheduler', () => {
log = [];
// for doublechecking, we flip it inside out, and assert on the outermost
- TestUtils.act(() => {
+ ReactDOM.act(() => {
TestRenderer.act(() => {
TestRenderer.create();
});
@@ -59,7 +64,7 @@ describe('mocked scheduler', () => {
require.requireActual('scheduler/unstable_mock')
);
React = require('react');
- TestUtils = require('react-dom/test-utils');
+ ReactDOM = require('react-dom');
TestRenderer = require('react-test-renderer');
});
@@ -77,7 +82,7 @@ describe('mocked scheduler', () => {
}
// with a mocked scheduler, this tests whether it flushes all work only on the outermost act
TestRenderer.act(() => {
- TestUtils.act(() => {
+ ReactDOM.act(() => {
TestRenderer.create();
});
expect(log).toEqual([]);
@@ -86,7 +91,7 @@ describe('mocked scheduler', () => {
log = [];
// for doublechecking, we flip it inside out, and assert on the outermost
- TestUtils.act(() => {
+ ReactDOM.act(() => {
TestRenderer.act(() => {
TestRenderer.create();
});
diff --git a/fixtures/dom/src/__tests__/wrong-act-test.js b/fixtures/dom/src/__tests__/wrong-act-test.js
index 6c054efec1bf9..10df65ce6df60 100644
--- a/fixtures/dom/src/__tests__/wrong-act-test.js
+++ b/fixtures/dom/src/__tests__/wrong-act-test.js
@@ -12,13 +12,17 @@ let ReactDOM;
let ReactART;
let ARTSVGMode;
let ARTCurrentMode;
-let TestUtils;
let TestRenderer;
let ARTTest;
global.__DEV__ = process.env.NODE_ENV !== 'production';
global.__EXPERIMENTAL__ = process.env.RELEASE_CHANNEL === 'experimental';
+jest.mock('react-dom', () =>
+ require.requireActual('react-dom/cjs/react-dom-testing.development.js')
+);
+// we'll replace the above with react/testing and react-dom/testing right before the next minor
+
expect.extend(require('../toWarnDev'));
function App(props) {
@@ -32,7 +36,6 @@ beforeEach(() => {
ReactART = require('react-art');
ARTSVGMode = require('art/modes/svg');
ARTCurrentMode = require('art/modes/current');
- TestUtils = require('react-dom/test-utils');
TestRenderer = require('react-test-renderer');
ARTCurrentMode.setCurrent(ARTSVGMode);
@@ -70,8 +73,8 @@ beforeEach(() => {
});
it("doesn't warn when you use the right act + renderer: dom", () => {
- TestUtils.act(() => {
- TestUtils.renderIntoDocument();
+ ReactDOM.act(() => {
+ ReactDOM.render(, document.createElement('div'));
});
});
@@ -86,7 +89,7 @@ it('resets correctly across renderers', () => {
React.useEffect(() => {}, []);
return null;
}
- TestUtils.act(() => {
+ ReactDOM.act(() => {
TestRenderer.act(() => {});
expect(() => {
TestRenderer.create();
@@ -99,7 +102,7 @@ it('resets correctly across renderers', () => {
it('warns when using the wrong act version - test + dom: render', () => {
expect(() => {
TestRenderer.act(() => {
- TestUtils.renderIntoDocument();
+ ReactDOM.render(, document.createElement('div'));
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
withoutStack: true,
@@ -113,7 +116,7 @@ it('warns when using the wrong act version - test + dom: updates', () => {
setCtr = _setCtr;
return ctr;
}
- TestUtils.renderIntoDocument();
+ ReactDOM.render(, document.createElement('div'));
expect(() => {
TestRenderer.act(() => {
setCtr(1);
@@ -123,7 +126,7 @@ it('warns when using the wrong act version - test + dom: updates', () => {
it('warns when using the wrong act version - dom + test: .create()', () => {
expect(() => {
- TestUtils.act(() => {
+ ReactDOM.act(() => {
TestRenderer.create();
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
@@ -134,7 +137,7 @@ it('warns when using the wrong act version - dom + test: .create()', () => {
it('warns when using the wrong act version - dom + test: .update()', () => {
const root = TestRenderer.create();
expect(() => {
- TestUtils.act(() => {
+ ReactDOM.act(() => {
root.update();
});
}).toWarnDev(["It looks like you're using the wrong act()"], {
@@ -151,15 +154,15 @@ it('warns when using the wrong act version - dom + test: updates', () => {
}
TestRenderer.create();
expect(() => {
- TestUtils.act(() => {
+ ReactDOM.act(() => {
setCtr(1);
});
}).toWarnDev(["It looks like you're using the wrong act()"]);
});
it('does not warn when nesting react-act inside react-dom', () => {
- TestUtils.act(() => {
- TestUtils.renderIntoDocument();
+ ReactDOM.act(() => {
+ ReactDOM.render(, document.createElement('div'));
});
});
@@ -171,7 +174,7 @@ it('does not warn when nesting react-act inside react-test-renderer', () => {
it("doesn't warn if you use nested acts from different renderers", () => {
TestRenderer.act(() => {
- TestUtils.act(() => {
+ ReactDOM.act(() => {
TestRenderer.create();
});
});
diff --git a/packages/react-dom/npm/testing.js b/packages/react-dom/npm/testing.js
new file mode 100644
index 0000000000000..0cb587bf9a9dc
--- /dev/null
+++ b/packages/react-dom/npm/testing.js
@@ -0,0 +1,38 @@
+'use strict';
+
+function checkDCE() {
+ /* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
+ if (
+ typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined' ||
+ typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== 'function'
+ ) {
+ return;
+ }
+ if (process.env.NODE_ENV !== 'production') {
+ // This branch is unreachable because this function is only called
+ // in production, but the condition is true only in development.
+ // Therefore if the branch is still here, dead code elimination wasn't
+ // properly applied.
+ // Don't change the message. React DevTools relies on it. Also make sure
+ // this message doesn't occur elsewhere in this function, or it will cause
+ // a false positive.
+ throw new Error('^_^');
+ }
+ try {
+ // Verify that the code above has been dead code eliminated (DCE'd).
+ __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(checkDCE);
+ } catch (err) {
+ // DevTools shouldn't crash React, no matter what.
+ // We should still report in case we break this code.
+ console.error(err);
+ }
+}
+
+if (process.env.NODE_ENV === 'production') {
+ // DCE check should happen before ReactDOM bundle executes so that
+ // DevTools can report bad minification during injection.
+ checkDCE();
+ module.exports = require('./cjs/react-dom-testing.production.min.js');
+} else {
+ module.exports = require('./cjs/react-dom-testing.development.js');
+}
diff --git a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
index d68a4a1141709..2f14259735000 100644
--- a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
+++ b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js
@@ -722,6 +722,7 @@ function runActTests(label, render, unmount, rerender) {
describe('suspense', () => {
if (__DEV__ && __EXPERIMENTAL__) {
+ // todo - remove __DEV__ check once we start using testing builds
it('triggers fallbacks if available', async () => {
let resolved = false;
let resolve;
diff --git a/packages/react-dom/src/client/ReactDOM.js b/packages/react-dom/src/client/ReactDOM.js
index 51b4071363b01..1a1bf445f56a2 100644
--- a/packages/react-dom/src/client/ReactDOM.js
+++ b/packages/react-dom/src/client/ReactDOM.js
@@ -35,6 +35,7 @@ import {
attemptUserBlockingHydration,
attemptContinuousHydration,
attemptHydrationAtCurrentPriority,
+ act,
} from 'react-reconciler/inline.dom';
import {createPortal as createPortalImpl} from 'shared/ReactPortal';
import {canUseDOM} from 'shared/ExecutionEnvironment';
@@ -58,6 +59,7 @@ import {
disableUnstableCreatePortal,
disableUnstableRenderSubtreeIntoContainer,
warnUnstableRenderSubtreeIntoContainer,
+ isTestEnvironment,
} from 'shared/ReactFeatureFlags';
import {
@@ -249,4 +251,8 @@ if (__DEV__) {
}
}
+if (isTestEnvironment) {
+ ReactDOM.act = act;
+}
+
export default ReactDOM;
diff --git a/packages/react-dom/testing.js b/packages/react-dom/testing.js
new file mode 100644
index 0000000000000..2a016ba16e9db
--- /dev/null
+++ b/packages/react-dom/testing.js
@@ -0,0 +1,16 @@
+/**
+ * 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
+ */
+
+'use strict';
+
+const ReactDOM = require('./src/client/ReactDOM');
+
+// TODO: decide on the top-level export form.
+// This is hacky but makes it work with both Rollup and Jest.
+module.exports = ReactDOM.default || ReactDOM;
diff --git a/packages/react-noop-renderer/src/createReactNoop.js b/packages/react-noop-renderer/src/createReactNoop.js
index 5c11164ae66c4..87f72814ac96a 100644
--- a/packages/react-noop-renderer/src/createReactNoop.js
+++ b/packages/react-noop-renderer/src/createReactNoop.js
@@ -14,7 +14,6 @@
* environment.
*/
-import type {Thenable} from 'react-reconciler/src/ReactFiberWorkLoop';
import type {Fiber} from 'react-reconciler/src/ReactFiber';
import type {UpdateQueue} from 'react-reconciler/src/ReactUpdateQueue';
import type {ReactNodeList} from 'shared/ReactTypes';
@@ -23,8 +22,6 @@ import type {RootTag} from 'shared/ReactRootTags';
import * as Scheduler from 'scheduler/unstable_mock';
import {createPortal} from 'shared/ReactPortal';
import {REACT_FRAGMENT_TYPE, REACT_ELEMENT_TYPE} from 'shared/ReactSymbols';
-import enqueueTask from 'shared/enqueueTask';
-import ReactSharedInternals from 'shared/ReactSharedInternals';
import {ConcurrentRoot, BlockingRoot, LegacyRoot} from 'shared/ReactRootTags';
type Container = {
@@ -60,8 +57,6 @@ type TextInstance = {|
|};
type HostContext = Object;
-const {IsSomeRendererActing} = ReactSharedInternals;
-
const NO_CONTEXT = {};
const UPPERCASE_CONTEXT = {};
const UPDATE_SIGNAL = {};
@@ -597,197 +592,6 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
const roots = new Map();
const DEFAULT_ROOT_ID = '';
- const {
- flushPassiveEffects,
- batchedUpdates,
- IsThisRendererActing,
- } = NoopRenderer;
-
- // this act() implementation should be exactly the same in
- // ReactTestUtilsAct.js, ReactTestRendererAct.js, createReactNoop.js
-
- const isSchedulerMocked =
- typeof Scheduler.unstable_flushAllWithoutAsserting === 'function';
- const flushWork =
- Scheduler.unstable_flushAllWithoutAsserting ||
- function() {
- let didFlushWork = false;
- while (flushPassiveEffects()) {
- didFlushWork = true;
- }
-
- return didFlushWork;
- };
-
- function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) {
- try {
- flushWork();
- enqueueTask(() => {
- if (flushWork()) {
- flushWorkAndMicroTasks(onDone);
- } else {
- onDone();
- }
- });
- } catch (err) {
- onDone(err);
- }
- }
-
- // we track the 'depth' of the act() calls with this counter,
- // so we can tell if any async act() calls try to run in parallel.
-
- let actingUpdatesScopeDepth = 0;
- let didWarnAboutUsingActInProd = false;
-
- function act(callback: () => Thenable) {
- if (!__DEV__) {
- if (didWarnAboutUsingActInProd === false) {
- didWarnAboutUsingActInProd = true;
- // eslint-disable-next-line react-internal/no-production-logging
- console.error(
- 'act(...) is not supported in production builds of React, and might not behave as expected.',
- );
- }
- }
- let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
- let previousIsSomeRendererActing;
- let previousIsThisRendererActing;
- actingUpdatesScopeDepth++;
-
- previousIsSomeRendererActing = IsSomeRendererActing.current;
- previousIsThisRendererActing = IsThisRendererActing.current;
- IsSomeRendererActing.current = true;
- IsThisRendererActing.current = true;
-
- function onDone() {
- actingUpdatesScopeDepth--;
- IsSomeRendererActing.current = previousIsSomeRendererActing;
- IsThisRendererActing.current = previousIsThisRendererActing;
- if (__DEV__) {
- if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
- // if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
- console.error(
- 'You seem to have overlapping act() calls, this is not supported. ' +
- 'Be sure to await previous act() calls before making a new one. ',
- );
- }
- }
- }
-
- let result;
- try {
- result = batchedUpdates(callback);
- } catch (error) {
- // on sync errors, we still want to 'cleanup' and decrement actingUpdatesScopeDepth
- onDone();
- throw error;
- }
-
- if (
- result !== null &&
- typeof result === 'object' &&
- typeof result.then === 'function'
- ) {
- // setup a boolean that gets set to true only
- // once this act() call is await-ed
- let called = false;
- if (__DEV__) {
- if (typeof Promise !== 'undefined') {
- //eslint-disable-next-line no-undef
- Promise.resolve()
- .then(() => {})
- .then(() => {
- if (called === false) {
- console.error(
- 'You called act(async () => ...) without await. ' +
- 'This could lead to unexpected testing behaviour, interleaving multiple act ' +
- 'calls and mixing their scopes. You should - await act(async () => ...);',
- );
- }
- });
- }
- }
-
- // in the async case, the returned thenable runs the callback, flushes
- // effects and microtasks in a loop until flushPassiveEffects() === false,
- // and cleans up
- return {
- then(resolve: () => void, reject: (?Error) => void) {
- called = true;
- result.then(
- () => {
- if (
- actingUpdatesScopeDepth > 1 ||
- (isSchedulerMocked === true &&
- previousIsSomeRendererActing === true)
- ) {
- onDone();
- resolve();
- return;
- }
- // we're about to exit the act() scope,
- // now's the time to flush tasks/effects
- flushWorkAndMicroTasks((err: ?Error) => {
- onDone();
- if (err) {
- reject(err);
- } else {
- resolve();
- }
- });
- },
- err => {
- onDone();
- reject(err);
- },
- );
- },
- };
- } else {
- if (__DEV__) {
- if (result !== undefined) {
- console.error(
- 'The callback passed to act(...) function ' +
- 'must return undefined, or a Promise. You returned %s',
- result,
- );
- }
- }
-
- // flush effects until none remain, and cleanup
- try {
- if (
- actingUpdatesScopeDepth === 1 &&
- (isSchedulerMocked === false ||
- previousIsSomeRendererActing === false)
- ) {
- // we're about to exit the act() scope,
- // now's the time to flush effects
- flushWork();
- }
- onDone();
- } catch (err) {
- onDone();
- throw err;
- }
-
- // in the sync case, the returned thenable only warns *if* await-ed
- return {
- then(resolve: () => void) {
- if (__DEV__) {
- console.error(
- 'Do not await the result of calling act(...) with sync logic, it is not a Promise.',
- );
- }
- resolve();
- },
- };
- }
- }
-
- // end act() implementation
-
function childToJSX(child, text) {
if (text !== null) {
return text;
@@ -1106,7 +910,7 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
flushPassiveEffects: NoopRenderer.flushPassiveEffects,
- act,
+ act: NoopRenderer.act,
// Logs the current state of the tree.
dumpTree(rootID: string = DEFAULT_ROOT_ID) {
diff --git a/packages/react-reconciler/src/ReactFiberReconciler.js b/packages/react-reconciler/src/ReactFiberReconciler.js
index fb46524645aee..2c2d2e7c8fe99 100644
--- a/packages/react-reconciler/src/ReactFiberReconciler.js
+++ b/packages/react-reconciler/src/ReactFiberReconciler.js
@@ -87,6 +87,11 @@ import {
findHostInstancesForRefresh,
} from './ReactFiberHotReloading';
+// used by isTestEnvironment builds
+import enqueueTask from 'shared/enqueueTask';
+import * as Scheduler from 'scheduler';
+// end isTestEnvironment imports
+
type OpaqueRoot = FiberRoot;
// 0 is PROD, 1 is DEV.
@@ -538,3 +543,185 @@ export function injectIntoDevTools(devToolsConfig: DevToolsConfig): boolean {
getCurrentFiber: __DEV__ ? () => ReactCurrentFiberCurrent : null,
});
}
+
+const {IsSomeRendererActing} = ReactSharedInternals;
+const isSchedulerMocked =
+ typeof Scheduler.unstable_flushAllWithoutAsserting === 'function';
+const flushWork =
+ Scheduler.unstable_flushAllWithoutAsserting ||
+ function() {
+ let didFlushWork = false;
+ while (flushPassiveEffects()) {
+ didFlushWork = true;
+ }
+
+ return didFlushWork;
+ };
+
+function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) {
+ try {
+ flushWork();
+ enqueueTask(() => {
+ if (flushWork()) {
+ flushWorkAndMicroTasks(onDone);
+ } else {
+ onDone();
+ }
+ });
+ } catch (err) {
+ onDone(err);
+ }
+}
+
+// we track the 'depth' of the act() calls with this counter,
+// so we can tell if any async act() calls try to run in parallel.
+
+let actingUpdatesScopeDepth = 0;
+let didWarnAboutUsingActInProd = false;
+
+// eslint-disable-next-line no-inner-declarations
+export function act(callback: () => Thenable) {
+ if (!__DEV__) {
+ if (didWarnAboutUsingActInProd === false) {
+ didWarnAboutUsingActInProd = true;
+ // eslint-disable-next-line react-internal/no-production-logging
+ console.error(
+ 'act(...) is not supported in production builds of React, and might not behave as expected.',
+ );
+ }
+ }
+
+ let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
+ let previousIsSomeRendererActing;
+ let previousIsThisRendererActing;
+ actingUpdatesScopeDepth++;
+
+ previousIsSomeRendererActing = IsSomeRendererActing.current;
+ previousIsThisRendererActing = IsThisRendererActing.current;
+ IsSomeRendererActing.current = true;
+ IsThisRendererActing.current = true;
+
+ function onDone() {
+ actingUpdatesScopeDepth--;
+ IsSomeRendererActing.current = previousIsSomeRendererActing;
+ IsThisRendererActing.current = previousIsThisRendererActing;
+ if (__DEV__) {
+ if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
+ // if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
+ console.error(
+ 'You seem to have overlapping act() calls, this is not supported. ' +
+ 'Be sure to await previous act() calls before making a new one. ',
+ );
+ }
+ }
+ }
+
+ let result;
+ try {
+ result = batchedUpdates(callback);
+ } catch (error) {
+ // on sync errors, we still want to 'cleanup' and decrement actingUpdatesScopeDepth
+ onDone();
+ throw error;
+ }
+
+ if (
+ result !== null &&
+ typeof result === 'object' &&
+ typeof result.then === 'function'
+ ) {
+ // setup a boolean that gets set to true only
+ // once this act() call is await-ed
+ let called = false;
+ if (__DEV__) {
+ if (typeof Promise !== 'undefined') {
+ //eslint-disable-next-line no-undef
+ Promise.resolve()
+ .then(() => {})
+ .then(() => {
+ if (called === false) {
+ console.error(
+ 'You called act(async () => ...) without await. ' +
+ 'This could lead to unexpected testing behaviour, interleaving multiple act ' +
+ 'calls and mixing their scopes. You should - await act(async () => ...);',
+ );
+ }
+ });
+ }
+ }
+
+ // in the async case, the returned thenable runs the callback, flushes
+ // effects and microtasks in a loop until flushPassiveEffects() === false,
+ // and cleans up
+ return {
+ then(resolve: () => void, reject: (?Error) => void) {
+ called = true;
+ result.then(
+ () => {
+ if (
+ actingUpdatesScopeDepth > 1 ||
+ (isSchedulerMocked === true &&
+ previousIsSomeRendererActing === true)
+ ) {
+ onDone();
+ resolve();
+ return;
+ }
+ // we're about to exit the act() scope,
+ // now's the time to flush tasks/effects
+ flushWorkAndMicroTasks((err: ?Error) => {
+ onDone();
+ if (err) {
+ reject(err);
+ } else {
+ resolve();
+ }
+ });
+ },
+ err => {
+ onDone();
+ reject(err);
+ },
+ );
+ },
+ };
+ } else {
+ if (__DEV__) {
+ if (result !== undefined) {
+ console.error(
+ 'The callback passed to act(...) function ' +
+ 'must return undefined, or a Promise. You returned %s',
+ result,
+ );
+ }
+ }
+
+ // flush effects until none remain, and cleanup
+ try {
+ if (
+ actingUpdatesScopeDepth === 1 &&
+ (isSchedulerMocked === false || previousIsSomeRendererActing === false)
+ ) {
+ // we're about to exit the act() scope,
+ // now's the time to flush effects
+ flushWork();
+ }
+ onDone();
+ } catch (err) {
+ onDone();
+ throw err;
+ }
+
+ // in the sync case, the returned thenable only warns *if* await-ed
+ return {
+ then(resolve: () => void) {
+ if (__DEV__) {
+ console.error(
+ 'Do not await the result of calling act(...) with sync logic, it is not a Promise.',
+ );
+ }
+ resolve();
+ },
+ };
+ }
+}
diff --git a/packages/react-test-renderer/src/ReactTestRenderer.js b/packages/react-test-renderer/src/ReactTestRenderer.js
index ca56ffaaa2685..e8ec6cbd53e6a 100644
--- a/packages/react-test-renderer/src/ReactTestRenderer.js
+++ b/packages/react-test-renderer/src/ReactTestRenderer.js
@@ -19,6 +19,7 @@ import {
flushSync,
injectIntoDevTools,
batchedUpdates,
+ act,
} from 'react-reconciler/inline.test';
import {findCurrentFiberUsingSlowPath} from 'react-reconciler/reflection';
import {
@@ -42,7 +43,6 @@ import {
} from 'shared/ReactWorkTags';
import invariant from 'shared/invariant';
import ReactVersion from 'shared/ReactVersion';
-import act from './ReactTestRendererAct';
import {getPublicInstance} from './ReactTestHostConfig';
import {ConcurrentRoot, LegacyRoot} from 'shared/ReactRootTags';
diff --git a/packages/react-test-renderer/src/ReactTestRendererAct.js b/packages/react-test-renderer/src/ReactTestRendererAct.js
deleted file mode 100644
index 362de4e2b22ae..0000000000000
--- a/packages/react-test-renderer/src/ReactTestRendererAct.js
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @flow
- */
-import type {Thenable} from 'react-reconciler/src/ReactFiberWorkLoop';
-
-import {
- batchedUpdates,
- flushPassiveEffects,
- IsThisRendererActing,
-} from 'react-reconciler/inline.test';
-import ReactSharedInternals from 'shared/ReactSharedInternals';
-import enqueueTask from 'shared/enqueueTask';
-import * as Scheduler from 'scheduler';
-
-const {IsSomeRendererActing} = ReactSharedInternals;
-
-// this implementation should be exactly the same in
-// ReactTestUtilsAct.js, ReactTestRendererAct.js, createReactNoop.js
-
-const isSchedulerMocked =
- typeof Scheduler.unstable_flushAllWithoutAsserting === 'function';
-const flushWork =
- Scheduler.unstable_flushAllWithoutAsserting ||
- function() {
- let didFlushWork = false;
- while (flushPassiveEffects()) {
- didFlushWork = true;
- }
-
- return didFlushWork;
- };
-
-function flushWorkAndMicroTasks(onDone: (err: ?Error) => void) {
- try {
- flushWork();
- enqueueTask(() => {
- if (flushWork()) {
- flushWorkAndMicroTasks(onDone);
- } else {
- onDone();
- }
- });
- } catch (err) {
- onDone(err);
- }
-}
-
-// we track the 'depth' of the act() calls with this counter,
-// so we can tell if any async act() calls try to run in parallel.
-
-let actingUpdatesScopeDepth = 0;
-let didWarnAboutUsingActInProd = false;
-
-function act(callback: () => Thenable) {
- if (!__DEV__) {
- if (didWarnAboutUsingActInProd === false) {
- didWarnAboutUsingActInProd = true;
- // eslint-disable-next-line react-internal/no-production-logging
- console.error(
- 'act(...) is not supported in production builds of React, and might not behave as expected.',
- );
- }
- }
- let previousActingUpdatesScopeDepth = actingUpdatesScopeDepth;
- let previousIsSomeRendererActing;
- let previousIsThisRendererActing;
- actingUpdatesScopeDepth++;
-
- previousIsSomeRendererActing = IsSomeRendererActing.current;
- previousIsThisRendererActing = IsThisRendererActing.current;
- IsSomeRendererActing.current = true;
- IsThisRendererActing.current = true;
-
- function onDone() {
- actingUpdatesScopeDepth--;
- IsSomeRendererActing.current = previousIsSomeRendererActing;
- IsThisRendererActing.current = previousIsThisRendererActing;
- if (__DEV__) {
- if (actingUpdatesScopeDepth > previousActingUpdatesScopeDepth) {
- // if it's _less than_ previousActingUpdatesScopeDepth, then we can assume the 'other' one has warned
- console.error(
- 'You seem to have overlapping act() calls, this is not supported. ' +
- 'Be sure to await previous act() calls before making a new one. ',
- );
- }
- }
- }
-
- let result;
- try {
- result = batchedUpdates(callback);
- } catch (error) {
- // on sync errors, we still want to 'cleanup' and decrement actingUpdatesScopeDepth
- onDone();
- throw error;
- }
-
- if (
- result !== null &&
- typeof result === 'object' &&
- typeof result.then === 'function'
- ) {
- // setup a boolean that gets set to true only
- // once this act() call is await-ed
- let called = false;
- if (__DEV__) {
- if (typeof Promise !== 'undefined') {
- //eslint-disable-next-line no-undef
- Promise.resolve()
- .then(() => {})
- .then(() => {
- if (called === false) {
- console.error(
- 'You called act(async () => ...) without await. ' +
- 'This could lead to unexpected testing behaviour, interleaving multiple act ' +
- 'calls and mixing their scopes. You should - await act(async () => ...);',
- );
- }
- });
- }
- }
-
- // in the async case, the returned thenable runs the callback, flushes
- // effects and microtasks in a loop until flushPassiveEffects() === false,
- // and cleans up
- return {
- then(resolve: () => void, reject: (?Error) => void) {
- called = true;
- result.then(
- () => {
- if (
- actingUpdatesScopeDepth > 1 ||
- (isSchedulerMocked === true &&
- previousIsSomeRendererActing === true)
- ) {
- onDone();
- resolve();
- return;
- }
- // we're about to exit the act() scope,
- // now's the time to flush tasks/effects
- flushWorkAndMicroTasks((err: ?Error) => {
- onDone();
- if (err) {
- reject(err);
- } else {
- resolve();
- }
- });
- },
- err => {
- onDone();
- reject(err);
- },
- );
- },
- };
- } else {
- if (__DEV__) {
- if (result !== undefined) {
- console.error(
- 'The callback passed to act(...) function ' +
- 'must return undefined, or a Promise. You returned %s',
- result,
- );
- }
- }
-
- // flush effects until none remain, and cleanup
- try {
- if (
- actingUpdatesScopeDepth === 1 &&
- (isSchedulerMocked === false || previousIsSomeRendererActing === false)
- ) {
- // we're about to exit the act() scope,
- // now's the time to flush effects
- flushWork();
- }
- onDone();
- } catch (err) {
- onDone();
- throw err;
- }
-
- // in the sync case, the returned thenable only warns *if* await-ed
- return {
- then(resolve: () => void) {
- if (__DEV__) {
- console.error(
- 'Do not await the result of calling act(...) with sync logic, it is not a Promise.',
- );
- }
- resolve();
- },
- };
- }
-}
-
-export default act;
diff --git a/packages/react/npm/testing.js b/packages/react/npm/testing.js
new file mode 100644
index 0000000000000..f20bb1d19db68
--- /dev/null
+++ b/packages/react/npm/testing.js
@@ -0,0 +1,7 @@
+'use strict';
+
+if (process.env.NODE_ENV === 'production') {
+ module.exports = require('./cjs/react-testing.production.min.js');
+} else {
+ module.exports = require('./cjs/react-testing.development.js');
+}
diff --git a/packages/react/testing.js b/packages/react/testing.js
new file mode 100644
index 0000000000000..4268898c088b9
--- /dev/null
+++ b/packages/react/testing.js
@@ -0,0 +1,16 @@
+/**
+ * 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
+ */
+
+'use strict';
+
+const React = require('./src/React');
+
+// TODO: decide on the top-level export form.
+// This is hacky but makes it work with both Rollup and Jest.
+module.exports = React.default || React;
diff --git a/packages/shared/ReactFeatureFlags.js b/packages/shared/ReactFeatureFlags.js
index ead32bb435b40..63eafd9a07719 100644
--- a/packages/shared/ReactFeatureFlags.js
+++ b/packages/shared/ReactFeatureFlags.js
@@ -116,3 +116,5 @@ export const warnUnstableRenderSubtreeIntoContainer = false;
// Disables ReactDOM.unstable_createPortal
export const disableUnstableCreatePortal = false;
+
+export const isTestEnvironment = false;
diff --git a/packages/shared/enqueueTask.js b/packages/shared/enqueueTask.js
index 5bf23c18f3a02..c6905c89696e0 100644
--- a/packages/shared/enqueueTask.js
+++ b/packages/shared/enqueueTask.js
@@ -8,37 +8,41 @@
*/
let didWarnAboutMessageChannel = false;
-let enqueueTask;
-try {
- // read require off the module object to get around the bundlers.
- // we don't want them to detect a require and bundle a Node polyfill.
- let requireString = ('require' + Math.random()).slice(0, 7);
- let nodeRequire = module && module[requireString];
- // assuming we're in node, let's try to get node's
- // version of setImmediate, bypassing fake timers if any.
- enqueueTask = nodeRequire('timers').setImmediate;
-} catch (_err) {
- // we're in a browser
- // we can't use regular timers because they may still be faked
- // so we try MessageChannel+postMessage instead
- enqueueTask = function(callback: () => void) {
- if (__DEV__) {
- if (didWarnAboutMessageChannel === false) {
- didWarnAboutMessageChannel = true;
- if (typeof MessageChannel === 'undefined') {
- console.error(
- 'This browser does not have a MessageChannel implementation, ' +
- 'so enqueuing tasks via await act(async () => ...) will fail. ' +
- 'Please file an issue at https://github.com/facebook/react/issues ' +
- 'if you encounter this warning.',
- );
+let enqueueTaskImpl = null;
+
+export default function enqueueTask(task: () => void) {
+ if (enqueueTaskImpl === null) {
+ try {
+ // read require off the module object to get around the bundlers.
+ // we don't want them to detect a require and bundle a Node polyfill.
+ let requireString = ('require' + Math.random()).slice(0, 7);
+ let nodeRequire = module && module[requireString];
+ // assuming we're in node, let's try to get node's
+ // version of setImmediate, bypassing fake timers if any.
+ enqueueTaskImpl = nodeRequire('timers').setImmediate;
+ } catch (_err) {
+ // we're in a browser
+ // we can't use regular timers because they may still be faked
+ // so we try MessageChannel+postMessage instead
+ enqueueTaskImpl = function(callback: () => void) {
+ if (__DEV__) {
+ if (didWarnAboutMessageChannel === false) {
+ didWarnAboutMessageChannel = true;
+ if (typeof MessageChannel === 'undefined') {
+ console.error(
+ 'This browser does not have a MessageChannel implementation, ' +
+ 'so enqueuing tasks via await act(async () => ...) will fail. ' +
+ 'Please file an issue at https://github.com/facebook/react/issues ' +
+ 'if you encounter this warning.',
+ );
+ }
+ }
}
- }
+ const channel = new MessageChannel();
+ channel.port1.onmessage = callback;
+ channel.port2.postMessage(undefined);
+ };
}
- const channel = new MessageChannel();
- channel.port1.onmessage = callback;
- channel.port2.postMessage(undefined);
- };
+ }
+ return enqueueTaskImpl(task);
}
-
-export default enqueueTask;
diff --git a/packages/shared/forks/ReactFeatureFlags.native-fb.js b/packages/shared/forks/ReactFeatureFlags.native-fb.js
index 7ae4ab0e4113d..326f16c7e6bc6 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-fb.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-fb.js
@@ -50,6 +50,7 @@ export const disableTextareaChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
+export const isTestEnvironment = false;
// Only used in www builds.
export function addUserTimingListener() {
diff --git a/packages/shared/forks/ReactFeatureFlags.native-oss.js b/packages/shared/forks/ReactFeatureFlags.native-oss.js
index 241dad2cf7e3c..e968ecacf8048 100644
--- a/packages/shared/forks/ReactFeatureFlags.native-oss.js
+++ b/packages/shared/forks/ReactFeatureFlags.native-oss.js
@@ -45,6 +45,7 @@ export const disableTextareaChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
+export const isTestEnvironment = false;
// Only used in www builds.
export function addUserTimingListener() {
diff --git a/packages/shared/forks/ReactFeatureFlags.persistent.js b/packages/shared/forks/ReactFeatureFlags.persistent.js
index a8bb6bf0aff56..385ddd9f829b4 100644
--- a/packages/shared/forks/ReactFeatureFlags.persistent.js
+++ b/packages/shared/forks/ReactFeatureFlags.persistent.js
@@ -45,6 +45,7 @@ export const disableTextareaChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
+export const isTestEnvironment = false;
// Only used in www builds.
export function addUserTimingListener() {
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
index ae94c8f7f5e7b..1c842b106778e 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.js
@@ -45,6 +45,7 @@ export const disableTextareaChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
+export const isTestEnvironment = true; // this should probably *never* change
// Only used in www builds.
export function addUserTimingListener() {
diff --git a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
index 60448b0097b0e..2cbee322dc0bc 100644
--- a/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.test-renderer.www.js
@@ -43,6 +43,7 @@ export const disableTextareaChildren = false;
export const disableUnstableRenderSubtreeIntoContainer = false;
export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
+export const isTestEnvironment = true; // this should probably *never* change
// Only used in www builds.
export function addUserTimingListener() {
diff --git a/packages/shared/forks/ReactFeatureFlags.testing.js b/packages/shared/forks/ReactFeatureFlags.testing.js
new file mode 100644
index 0000000000000..9e8d68c31f91a
--- /dev/null
+++ b/packages/shared/forks/ReactFeatureFlags.testing.js
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ *
+ * @flow
+ */
+
+import invariant from 'shared/invariant';
+
+import typeof * as FeatureFlagsType from 'shared/ReactFeatureFlags';
+import typeof * as PersistentFeatureFlagsType from './ReactFeatureFlags.persistent';
+
+export const debugRenderPhaseSideEffectsForStrictMode = false;
+export const enableUserTimingAPI = __DEV__;
+export const warnAboutDeprecatedLifecycles = true;
+export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false;
+export const enableProfilerTimer = __PROFILE__;
+export const enableSchedulerTracing = __PROFILE__;
+export const enableSuspenseServerRenderer = false;
+export const enableSelectiveHydration = false;
+export const enableChunksAPI = false;
+export const disableJavaScriptURLs = false;
+export const disableInputAttributeSyncing = false;
+export const exposeConcurrentModeAPIs = __EXPERIMENTAL__;
+export const warnAboutShorthandPropertyCollision = false;
+export const enableSchedulerDebugging = false;
+export const enableDeprecatedFlareAPI = false;
+export const enableFundamentalAPI = false;
+export const enableScopeAPI = false;
+export const enableJSXTransformAPI = false;
+export const warnAboutUnmockedScheduler = false;
+export const flushSuspenseFallbacksInTests = true;
+export const enableSuspenseCallback = false;
+export const warnAboutDefaultPropsOnFunctionComponents = false;
+export const warnAboutStringRefs = false;
+export const disableLegacyContext = false;
+export const disableSchedulerTimeoutBasedOnReactExpirationTime = false;
+export const enableTrainModelFix = true;
+export const enableTrustedTypesIntegration = false;
+export const enableNativeTargetAsInstance = false;
+export const disableCreateFactory = false;
+export const disableTextareaChildren = false;
+export const disableUnstableRenderSubtreeIntoContainer = false;
+export const warnUnstableRenderSubtreeIntoContainer = false;
+export const disableUnstableCreatePortal = false;
+export const isTestEnvironment = true;
+
+// Only used in www builds.
+export function addUserTimingListener() {
+ invariant(false, 'Not implemented.');
+}
+
+// Flow magic to verify the exports of this file match the original version.
+// eslint-disable-next-line no-unused-vars
+type Check<_X, Y: _X, X: Y = _X> = null;
+// eslint-disable-next-line no-unused-expressions
+(null: Check);
diff --git a/packages/shared/forks/ReactFeatureFlags.www.js b/packages/shared/forks/ReactFeatureFlags.www.js
index cd3e59e5fe589..2aadf6536b160 100644
--- a/packages/shared/forks/ReactFeatureFlags.www.js
+++ b/packages/shared/forks/ReactFeatureFlags.www.js
@@ -101,6 +101,8 @@ export const warnUnstableRenderSubtreeIntoContainer = false;
export const disableUnstableCreatePortal = false;
+export const isTestEnvironment = false;
+
// Flow magic to verify the exports of this file match the original version.
// eslint-disable-next-line no-unused-vars
type Check<_X, Y: _X, X: Y = _X> = null;
diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js
index aefbb65e4f1b1..fd262e49f401d 100644
--- a/scripts/rollup/bundles.js
+++ b/scripts/rollup/bundles.js
@@ -104,6 +104,31 @@ const bundles = [
externals: ['react', 'react-dom'],
},
+ /******* React DOM - Testing *******/
+ {
+ moduleType: RENDERER,
+ bundleTypes: [
+ UMD_DEV,
+ UMD_PROD,
+ UMD_PROFILING,
+ NODE_DEV,
+ NODE_PROD,
+ NODE_PROFILING,
+ ],
+ entry: 'react-dom/testing',
+ global: 'ReactDOM',
+ externals: ['react'],
+ },
+
+ /******* React DOM - www - Testing *******/
+ {
+ moduleType: RENDERER,
+ bundleTypes: [FB_WWW_DEV, FB_WWW_PROD, FB_WWW_PROFILING],
+ entry: 'react-dom/testing',
+ global: 'ReactDOMTesting',
+ externals: ['react'],
+ },
+
/* React DOM internals required for react-native-web (e.g., to shim native events from react-dom) */
{
bundleTypes: [
@@ -517,7 +542,7 @@ const bundles = [
externals: [],
},
- /******* ESLint Plugin for Hooks (proposal) *******/
+ /******* ESLint Plugin for Hooks *******/
{
// TODO: it's awkward to create a bundle for this but if we don't, the package
// won't get copied. We also can't create just DEV bundle because it contains a
diff --git a/scripts/rollup/forks.js b/scripts/rollup/forks.js
index eeb0c1caee8a7..9f1f3c41bdd62 100644
--- a/scripts/rollup/forks.js
+++ b/scripts/rollup/forks.js
@@ -1,23 +1,23 @@
'use strict';
-const bundleTypes = require('./bundles').bundleTypes;
-const moduleTypes = require('./bundles').moduleTypes;
+const {bundleTypes, moduleTypes} = require('./bundles');
const inlinedHostConfigs = require('../shared/inlinedHostConfigs');
-const UMD_DEV = bundleTypes.UMD_DEV;
-const UMD_PROD = bundleTypes.UMD_PROD;
-const UMD_PROFILING = bundleTypes.UMD_PROFILING;
-const FB_WWW_DEV = bundleTypes.FB_WWW_DEV;
-const FB_WWW_PROD = bundleTypes.FB_WWW_PROD;
-const FB_WWW_PROFILING = bundleTypes.FB_WWW_PROFILING;
-const RN_OSS_DEV = bundleTypes.RN_OSS_DEV;
-const RN_OSS_PROD = bundleTypes.RN_OSS_PROD;
-const RN_OSS_PROFILING = bundleTypes.RN_OSS_PROFILING;
-const RN_FB_DEV = bundleTypes.RN_FB_DEV;
-const RN_FB_PROD = bundleTypes.RN_FB_PROD;
-const RN_FB_PROFILING = bundleTypes.RN_FB_PROFILING;
-const RENDERER = moduleTypes.RENDERER;
-const RECONCILER = moduleTypes.RECONCILER;
+const {
+ UMD_DEV,
+ UMD_PROD,
+ UMD_PROFILING,
+ FB_WWW_DEV,
+ FB_WWW_PROD,
+ FB_WWW_PROFILING,
+ RN_OSS_DEV,
+ RN_OSS_PROD,
+ RN_OSS_PROFILING,
+ RN_FB_DEV,
+ RN_FB_PROD,
+ RN_FB_PROFILING,
+} = bundleTypes;
+const {RENDERER, RECONCILER} = moduleTypes;
// If you need to replace a file with another file for a specific environment,
// add it to this list with the logic for choosing the right replacement.
@@ -46,7 +46,7 @@ const forks = Object.freeze({
// Without this fork, importing `shared/ReactSharedInternals` inside
// the `react` package itself would not work due to a cyclical dependency.
'shared/ReactSharedInternals': (bundleType, entry, dependencies) => {
- if (entry === 'react') {
+ if (entry === 'react' || entry === 'react/testing') {
return 'react/src/ReactSharedInternals';
}
if (dependencies.indexOf('react') === -1) {
@@ -106,6 +106,10 @@ const forks = Object.freeze({
return 'shared/forks/ReactFeatureFlags.test-renderer.www.js';
}
return 'shared/forks/ReactFeatureFlags.test-renderer.js';
+ case 'react-dom/testing':
+ return 'shared/forks/ReactFeatureFlags.testing.js';
+ case 'react/testing':
+ return 'shared/forks/ReactFeatureFlags.testing.js';
default:
switch (bundleType) {
case FB_WWW_DEV:
diff --git a/scripts/rollup/modules.js b/scripts/rollup/modules.js
index 968f98bc3f081..a5975f3d2e64b 100644
--- a/scripts/rollup/modules.js
+++ b/scripts/rollup/modules.js
@@ -1,11 +1,7 @@
'use strict';
const forks = require('./forks');
-const bundleTypes = require('./bundles').bundleTypes;
-
-const UMD_DEV = bundleTypes.UMD_DEV;
-const UMD_PROD = bundleTypes.UMD_PROD;
-const UMD_PROFILING = bundleTypes.UMD_PROFILING;
+const {UMD_DEV, UMD_PROD, UMD_PROFILING} = require('./bundles').bundleTypes;
// For any external that is used in a DEV-only condition, explicitly
// specify whether it has side effects during import or not. This lets
diff --git a/scripts/rollup/wrappers.js b/scripts/rollup/wrappers.js
index 7f17491936968..f9ca412c4364e 100644
--- a/scripts/rollup/wrappers.js
+++ b/scripts/rollup/wrappers.js
@@ -1,25 +1,27 @@
'use strict';
-const Bundles = require('./bundles');
+const {bundleTypes, moduleTypes} = require('./bundles');
const reactVersion = require('../../package.json').version;
-const UMD_DEV = Bundles.bundleTypes.UMD_DEV;
-const UMD_PROD = Bundles.bundleTypes.UMD_PROD;
-const UMD_PROFILING = Bundles.bundleTypes.UMD_PROFILING;
-const NODE_DEV = Bundles.bundleTypes.NODE_DEV;
-const NODE_PROD = Bundles.bundleTypes.NODE_PROD;
-const NODE_PROFILING = Bundles.bundleTypes.NODE_PROFILING;
-const FB_WWW_DEV = Bundles.bundleTypes.FB_WWW_DEV;
-const FB_WWW_PROD = Bundles.bundleTypes.FB_WWW_PROD;
-const FB_WWW_PROFILING = Bundles.bundleTypes.FB_WWW_PROFILING;
-const RN_OSS_DEV = Bundles.bundleTypes.RN_OSS_DEV;
-const RN_OSS_PROD = Bundles.bundleTypes.RN_OSS_PROD;
-const RN_OSS_PROFILING = Bundles.bundleTypes.RN_OSS_PROFILING;
-const RN_FB_DEV = Bundles.bundleTypes.RN_FB_DEV;
-const RN_FB_PROD = Bundles.bundleTypes.RN_FB_PROD;
-const RN_FB_PROFILING = Bundles.bundleTypes.RN_FB_PROFILING;
-
-const RECONCILER = Bundles.moduleTypes.RECONCILER;
+const {
+ UMD_DEV,
+ UMD_PROD,
+ UMD_PROFILING,
+ NODE_DEV,
+ NODE_PROD,
+ NODE_PROFILING,
+ FB_WWW_DEV,
+ FB_WWW_PROD,
+ FB_WWW_PROFILING,
+ RN_OSS_DEV,
+ RN_OSS_PROD,
+ RN_OSS_PROFILING,
+ RN_FB_DEV,
+ RN_FB_PROD,
+ RN_FB_PROFILING,
+} = bundleTypes;
+
+const {RECONCILER} = moduleTypes;
const license = ` * Copyright (c) Facebook, Inc. and its affiliates.
*
diff --git a/scripts/shared/inlinedHostConfigs.js b/scripts/shared/inlinedHostConfigs.js
index 81814324e6c48..c92deb2f24f37 100644
--- a/scripts/shared/inlinedHostConfigs.js
+++ b/scripts/shared/inlinedHostConfigs.js
@@ -11,6 +11,7 @@ module.exports = [
shortName: 'dom',
entryPoints: [
'react-dom',
+ 'react-dom/testing',
'react-dom/unstable-fizz.node',
'react-flight-dom-webpack/server.node',
'react-flight-dom-webpack',