From f9c0a454415172433b8b94eec94fc36b2461065c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Markb=C3=A5ge?= Date: Wed, 26 Feb 2020 18:04:32 -0800 Subject: [PATCH] Convert the rest of react-dom and react-test-renderer to Named Exports (#18145) Nothing interesting here except that ReactShallowRenderer currently exports a class with a static method instead of an object. I think the public API is probably just meant to be createRenderer but currently the whole class is exposed. So this means that we have to keep it as default export. We could potentially also expose a named export for createRenderer but that's going to cause compatibility issues. So I'm just going to make that export default. Unfortunately Rollup and Babel (which powers Jest) disagree on how to import this. So to make it work I had to move the jest tests to imports. This doesn't work with module resetting. Some tests weren't doing that anyway and the rest is just testing ReactShallowRenderer so meh. --- packages/react-dom/server.browser.js | 14 +- packages/react-dom/server.js | 4 +- packages/react-dom/server.node.js | 15 +- .../src/__tests__/ReactTestUtils-test.js | 20 +- .../src/server/ReactDOMFizzServerBrowser.js | 4 +- .../src/server/ReactDOMFizzServerNode.js | 4 +- .../src/server/ReactDOMServerBrowser.js | 5 +- .../src/server/ReactDOMServerNode.js | 5 +- .../src/test-utils/ReactTestUtils.js | 467 +++++++++--------- packages/react-dom/test-utils.js | 8 +- packages/react-dom/unstable-fizz.browser.js | 8 +- packages/react-dom/unstable-fizz.js | 4 +- packages/react-dom/unstable-fizz.node.js | 8 +- .../react-dom/unstable-native-dependencies.js | 4 +- .../src/ReactDOMServerFormatConfig.js | 4 +- packages/react-test-renderer/index.js | 8 +- packages/react-test-renderer/shallow.js | 8 +- .../src/ReactShallowRenderer.js | 4 + .../src/ReactTestRenderer.js | 245 +++++---- .../__tests__/ReactShallowRenderer-test.js | 16 +- .../ReactShallowRendererHooks-test.js | 12 +- .../ReactShallowRendererMemo-test.js | 16 +- 22 files changed, 412 insertions(+), 471 deletions(-) diff --git a/packages/react-dom/server.browser.js b/packages/react-dom/server.browser.js index df45b9fa9fd63..c57063649a9f0 100644 --- a/packages/react-dom/server.browser.js +++ b/packages/react-dom/server.browser.js @@ -7,10 +7,10 @@ * @flow */ -'use strict'; - -const ReactDOMServer = require('./src/server/ReactDOMServerBrowser'); - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest -module.exports = ReactDOMServer.default || ReactDOMServer; +export { + renderToString, + renderToStaticMarkup, + renderToNodeStream, + renderToStaticNodeStream, + version, +} from './src/server/ReactDOMServerBrowser'; diff --git a/packages/react-dom/server.js b/packages/react-dom/server.js index 03006336ba4fe..6010f4e3d5b22 100644 --- a/packages/react-dom/server.js +++ b/packages/react-dom/server.js @@ -7,6 +7,4 @@ * @flow */ -'use strict'; - -module.exports = require('./server.node'); +export * from './server.node'; diff --git a/packages/react-dom/server.node.js b/packages/react-dom/server.node.js index 66e1ea1f0f9ad..e610a8818f961 100644 --- a/packages/react-dom/server.node.js +++ b/packages/react-dom/server.node.js @@ -7,10 +7,11 @@ * @flow */ -'use strict'; - -const ReactDOMServer = require('./src/server/ReactDOMServerNode'); - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest -module.exports = ReactDOMServer.default || ReactDOMServer; +// For some reason Flow doesn't like export * in this file. I don't know why. +export { + renderToString, + renderToStaticMarkup, + renderToNodeStream, + renderToStaticNodeStream, + version, +} from './src/server/ReactDOMServerNode'; diff --git a/packages/react-dom/src/__tests__/ReactTestUtils-test.js b/packages/react-dom/src/__tests__/ReactTestUtils-test.js index 540f23edd17c0..b0ac326e9573e 100644 --- a/packages/react-dom/src/__tests__/ReactTestUtils-test.js +++ b/packages/react-dom/src/__tests__/ReactTestUtils-test.js @@ -9,11 +9,11 @@ 'use strict'; -let createRenderer; -let React; -let ReactDOM; -let ReactDOMServer; -let ReactTestUtils; +import ReactShallowRenderer from 'react-test-renderer/shallow'; +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import * as ReactDOMServer from 'react-dom/server'; +import * as ReactTestUtils from 'react-dom/test-utils'; function getTestDocument(markup) { const doc = document.implementation.createHTMLDocument(''); @@ -27,14 +27,6 @@ function getTestDocument(markup) { } describe('ReactTestUtils', () => { - beforeEach(() => { - createRenderer = require('react-test-renderer/shallow').createRenderer; - React = require('react'); - ReactDOM = require('react-dom'); - ReactDOMServer = require('react-dom/server'); - ReactTestUtils = require('react-dom/test-utils'); - }); - it('Simulate should have locally attached media events', () => { expect(Object.keys(ReactTestUtils.Simulate).sort()).toMatchSnapshot(); }); @@ -403,7 +395,7 @@ describe('ReactTestUtils', () => { } const handler = jest.fn().mockName('spy'); - const shallowRenderer = createRenderer(); + const shallowRenderer = ReactShallowRenderer.createRenderer(); const result = shallowRenderer.render( , ); diff --git a/packages/react-dom/src/server/ReactDOMFizzServerBrowser.js b/packages/react-dom/src/server/ReactDOMFizzServerBrowser.js index 93419fa27194b..cbf83b1b71aed 100644 --- a/packages/react-dom/src/server/ReactDOMFizzServerBrowser.js +++ b/packages/react-dom/src/server/ReactDOMFizzServerBrowser.js @@ -29,6 +29,4 @@ function renderToReadableStream(children: ReactNodeList): ReadableStream { }); } -export default { - renderToReadableStream, -}; +export {renderToReadableStream}; diff --git a/packages/react-dom/src/server/ReactDOMFizzServerNode.js b/packages/react-dom/src/server/ReactDOMFizzServerNode.js index 3815e1f958ef8..154b4fff204a6 100644 --- a/packages/react-dom/src/server/ReactDOMFizzServerNode.js +++ b/packages/react-dom/src/server/ReactDOMFizzServerNode.js @@ -25,6 +25,4 @@ function pipeToNodeWritable( startWork(request); } -export default { - pipeToNodeWritable, -}; +export {pipeToNodeWritable}; diff --git a/packages/react-dom/src/server/ReactDOMServerBrowser.js b/packages/react-dom/src/server/ReactDOMServerBrowser.js index 58f04b4960b31..4424040496b99 100644 --- a/packages/react-dom/src/server/ReactDOMServerBrowser.js +++ b/packages/react-dom/src/server/ReactDOMServerBrowser.js @@ -26,11 +26,10 @@ function renderToStaticNodeStream() { ); } -// Note: when changing this, also consider https://github.com/facebook/react/issues/11526 -export default { +export { renderToString, renderToStaticMarkup, renderToNodeStream, renderToStaticNodeStream, - version: ReactVersion, + ReactVersion as version, }; diff --git a/packages/react-dom/src/server/ReactDOMServerNode.js b/packages/react-dom/src/server/ReactDOMServerNode.js index b1f955eef53d7..1347434b6900c 100644 --- a/packages/react-dom/src/server/ReactDOMServerNode.js +++ b/packages/react-dom/src/server/ReactDOMServerNode.js @@ -13,11 +13,10 @@ import { renderToStaticNodeStream, } from './ReactDOMNodeStreamRenderer'; -// Note: when changing this, also consider https://github.com/facebook/react/issues/11526 -export default { +export { renderToString, renderToStaticMarkup, renderToNodeStream, renderToStaticNodeStream, - version: ReactVersion, + ReactVersion as version, }; diff --git a/packages/react-dom/src/test-utils/ReactTestUtils.js b/packages/react-dom/src/test-utils/ReactTestUtils.js index 5ac2948c1c36b..9449880c83ed4 100644 --- a/packages/react-dom/src/test-utils/ReactTestUtils.js +++ b/packages/react-dom/src/test-utils/ReactTestUtils.js @@ -159,243 +159,233 @@ function validateClassInstance(inst, methodName) { * utilities will suffice for testing purposes. * @lends ReactTestUtils */ -const ReactTestUtils = { - renderIntoDocument: function(element) { - const div = document.createElement('div'); - // None of our tests actually require attaching the container to the - // DOM, and doing so creates a mess that we rely on test isolation to - // clean up, so we're going to stop honoring the name of this method - // (and probably rename it eventually) if no problems arise. - // document.documentElement.appendChild(div); - return ReactDOM.render(element, div); - }, - - isElement: function(element) { - return React.isValidElement(element); - }, - - isElementOfType: function(inst, convenienceConstructor) { - return React.isValidElement(inst) && inst.type === convenienceConstructor; - }, - - isDOMComponent: function(inst) { - return !!(inst && inst.nodeType === ELEMENT_NODE && inst.tagName); - }, - - isDOMComponentElement: function(inst) { - return !!(inst && React.isValidElement(inst) && !!inst.tagName); - }, - - isCompositeComponent: function(inst) { - if (ReactTestUtils.isDOMComponent(inst)) { - // Accessing inst.setState warns; just return false as that'll be what - // this returns when we have DOM nodes as refs directly - return false; - } - return ( - inst != null && - typeof inst.render === 'function' && - typeof inst.setState === 'function' - ); - }, +function renderIntoDocument(element) { + const div = document.createElement('div'); + // None of our tests actually require attaching the container to the + // DOM, and doing so creates a mess that we rely on test isolation to + // clean up, so we're going to stop honoring the name of this method + // (and probably rename it eventually) if no problems arise. + // document.documentElement.appendChild(div); + return ReactDOM.render(element, div); +} - isCompositeComponentWithType: function(inst, type) { - if (!ReactTestUtils.isCompositeComponent(inst)) { - return false; - } - const internalInstance = getInstance(inst); - const constructor = internalInstance.type; - return constructor === type; - }, - - findAllInRenderedTree: function(inst, test) { - validateClassInstance(inst, 'findAllInRenderedTree'); - if (!inst) { - return []; - } - const internalInstance = getInstance(inst); - return findAllInRenderedFiberTreeInternal(internalInstance, test); - }, +function isElement(element) { + return React.isValidElement(element); +} - /** - * Finds all instance of components in the rendered tree that are DOM - * components with the class name matching `className`. - * @return {array} an array of all the matches. - */ - scryRenderedDOMComponentsWithClass: function(root, classNames) { - validateClassInstance(root, 'scryRenderedDOMComponentsWithClass'); - return ReactTestUtils.findAllInRenderedTree(root, function(inst) { - if (ReactTestUtils.isDOMComponent(inst)) { - let className = inst.className; - if (typeof className !== 'string') { - // SVG, probably. - className = inst.getAttribute('class') || ''; - } - const classList = className.split(/\s+/); - - if (!Array.isArray(classNames)) { - invariant( - classNames !== undefined, - 'TestUtils.scryRenderedDOMComponentsWithClass expects a ' + - 'className as a second argument.', - ); - classNames = classNames.split(/\s+/); - } - return classNames.every(function(name) { - return classList.indexOf(name) !== -1; - }); - } - return false; - }); - }, +function isElementOfType(inst, convenienceConstructor) { + return React.isValidElement(inst) && inst.type === convenienceConstructor; +} - /** - * Like scryRenderedDOMComponentsWithClass but expects there to be one result, - * and returns that one result, or throws exception if there is any other - * number of matches besides one. - * @return {!ReactDOMComponent} The one match. - */ - findRenderedDOMComponentWithClass: function(root, className) { - validateClassInstance(root, 'findRenderedDOMComponentWithClass'); - const all = ReactTestUtils.scryRenderedDOMComponentsWithClass( - root, - className, - ); - if (all.length !== 1) { - throw new Error( - 'Did not find exactly one match (found: ' + - all.length + - ') ' + - 'for class:' + - className, - ); - } - return all[0]; - }, +function isDOMComponent(inst) { + return !!(inst && inst.nodeType === ELEMENT_NODE && inst.tagName); +} - /** - * Finds all instance of components in the rendered tree that are DOM - * components with the tag name matching `tagName`. - * @return {array} an array of all the matches. - */ - scryRenderedDOMComponentsWithTag: function(root, tagName) { - validateClassInstance(root, 'scryRenderedDOMComponentsWithTag'); - return ReactTestUtils.findAllInRenderedTree(root, function(inst) { - return ( - ReactTestUtils.isDOMComponent(inst) && - inst.tagName.toUpperCase() === tagName.toUpperCase() - ); - }); - }, +function isDOMComponentElement(inst) { + return !!(inst && React.isValidElement(inst) && !!inst.tagName); +} - /** - * Like scryRenderedDOMComponentsWithTag but expects there to be one result, - * and returns that one result, or throws exception if there is any other - * number of matches besides one. - * @return {!ReactDOMComponent} The one match. - */ - findRenderedDOMComponentWithTag: function(root, tagName) { - validateClassInstance(root, 'findRenderedDOMComponentWithTag'); - const all = ReactTestUtils.scryRenderedDOMComponentsWithTag(root, tagName); - if (all.length !== 1) { - throw new Error( - 'Did not find exactly one match (found: ' + - all.length + - ') ' + - 'for tag:' + - tagName, - ); - } - return all[0]; - }, +function isCompositeComponent(inst) { + if (isDOMComponent(inst)) { + // Accessing inst.setState warns; just return false as that'll be what + // this returns when we have DOM nodes as refs directly + return false; + } + return ( + inst != null && + typeof inst.render === 'function' && + typeof inst.setState === 'function' + ); +} - /** - * Finds all instances of components with type equal to `componentType`. - * @return {array} an array of all the matches. - */ - scryRenderedComponentsWithType: function(root, componentType) { - validateClassInstance(root, 'scryRenderedComponentsWithType'); - return ReactTestUtils.findAllInRenderedTree(root, function(inst) { - return ReactTestUtils.isCompositeComponentWithType(inst, componentType); - }); - }, +function isCompositeComponentWithType(inst, type) { + if (!isCompositeComponent(inst)) { + return false; + } + const internalInstance = getInstance(inst); + const constructor = internalInstance.type; + return constructor === type; +} - /** - * Same as `scryRenderedComponentsWithType` but expects there to be one result - * and returns that one result, or throws exception if there is any other - * number of matches besides one. - * @return {!ReactComponent} The one match. - */ - findRenderedComponentWithType: function(root, componentType) { - validateClassInstance(root, 'findRenderedComponentWithType'); - const all = ReactTestUtils.scryRenderedComponentsWithType( - root, - componentType, - ); - if (all.length !== 1) { - throw new Error( - 'Did not find exactly one match (found: ' + - all.length + - ') ' + - 'for componentType:' + - componentType, - ); - } - return all[0]; - }, +function findAllInRenderedTree(inst, test) { + validateClassInstance(inst, 'findAllInRenderedTree'); + if (!inst) { + return []; + } + const internalInstance = getInstance(inst); + return findAllInRenderedFiberTreeInternal(internalInstance, test); +} - /** - * Pass a mocked component module to this method to augment it with - * useful methods that allow it to be used as a dummy React component. - * Instead of rendering as usual, the component will become a simple - *
containing any provided children. - * - * @param {object} module the mock function object exported from a - * module that defines the component to be mocked - * @param {?string} mockTagName optional dummy root tag name to return - * from render method (overrides - * module.mockTagName if provided) - * @return {object} the ReactTestUtils object (for chaining) - */ - mockComponent: function(module, mockTagName) { - if (__DEV__) { - if (!hasWarnedAboutDeprecatedMockComponent) { - hasWarnedAboutDeprecatedMockComponent = true; - console.warn( - 'ReactTestUtils.mockComponent() is deprecated. ' + - 'Use shallow rendering or jest.mock() instead.\n\n' + - 'See https://fb.me/test-utils-mock-component for more information.', +/** + * Finds all instance of components in the rendered tree that are DOM + * components with the class name matching `className`. + * @return {array} an array of all the matches. + */ +function scryRenderedDOMComponentsWithClass(root, classNames) { + validateClassInstance(root, 'scryRenderedDOMComponentsWithClass'); + return findAllInRenderedTree(root, function(inst) { + if (isDOMComponent(inst)) { + let className = inst.className; + if (typeof className !== 'string') { + // SVG, probably. + className = inst.getAttribute('class') || ''; + } + const classList = className.split(/\s+/); + + if (!Array.isArray(classNames)) { + invariant( + classNames !== undefined, + 'TestUtils.scryRenderedDOMComponentsWithClass expects a ' + + 'className as a second argument.', ); + classNames = classNames.split(/\s+/); } + return classNames.every(function(name) { + return classList.indexOf(name) !== -1; + }); } + return false; + }); +} - mockTagName = mockTagName || module.mockTagName || 'div'; +/** + * Like scryRenderedDOMComponentsWithClass but expects there to be one result, + * and returns that one result, or throws exception if there is any other + * number of matches besides one. + * @return {!ReactDOMComponent} The one match. + */ +function findRenderedDOMComponentWithClass(root, className) { + validateClassInstance(root, 'findRenderedDOMComponentWithClass'); + const all = scryRenderedDOMComponentsWithClass(root, className); + if (all.length !== 1) { + throw new Error( + 'Did not find exactly one match (found: ' + + all.length + + ') ' + + 'for class:' + + className, + ); + } + return all[0]; +} - module.prototype.render.mockImplementation(function() { - return React.createElement(mockTagName, null, this.props.children); - }); +/** + * Finds all instance of components in the rendered tree that are DOM + * components with the tag name matching `tagName`. + * @return {array} an array of all the matches. + */ +function scryRenderedDOMComponentsWithTag(root, tagName) { + validateClassInstance(root, 'scryRenderedDOMComponentsWithTag'); + return findAllInRenderedTree(root, function(inst) { + return ( + isDOMComponent(inst) && + inst.tagName.toUpperCase() === tagName.toUpperCase() + ); + }); +} - return this; - }, +/** + * Like scryRenderedDOMComponentsWithTag but expects there to be one result, + * and returns that one result, or throws exception if there is any other + * number of matches besides one. + * @return {!ReactDOMComponent} The one match. + */ +function findRenderedDOMComponentWithTag(root, tagName) { + validateClassInstance(root, 'findRenderedDOMComponentWithTag'); + const all = scryRenderedDOMComponentsWithTag(root, tagName); + if (all.length !== 1) { + throw new Error( + 'Did not find exactly one match (found: ' + + all.length + + ') ' + + 'for tag:' + + tagName, + ); + } + return all[0]; +} - nativeTouchData: function(x, y) { - return { - touches: [{pageX: x, pageY: y}], - }; - }, +/** + * Finds all instances of components with type equal to `componentType`. + * @return {array} an array of all the matches. + */ +function scryRenderedComponentsWithType(root, componentType) { + validateClassInstance(root, 'scryRenderedComponentsWithType'); + return findAllInRenderedTree(root, function(inst) { + return isCompositeComponentWithType(inst, componentType); + }); +} - Simulate: null, - SimulateNative: {}, +/** + * Same as `scryRenderedComponentsWithType` but expects there to be one result + * and returns that one result, or throws exception if there is any other + * number of matches besides one. + * @return {!ReactComponent} The one match. + */ +function findRenderedComponentWithType(root, componentType) { + validateClassInstance(root, 'findRenderedComponentWithType'); + const all = scryRenderedComponentsWithType(root, componentType); + if (all.length !== 1) { + throw new Error( + 'Did not find exactly one match (found: ' + + all.length + + ') ' + + 'for componentType:' + + componentType, + ); + } + return all[0]; +} - act, -}; +/** + * Pass a mocked component module to this method to augment it with + * useful methods that allow it to be used as a dummy React component. + * Instead of rendering as usual, the component will become a simple + *
containing any provided children. + * + * @param {object} module the mock function object exported from a + * module that defines the component to be mocked + * @param {?string} mockTagName optional dummy root tag name to return + * from render method (overrides + * module.mockTagName if provided) + * @return {object} the ReactTestUtils object (for chaining) + */ +function mockComponent(module, mockTagName) { + if (__DEV__) { + if (!hasWarnedAboutDeprecatedMockComponent) { + hasWarnedAboutDeprecatedMockComponent = true; + console.warn( + 'ReactTestUtils.mockComponent() is deprecated. ' + + 'Use shallow rendering or jest.mock() instead.\n\n' + + 'See https://fb.me/test-utils-mock-component for more information.', + ); + } + } + + mockTagName = mockTagName || module.mockTagName || 'div'; + + module.prototype.render.mockImplementation(function() { + return React.createElement(mockTagName, null, this.props.children); + }); + + return this; +} + +function nativeTouchData(x, y) { + return { + touches: [{pageX: x, pageY: y}], + }; +} + +const Simulate = {}; +const SimulateNative = {}; /** * Exports: * - * - `ReactTestUtils.Simulate.click(Element)` - * - `ReactTestUtils.Simulate.mouseMove(Element)` - * - `ReactTestUtils.Simulate.change(Element)` + * - `Simulate.click(Element)` + * - `Simulate.mouseMove(Element)` + * - `Simulate.change(Element)` * - ... (All keys from event plugin `eventTypes` objects) */ function makeSimulator(eventType) { @@ -407,7 +397,7 @@ function makeSimulator(eventType) { 'Note that TestUtils.Simulate will not work if you are using shallow rendering.', ); invariant( - !ReactTestUtils.isCompositeComponent(domNode), + !isCompositeComponent(domNode), 'TestUtils.Simulate expected a DOM node as the first argument but received ' + 'a component instance. Pass the DOM node you wish to simulate the event on instead.', ); @@ -450,15 +440,13 @@ function makeSimulator(eventType) { } function buildSimulators() { - ReactTestUtils.Simulate = {}; - let eventType; for (eventType in eventNameDispatchConfigs) { /** * @param {!Element|ReactDOMComponent} domComponentOrNode * @param {?object} eventData Fake event data to use in SyntheticEvent. */ - ReactTestUtils.Simulate[eventType] = makeSimulator(eventType); + Simulate[eventType] = makeSimulator(eventType); } } @@ -467,16 +455,16 @@ buildSimulators(); /** * Exports: * - * - `ReactTestUtils.SimulateNative.click(Element/ReactDOMComponent)` - * - `ReactTestUtils.SimulateNative.mouseMove(Element/ReactDOMComponent)` - * - `ReactTestUtils.SimulateNative.mouseIn/ReactDOMComponent)` - * - `ReactTestUtils.SimulateNative.mouseOut(Element/ReactDOMComponent)` + * - `SimulateNative.click(Element/ReactDOMComponent)` + * - `SimulateNative.mouseMove(Element/ReactDOMComponent)` + * - `SimulateNative.mouseIn/ReactDOMComponent)` + * - `SimulateNative.mouseOut(Element/ReactDOMComponent)` * - ... (All keys from `BrowserEventConstants.topLevelTypes`) * * Note: Top level event types are a subset of the entire set of handler types * (which include a broader set of "synthetic" events). For example, onDragDone * is a synthetic event. Except when testing an event plugin or React's event - * handling code specifically, you probably want to use ReactTestUtils.Simulate + * handling code specifically, you probably want to use Simulate * to dispatch synthetic events. */ @@ -484,7 +472,7 @@ function makeNativeSimulator(eventType, topLevelType) { return function(domComponentOrNode, nativeEventData) { const fakeNativeEvent = new Event(eventType); Object.assign(fakeNativeEvent, nativeEventData); - if (ReactTestUtils.isDOMComponent(domComponentOrNode)) { + if (isDOMComponent(domComponentOrNode)) { simulateNativeEventOnDOMComponent( topLevelType, domComponentOrNode, @@ -576,10 +564,27 @@ function makeNativeSimulator(eventType, topLevelType) { * @param {!Element|ReactDOMComponent} domComponentOrNode * @param {?Event} nativeEventData Fake native event to use in SyntheticEvent. */ - ReactTestUtils.SimulateNative[eventType] = makeNativeSimulator( - eventType, - topLevelType, - ); + SimulateNative[eventType] = makeNativeSimulator(eventType, topLevelType); }); -export default ReactTestUtils; +export { + renderIntoDocument, + isElement, + isElementOfType, + isDOMComponent, + isDOMComponentElement, + isCompositeComponent, + isCompositeComponentWithType, + findAllInRenderedTree, + scryRenderedDOMComponentsWithClass, + findRenderedDOMComponentWithClass, + scryRenderedDOMComponentsWithTag, + findRenderedDOMComponentWithTag, + scryRenderedComponentsWithType, + findRenderedComponentWithType, + mockComponent, + nativeTouchData, + Simulate, + SimulateNative, + act, +}; diff --git a/packages/react-dom/test-utils.js b/packages/react-dom/test-utils.js index 1d4f69189e026..3eaa6b7b8c5d1 100644 --- a/packages/react-dom/test-utils.js +++ b/packages/react-dom/test-utils.js @@ -7,10 +7,4 @@ * @flow */ -'use strict'; - -const ReactTestUtils = require('./src/test-utils/ReactTestUtils'); - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest. -module.exports = ReactTestUtils.default || ReactTestUtils; +export * from './src/test-utils/ReactTestUtils'; diff --git a/packages/react-dom/unstable-fizz.browser.js b/packages/react-dom/unstable-fizz.browser.js index 4fb175ec6825e..322d4e364e1ae 100644 --- a/packages/react-dom/unstable-fizz.browser.js +++ b/packages/react-dom/unstable-fizz.browser.js @@ -7,10 +7,4 @@ * @flow */ -'use strict'; - -const ReactDOMFizzServerBrowser = require('./src/server/ReactDOMFizzServerBrowser'); - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest -module.exports = ReactDOMFizzServerBrowser.default || ReactDOMFizzServerBrowser; +export * from './src/server/ReactDOMFizzServerBrowser'; diff --git a/packages/react-dom/unstable-fizz.js b/packages/react-dom/unstable-fizz.js index 81d1ccee698d1..835fb25dca4a3 100644 --- a/packages/react-dom/unstable-fizz.js +++ b/packages/react-dom/unstable-fizz.js @@ -7,6 +7,4 @@ * @flow */ -'use strict'; - -module.exports = require('./unstable-fizz.node'); +export * from './unstable-fizz.node'; diff --git a/packages/react-dom/unstable-fizz.node.js b/packages/react-dom/unstable-fizz.node.js index ef943c74eccf5..ae7462ed70713 100644 --- a/packages/react-dom/unstable-fizz.node.js +++ b/packages/react-dom/unstable-fizz.node.js @@ -7,10 +7,4 @@ * @flow */ -'use strict'; - -const ReactDOMFizzServerNode = require('./src/server/ReactDOMFizzServerNode'); - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest -module.exports = ReactDOMFizzServerNode.default || ReactDOMFizzServerNode; +export * from './src/server/ReactDOMFizzServerNode'; diff --git a/packages/react-dom/unstable-native-dependencies.js b/packages/react-dom/unstable-native-dependencies.js index d44d492b8f198..ec502fb890690 100644 --- a/packages/react-dom/unstable-native-dependencies.js +++ b/packages/react-dom/unstable-native-dependencies.js @@ -7,6 +7,4 @@ * @flow */ -'use strict'; - -module.exports = require('./src/unstable-native-dependencies/ReactDOMUnstableNativeDependencies'); +export * from './src/unstable-native-dependencies/ReactDOMUnstableNativeDependencies'; diff --git a/packages/react-server/src/ReactDOMServerFormatConfig.js b/packages/react-server/src/ReactDOMServerFormatConfig.js index ece3e63890582..fa94102a98c9a 100644 --- a/packages/react-server/src/ReactDOMServerFormatConfig.js +++ b/packages/react-server/src/ReactDOMServerFormatConfig.js @@ -9,7 +9,7 @@ import {convertStringToBuffer} from 'react-server/src/ReactServerHostConfig'; -import ReactDOMServer from 'react-dom/server'; +import {renderToStaticMarkup} from 'react-dom/server'; export function formatChunkAsString(type: string, props: Object): string { let str = '<' + type + '>'; @@ -31,5 +31,5 @@ export function renderHostChildrenToString( // so we can't actually reference the renderer here. Instead, we // should replace this method with a reference to Fizz which // then uses this file to implement the server renderer. - return ReactDOMServer.renderToStaticMarkup(children); + return renderToStaticMarkup(children); } diff --git a/packages/react-test-renderer/index.js b/packages/react-test-renderer/index.js index 8d1c90e8855ac..61da6c01c1d5e 100644 --- a/packages/react-test-renderer/index.js +++ b/packages/react-test-renderer/index.js @@ -7,10 +7,4 @@ * @flow */ -'use strict'; - -const ReactTestRenderer = require('./src/ReactTestRenderer'); - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest. -module.exports = ReactTestRenderer.default || ReactTestRenderer; +export * from './src/ReactTestRenderer'; diff --git a/packages/react-test-renderer/shallow.js b/packages/react-test-renderer/shallow.js index 05df5d498fd91..fa548b35732db 100644 --- a/packages/react-test-renderer/shallow.js +++ b/packages/react-test-renderer/shallow.js @@ -7,10 +7,4 @@ * @flow */ -'use strict'; - -const ReactShallowRenderer = require('./src/ReactShallowRenderer'); - -// TODO: decide on the top-level export form. -// This is hacky but makes it work with both Rollup and Jest. -module.exports = ReactShallowRenderer.default || ReactShallowRenderer; +export {default} from './src/ReactShallowRenderer'; diff --git a/packages/react-test-renderer/src/ReactShallowRenderer.js b/packages/react-test-renderer/src/ReactShallowRenderer.js index abdd493704888..20751094fd28a 100644 --- a/packages/react-test-renderer/src/ReactShallowRenderer.js +++ b/packages/react-test-renderer/src/ReactShallowRenderer.js @@ -856,4 +856,8 @@ function getMaskedContext(contextTypes, unmaskedContext) { return context; } +// This should probably be a default export and a named export. +// However, this not how any of other APIs are designed so doesn't line up +// with our build configs and makes it hard to properly support ES modules +// and CommonJS. export default ReactShallowRenderer; diff --git a/packages/react-test-renderer/src/ReactTestRenderer.js b/packages/react-test-renderer/src/ReactTestRenderer.js index 0bd57d4702645..18a69c4202111 100644 --- a/packages/react-test-renderer/src/ReactTestRenderer.js +++ b/packages/react-test-renderer/src/ReactTestRenderer.js @@ -433,138 +433,129 @@ function propsMatch(props: Object, filter: Object): boolean { return true; } -const ReactTestRendererFiber = { - _Scheduler: Scheduler, - - create(element: React$Element, options: TestRendererOptions) { - let createNodeMock = defaultTestOptions.createNodeMock; - let isConcurrent = false; - if (typeof options === 'object' && options !== null) { - if (typeof options.createNodeMock === 'function') { - createNodeMock = options.createNodeMock; +function create(element: React$Element, options: TestRendererOptions) { + let createNodeMock = defaultTestOptions.createNodeMock; + let isConcurrent = false; + if (typeof options === 'object' && options !== null) { + if (typeof options.createNodeMock === 'function') { + createNodeMock = options.createNodeMock; + } + if (options.unstable_isConcurrent === true) { + isConcurrent = true; + } + } + let container = { + children: [], + createNodeMock, + tag: 'CONTAINER', + }; + let root: FiberRoot | null = createContainer( + container, + isConcurrent ? ConcurrentRoot : LegacyRoot, + false, + null, + ); + invariant(root != null, 'something went wrong'); + updateContainer(element, root, null, null); + + const entry = { + _Scheduler: Scheduler, + + root: undefined, // makes flow happy + // we define a 'getter' for 'root' below using 'Object.defineProperty' + toJSON(): Array | ReactTestRendererNode | null { + if (root == null || root.current == null || container == null) { + return null; } - if (options.unstable_isConcurrent === true) { - isConcurrent = true; + if (container.children.length === 0) { + return null; } - } - let container = { - children: [], - createNodeMock, - tag: 'CONTAINER', - }; - let root: FiberRoot | null = createContainer( - container, - isConcurrent ? ConcurrentRoot : LegacyRoot, - false, - null, - ); - invariant(root != null, 'something went wrong'); - updateContainer(element, root, null, null); - - const entry = { - _Scheduler: Scheduler, - - root: undefined, // makes flow happy - // we define a 'getter' for 'root' below using 'Object.defineProperty' - toJSON(): Array | ReactTestRendererNode | null { - if (root == null || root.current == null || container == null) { - return null; - } - if (container.children.length === 0) { - return null; - } - if (container.children.length === 1) { - return toJSON(container.children[0]); - } - if ( - container.children.length === 2 && - container.children[0].isHidden === true && - container.children[1].isHidden === false - ) { - // Omit timed out children from output entirely, including the fact that we - // temporarily wrap fallback and timed out children in an array. - return toJSON(container.children[1]); - } - let renderedChildren = null; - if (container.children && container.children.length) { - for (let i = 0; i < container.children.length; i++) { - const renderedChild = toJSON(container.children[i]); - if (renderedChild !== null) { - if (renderedChildren === null) { - renderedChildren = [renderedChild]; - } else { - renderedChildren.push(renderedChild); - } + if (container.children.length === 1) { + return toJSON(container.children[0]); + } + if ( + container.children.length === 2 && + container.children[0].isHidden === true && + container.children[1].isHidden === false + ) { + // Omit timed out children from output entirely, including the fact that we + // temporarily wrap fallback and timed out children in an array. + return toJSON(container.children[1]); + } + let renderedChildren = null; + if (container.children && container.children.length) { + for (let i = 0; i < container.children.length; i++) { + const renderedChild = toJSON(container.children[i]); + if (renderedChild !== null) { + if (renderedChildren === null) { + renderedChildren = [renderedChild]; + } else { + renderedChildren.push(renderedChild); } } } - return renderedChildren; - }, - toTree() { - if (root == null || root.current == null) { - return null; - } - return toTree(root.current); - }, - update(newElement: React$Element) { - if (root == null || root.current == null) { - return; - } - updateContainer(newElement, root, null, null); - }, - unmount() { - if (root == null || root.current == null) { - return; + } + return renderedChildren; + }, + toTree() { + if (root == null || root.current == null) { + return null; + } + return toTree(root.current); + }, + update(newElement: React$Element) { + if (root == null || root.current == null) { + return; + } + updateContainer(newElement, root, null, null); + }, + unmount() { + if (root == null || root.current == null) { + return; + } + updateContainer(null, root, null, null); + container = null; + root = null; + }, + getInstance() { + if (root == null || root.current == null) { + return null; + } + return getPublicRootInstance(root); + }, + + unstable_flushSync(fn: () => T): T { + return flushSync(fn); + }, + }; + + Object.defineProperty( + entry, + 'root', + ({ + configurable: true, + enumerable: true, + get: function() { + if (root === null) { + throw new Error("Can't access .root on unmounted test renderer"); } - updateContainer(null, root, null, null); - container = null; - root = null; - }, - getInstance() { - if (root == null || root.current == null) { - return null; + const children = getChildren(root.current); + if (children.length === 0) { + throw new Error("Can't access .root on unmounted test renderer"); + } else if (children.length === 1) { + // Normally, we skip the root and just give you the child. + return children[0]; + } else { + // However, we give you the root if there's more than one root child. + // We could make this the behavior for all cases but it would be a breaking change. + return wrapFiber(root.current); } - return getPublicRootInstance(root); - }, - - unstable_flushSync(fn: () => T): T { - return flushSync(fn); }, - }; - - Object.defineProperty( - entry, - 'root', - ({ - configurable: true, - enumerable: true, - get: function() { - if (root === null) { - throw new Error("Can't access .root on unmounted test renderer"); - } - const children = getChildren(root.current); - if (children.length === 0) { - throw new Error("Can't access .root on unmounted test renderer"); - } else if (children.length === 1) { - // Normally, we skip the root and just give you the child. - return children[0]; - } else { - // However, we give you the root if there's more than one root child. - // We could make this the behavior for all cases but it would be a breaking change. - return wrapFiber(root.current); - } - }, - }: Object), - ); - - return entry; - }, + }: Object), + ); - /* eslint-disable-next-line camelcase */ - unstable_batchedUpdates: batchedUpdates, - - act, -}; + return entry; +} const fiberToWrapper = new WeakMap(); function wrapFiber(fiber: Fiber): ReactTestInstance { @@ -589,4 +580,10 @@ injectIntoDevTools({ rendererPackageName: 'react-test-renderer', }); -export default ReactTestRendererFiber; +export { + Scheduler as _Scheduler, + create, + /* eslint-disable-next-line camelcase */ + batchedUpdates as unstable_batchedUpdates, + act, +}; diff --git a/packages/react-test-renderer/src/__tests__/ReactShallowRenderer-test.js b/packages/react-test-renderer/src/__tests__/ReactShallowRenderer-test.js index 68c8299cfe963..13aa7682aff2c 100644 --- a/packages/react-test-renderer/src/__tests__/ReactShallowRenderer-test.js +++ b/packages/react-test-renderer/src/__tests__/ReactShallowRenderer-test.js @@ -10,19 +10,13 @@ 'use strict'; -let createRenderer; -let PropTypes; -let React; +import * as PropTypes from 'prop-types'; +import * as React from 'react'; +import ReactShallowRenderer from 'react-test-renderer/shallow'; -describe('ReactShallowRenderer', () => { - beforeEach(() => { - jest.resetModules(); - - createRenderer = require('react-test-renderer/shallow').createRenderer; - PropTypes = require('prop-types'); - React = require('react'); - }); +const createRenderer = ReactShallowRenderer.createRenderer; +describe('ReactShallowRenderer', () => { it('should call all of the legacy lifecycle hooks', () => { const logs = []; const logger = message => () => logs.push(message) || true; diff --git a/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js b/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js index 6b8a962ad5b14..87bbdade2507c 100644 --- a/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js +++ b/packages/react-test-renderer/src/__tests__/ReactShallowRendererHooks-test.js @@ -10,16 +10,12 @@ 'use strict'; -let createRenderer; -let React; +import * as React from 'react'; +import ReactShallowRenderer from 'react-test-renderer/shallow'; -describe('ReactShallowRenderer with hooks', () => { - beforeEach(() => { - jest.resetModules(); - createRenderer = require('react-test-renderer/shallow').createRenderer; - React = require('react'); - }); +const createRenderer = ReactShallowRenderer.createRenderer; +describe('ReactShallowRenderer with hooks', () => { it('should work with useState', () => { function SomeComponent({defaultName}) { const [name] = React.useState(defaultName); diff --git a/packages/react-test-renderer/src/__tests__/ReactShallowRendererMemo-test.js b/packages/react-test-renderer/src/__tests__/ReactShallowRendererMemo-test.js index 9ed3bc681593b..5da98d8a7420a 100644 --- a/packages/react-test-renderer/src/__tests__/ReactShallowRendererMemo-test.js +++ b/packages/react-test-renderer/src/__tests__/ReactShallowRendererMemo-test.js @@ -10,19 +10,13 @@ 'use strict'; -let createRenderer; -let PropTypes; -let React; +import * as PropTypes from 'prop-types'; +import * as React from 'react'; +import ReactShallowRenderer from 'react-test-renderer/shallow'; -describe('ReactShallowRendererMemo', () => { - beforeEach(() => { - jest.resetModules(); - - createRenderer = require('react-test-renderer/shallow').createRenderer; - PropTypes = require('prop-types'); - React = require('react'); - }); +const createRenderer = ReactShallowRenderer.createRenderer; +describe('ReactShallowRendererMemo', () => { it('should call all of the legacy lifecycle hooks', () => { const logs = []; const logger = message => () => logs.push(message) || true;