mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
* ReactTestRenderer move current impl to stack dir * ReactTestRenderer on fiber: commence! * ReactTestRenderer: most non-ref/non-public-instance tests are passing * Move ReactTestFiberComponent functions from Renderer to Component file * test renderer: get rid of private root containers and root Maps * TestRenderer: switch impl based on ReactDOMFeatureFlag.useFiber * ReactTestRenderer: inline component creation * ReactTestRenderer: return to pristine original glory (+ Fiber for error order difference) * TestRendererFiber: use a simple class as TestComponentInstances * Add `getPublicInstance` to support TestRenderer `createNodeMock` * Rename files to end. Update for `mountContainer->createContainer` change * test renderer return same object to prevent unnecessary context pushing/popping * Fiber HostConfig add getPublicInstance. This should be the identity fn everywhere except the test renderer * appease flow * Initial cleanup from sleepy work * unstable_batchedUpdates * Stack test renderer: cache nodeMock to not call on unmount * add public instance type parameter to the reconciler * test renderer: set _nodeMock when mounted * More cleanup * Add test cases for root fragments and (maybe?) root text nodes * Fix the npm package build Explicitly require the Stack version by default. Add a separate entry point for Fiber. We don't add fiber.js to the package yet since it's considered internal until React 16. * Relax the ref type from Object to mixed This seems like the most straightforward way to support getPublicInstance for test renderer. * Remove accidental newline * test renderer: unify TestComponent and TestContainer, handle root updates * Remove string/number serialization attempts since Fiber ensures all textInstances are strings * Return full fragments in toJSON * Test Renderer remove TestComponent instances for simple objects * Update babylon for exact object type syntax * Use $$typeof because clarity > punching ducks. * Minor Flow annotation tweaks * Tweak style, types, and naming * Fix typo
180 lines
4.9 KiB
JavaScript
180 lines
4.9 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
* @providesModule ReactTestMount
|
|
* @flow
|
|
*/
|
|
'use strict';
|
|
|
|
var React = require('React');
|
|
var ReactReconciler = require('ReactReconciler');
|
|
var ReactUpdates = require('ReactUpdates');
|
|
|
|
var emptyObject = require('emptyObject');
|
|
var getHostComponentFromComposite = require('getHostComponentFromComposite');
|
|
var instantiateReactComponent = require('instantiateReactComponent');
|
|
var invariant = require('invariant');
|
|
|
|
export type TestRendererOptions = {
|
|
createNodeMock: (element: ReactElement<any>) => any,
|
|
};
|
|
|
|
var defaultTestOptions = {
|
|
createNodeMock: function() {
|
|
return null;
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Temporary (?) hack so that we can store all top-level pending updates on
|
|
* composites instead of having to worry about different types of components
|
|
* here.
|
|
*/
|
|
var TopLevelWrapper = function() {};
|
|
TopLevelWrapper.prototype.isReactComponent = {};
|
|
if (__DEV__) {
|
|
TopLevelWrapper.displayName = 'TopLevelWrapper';
|
|
}
|
|
TopLevelWrapper.prototype.render = function() {
|
|
return this.props.child;
|
|
};
|
|
TopLevelWrapper.isReactTopLevelWrapper = true;
|
|
|
|
/**
|
|
* Mounts this component and inserts it into the DOM.
|
|
*
|
|
* @param {ReactComponent} componentInstance The instance to mount.
|
|
* @param {ReactReconcileTransaction} transaction
|
|
* @param {Object} hostParent
|
|
* @param {Object} hostContainerInfo
|
|
*/
|
|
function mountComponentIntoNode(
|
|
componentInstance,
|
|
transaction,
|
|
hostParent,
|
|
hostContainerInfo
|
|
) {
|
|
var image = ReactReconciler.mountComponent(
|
|
componentInstance,
|
|
transaction,
|
|
null,
|
|
hostContainerInfo,
|
|
emptyObject
|
|
);
|
|
componentInstance._renderedComponent._topLevelWrapper = componentInstance;
|
|
return image;
|
|
}
|
|
|
|
/**
|
|
* Batched mount.
|
|
*
|
|
* @param {ReactComponent} componentInstance The instance to mount.
|
|
* @param {number} rootID ID of the root node.
|
|
* @param {number} containerTag container element to mount into.
|
|
*/
|
|
function batchedMountComponentIntoNode(
|
|
componentInstance,
|
|
options,
|
|
) {
|
|
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
|
|
var image = transaction.perform(
|
|
mountComponentIntoNode,
|
|
null,
|
|
componentInstance,
|
|
transaction,
|
|
null,
|
|
options
|
|
);
|
|
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
|
return image;
|
|
}
|
|
|
|
var ReactTestInstance = function(component) {
|
|
this._component = component;
|
|
};
|
|
ReactTestInstance.prototype.getInstance = function() {
|
|
return this._component._renderedComponent.getPublicInstance();
|
|
};
|
|
ReactTestInstance.prototype.update = function(nextElement) {
|
|
invariant(
|
|
this._component,
|
|
"ReactTestRenderer: .update() can't be called after unmount."
|
|
);
|
|
var nextWrappedElement = React.createElement(
|
|
TopLevelWrapper,
|
|
{ child: nextElement }
|
|
);
|
|
var component = this._component;
|
|
ReactUpdates.batchedUpdates(function() {
|
|
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
|
|
transaction.perform(function() {
|
|
ReactReconciler.receiveComponent(
|
|
component,
|
|
nextWrappedElement,
|
|
transaction,
|
|
emptyObject
|
|
);
|
|
});
|
|
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
|
});
|
|
};
|
|
ReactTestInstance.prototype.unmount = function(nextElement) {
|
|
var component = this._component;
|
|
ReactUpdates.batchedUpdates(function() {
|
|
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(true);
|
|
transaction.perform(function() {
|
|
ReactReconciler.unmountComponent(
|
|
component,
|
|
false, /* safely */
|
|
false /* skipLifecycle */
|
|
);
|
|
});
|
|
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
|
});
|
|
this._component = null;
|
|
};
|
|
ReactTestInstance.prototype.toJSON = function() {
|
|
var inst = getHostComponentFromComposite(this._component);
|
|
if (inst === null) {
|
|
return null;
|
|
}
|
|
return inst.toJSON();
|
|
};
|
|
|
|
/**
|
|
* As soon as `ReactMount` is refactored to not rely on the DOM, we can share
|
|
* code between the two. For now, we'll hard code the ID logic.
|
|
*/
|
|
var ReactTestMount = {
|
|
|
|
render: function(
|
|
nextElement: ReactElement<any>,
|
|
options?: TestRendererOptions,
|
|
): ReactTestInstance {
|
|
var nextWrappedElement = React.createElement(
|
|
TopLevelWrapper,
|
|
{child: nextElement},
|
|
);
|
|
|
|
var instance = instantiateReactComponent(nextWrappedElement, false);
|
|
|
|
// The initial render is synchronous but any updates that happen during
|
|
// rendering, in componentWillMount or componentDidMount, will be batched
|
|
// according to the current batching strategy.
|
|
ReactUpdates.batchedUpdates(
|
|
batchedMountComponentIntoNode,
|
|
instance,
|
|
Object.assign({}, defaultTestOptions, options),
|
|
);
|
|
return new ReactTestInstance(instance);
|
|
},
|
|
|
|
};
|
|
|
|
module.exports = ReactTestMount;
|