diff --git a/src/isomorphic/React.js b/src/isomorphic/React.js index 5e57605f1c..a37649a319 100644 --- a/src/isomorphic/React.js +++ b/src/isomorphic/React.js @@ -13,7 +13,6 @@ var ReactBaseClasses = require('ReactBaseClasses'); var ReactChildren = require('ReactChildren'); -var ReactClass = require('ReactClass'); var ReactDOMFactories = require('ReactDOMFactories'); var ReactElement = require('ReactElement'); var ReactPropTypes = require('ReactPropTypes'); @@ -75,7 +74,6 @@ var React = { // Classic PropTypes: ReactPropTypes, - createClass: ReactClass.createClass, createFactory: createFactory, createMixin: createMixin, diff --git a/src/isomorphic/classic/class/ReactClass.js b/src/isomorphic/classic/class/ReactClass.js deleted file mode 100644 index fb1c07ec08..0000000000 --- a/src/isomorphic/classic/class/ReactClass.js +++ /dev/null @@ -1,833 +0,0 @@ -/** - * Copyright 2013-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 ReactClass - */ - -'use strict'; - -var ReactBaseClasses = require('ReactBaseClasses'); -var ReactElement = require('ReactElement'); -var ReactNoopUpdateQueue = require('ReactNoopUpdateQueue'); - -var emptyObject = require('fbjs/lib/emptyObject'); -var invariant = require('fbjs/lib/invariant'); -var warning = require('fbjs/lib/warning'); - -var ReactComponent = ReactBaseClasses.Component; - -var MIXINS_KEY = 'mixins'; - -// Helper function to allow the creation of anonymous functions which do not -// have .name set to the name of the variable being assigned to. -function identity(fn) { - return fn; -} - -/** - * Policies that describe methods in `ReactClassInterface`. - */ -type SpecPolicy = - /** - * These methods may be defined only once by the class specification or mixin. - */ - | 'DEFINE_ONCE' /** - * These methods may be defined by both the class specification and mixins. - * Subsequent definitions will be chained. These methods must return void. - */ - | 'DEFINE_MANY' /** - * These methods are overriding the base class. - */ - | 'OVERRIDE_BASE' /** - * These methods are similar to DEFINE_MANY, except we assume they return - * objects. We try to merge the keys of the return values of all the mixed in - * functions. If there is a key conflict we throw. - */ - | 'DEFINE_MANY_MERGED'; - -/** - * Composite components are higher-level components that compose other composite - * or host components. - * - * To create a new type of `ReactClass`, pass a specification of - * your new class to `React.createClass`. The only requirement of your class - * specification is that you implement a `render` method. - * - * var MyComponent = React.createClass({ - * render: function() { - * return
Hello World
; - * } - * }); - * - * The class specification supports a specific protocol of methods that have - * special meaning (e.g. `render`). See `ReactClassInterface` for - * more the comprehensive protocol. Any other properties and methods in the - * class specification will be available on the prototype. - * - * @interface ReactClassInterface - * @internal - */ -var ReactClassInterface: {[key: string]: SpecPolicy} = { - /** - * An array of Mixin objects to include when defining your component. - * - * @type {array} - * @optional - */ - mixins: 'DEFINE_MANY', - - /** - * An object containing properties and methods that should be defined on - * the component's constructor instead of its prototype (static methods). - * - * @type {object} - * @optional - */ - statics: 'DEFINE_MANY', - - /** - * Definition of prop types for this component. - * - * @type {object} - * @optional - */ - propTypes: 'DEFINE_MANY', - - /** - * Definition of context types for this component. - * - * @type {object} - * @optional - */ - contextTypes: 'DEFINE_MANY', - - /** - * Definition of context types this component sets for its children. - * - * @type {object} - * @optional - */ - childContextTypes: 'DEFINE_MANY', - - // ==== Definition methods ==== - - /** - * Invoked when the component is mounted. Values in the mapping will be set on - * `this.props` if that prop is not specified (i.e. using an `in` check). - * - * This method is invoked before `getInitialState` and therefore cannot rely - * on `this.state` or use `this.setState`. - * - * @return {object} - * @optional - */ - getDefaultProps: 'DEFINE_MANY_MERGED', - - /** - * Invoked once before the component is mounted. The return value will be used - * as the initial value of `this.state`. - * - * getInitialState: function() { - * return { - * isOn: false, - * fooBaz: new BazFoo() - * } - * } - * - * @return {object} - * @optional - */ - getInitialState: 'DEFINE_MANY_MERGED', - - /** - * @return {object} - * @optional - */ - getChildContext: 'DEFINE_MANY_MERGED', - - /** - * Uses props from `this.props` and state from `this.state` to render the - * structure of the component. - * - * No guarantees are made about when or how often this method is invoked, so - * it must not have side effects. - * - * render: function() { - * var name = this.props.name; - * return
Hello, {name}!
; - * } - * - * @return {ReactComponent} - * @required - */ - render: 'DEFINE_ONCE', - - // ==== Delegate methods ==== - - /** - * Invoked when the component is initially created and about to be mounted. - * This may have side effects, but any external subscriptions or data created - * by this method must be cleaned up in `componentWillUnmount`. - * - * @optional - */ - componentWillMount: 'DEFINE_MANY', - - /** - * Invoked when the component has been mounted and has a DOM representation. - * However, there is no guarantee that the DOM node is in the document. - * - * Use this as an opportunity to operate on the DOM when the component has - * been mounted (initialized and rendered) for the first time. - * - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidMount: 'DEFINE_MANY', - - /** - * Invoked before the component receives new props. - * - * Use this as an opportunity to react to a prop transition by updating the - * state using `this.setState`. Current props are accessed via `this.props`. - * - * componentWillReceiveProps: function(nextProps, nextContext) { - * this.setState({ - * likesIncreasing: nextProps.likeCount > this.props.likeCount - * }); - * } - * - * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop - * transition may cause a state change, but the opposite is not true. If you - * need it, you are probably looking for `componentWillUpdate`. - * - * @param {object} nextProps - * @optional - */ - componentWillReceiveProps: 'DEFINE_MANY', - - /** - * Invoked while deciding if the component should be updated as a result of - * receiving new props, state and/or context. - * - * Use this as an opportunity to `return false` when you're certain that the - * transition to the new props/state/context will not require a component - * update. - * - * shouldComponentUpdate: function(nextProps, nextState, nextContext) { - * return !equal(nextProps, this.props) || - * !equal(nextState, this.state) || - * !equal(nextContext, this.context); - * } - * - * @param {object} nextProps - * @param {?object} nextState - * @param {?object} nextContext - * @return {boolean} True if the component should update. - * @optional - */ - shouldComponentUpdate: 'DEFINE_ONCE', - - /** - * Invoked when the component is about to update due to a transition from - * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState` - * and `nextContext`. - * - * Use this as an opportunity to perform preparation before an update occurs. - * - * NOTE: You **cannot** use `this.setState()` in this method. - * - * @param {object} nextProps - * @param {?object} nextState - * @param {?object} nextContext - * @param {ReactReconcileTransaction} transaction - * @optional - */ - componentWillUpdate: 'DEFINE_MANY', - - /** - * Invoked when the component's DOM representation has been updated. - * - * Use this as an opportunity to operate on the DOM when the component has - * been updated. - * - * @param {object} prevProps - * @param {?object} prevState - * @param {?object} prevContext - * @param {DOMElement} rootNode DOM element representing the component. - * @optional - */ - componentDidUpdate: 'DEFINE_MANY', - - /** - * Invoked when the component is about to be removed from its parent and have - * its DOM representation destroyed. - * - * Use this as an opportunity to deallocate any external resources. - * - * NOTE: There is no `componentDidUnmount` since your component will have been - * destroyed by that point. - * - * @optional - */ - componentWillUnmount: 'DEFINE_MANY', - - // ==== Advanced methods ==== - - /** - * Updates the component's currently mounted DOM representation. - * - * By default, this implements React's rendering and reconciliation algorithm. - * Sophisticated clients may wish to override this. - * - * @param {ReactReconcileTransaction} transaction - * @internal - * @overridable - */ - updateComponent: 'OVERRIDE_BASE', -}; - -/** - * Mapping from class specification keys to special processing functions. - * - * Although these are declared like instance properties in the specification - * when defining classes using `React.createClass`, they are actually static - * and are accessible on the constructor instead of the prototype. Despite - * being static, they must be defined outside of the "statics" key under - * which all other static methods are defined. - */ -var RESERVED_SPEC_KEYS = { - displayName: function(Constructor, displayName) { - Constructor.displayName = displayName; - }, - mixins: function(Constructor, mixins) { - if (mixins) { - for (var i = 0; i < mixins.length; i++) { - mixSpecIntoComponent(Constructor, mixins[i]); - } - } - }, - childContextTypes: function(Constructor, childContextTypes) { - if (__DEV__) { - validateTypeDef(Constructor, childContextTypes, 'child context'); - } - Constructor.childContextTypes = Object.assign( - {}, - Constructor.childContextTypes, - childContextTypes, - ); - }, - contextTypes: function(Constructor, contextTypes) { - if (__DEV__) { - validateTypeDef(Constructor, contextTypes, 'context'); - } - Constructor.contextTypes = Object.assign( - {}, - Constructor.contextTypes, - contextTypes, - ); - }, - /** - * Special case getDefaultProps which should move into statics but requires - * automatic merging. - */ - getDefaultProps: function(Constructor, getDefaultProps) { - if (Constructor.getDefaultProps) { - Constructor.getDefaultProps = createMergedResultFunction( - Constructor.getDefaultProps, - getDefaultProps, - ); - } else { - Constructor.getDefaultProps = getDefaultProps; - } - }, - propTypes: function(Constructor, propTypes) { - if (__DEV__) { - validateTypeDef(Constructor, propTypes, 'prop'); - } - Constructor.propTypes = Object.assign({}, Constructor.propTypes, propTypes); - }, - statics: function(Constructor, statics) { - mixStaticSpecIntoComponent(Constructor, statics); - }, - autobind: function() {}, // noop -}; - -function validateTypeDef(Constructor, typeDef, location: string) { - for (var propName in typeDef) { - if (typeDef.hasOwnProperty(propName)) { - // use a warning instead of an invariant so components - // don't show up in prod but only in __DEV__ - warning( - typeof typeDef[propName] === 'function', - '%s: %s type `%s` is invalid; it must be a function, usually from ' + - 'React.PropTypes.', - Constructor.displayName || 'ReactClass', - location, - propName, - ); - } - } -} - -function validateMethodOverride(isAlreadyDefined, name) { - var specPolicy = ReactClassInterface.hasOwnProperty(name) - ? ReactClassInterface[name] - : null; - - // Disallow overriding of base class methods unless explicitly allowed. - if (ReactClassMixin.hasOwnProperty(name)) { - invariant( - specPolicy === 'OVERRIDE_BASE', - 'ReactClassInterface: You are attempting to override ' + - '`%s` from your class specification. Ensure that your method names ' + - 'do not overlap with React methods.', - name, - ); - } - - // Disallow defining methods more than once unless explicitly allowed. - if (isAlreadyDefined) { - invariant( - specPolicy === 'DEFINE_MANY' || specPolicy === 'DEFINE_MANY_MERGED', - 'ReactClassInterface: You are attempting to define ' + - '`%s` on your component more than once. This conflict may be due ' + - 'to a mixin.', - name, - ); - } -} - -/** - * Mixin helper which handles policy validation and reserved - * specification keys when building React classes. - */ -function mixSpecIntoComponent(Constructor, spec) { - if (!spec) { - if (__DEV__) { - var typeofSpec = typeof spec; - var isMixinValid = typeofSpec === 'object' && spec !== null; - - warning( - isMixinValid, - "%s: You're attempting to include a mixin that is either null " + - 'or not an object. Check the mixins included by the component, ' + - 'as well as any mixins they include themselves. ' + - 'Expected object but got %s.', - Constructor.displayName || 'ReactClass', - spec === null ? null : typeofSpec, - ); - } - - return; - } - - invariant( - typeof spec !== 'function', - "ReactClass: You're attempting to " + - 'use a component class or function as a mixin. Instead, just use a ' + - 'regular object.', - ); - invariant( - !ReactElement.isValidElement(spec), - "ReactClass: You're attempting to " + - 'use a component as a mixin. Instead, just use a regular object.', - ); - - var proto = Constructor.prototype; - var autoBindPairs = proto.__reactAutoBindPairs; - - // By handling mixins before any other properties, we ensure the same - // chaining order is applied to methods with DEFINE_MANY policy, whether - // mixins are listed before or after these methods in the spec. - if (spec.hasOwnProperty(MIXINS_KEY)) { - RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins); - } - - for (var name in spec) { - if (!spec.hasOwnProperty(name)) { - continue; - } - - if (name === MIXINS_KEY) { - // We have already handled mixins in a special case above. - continue; - } - - var property = spec[name]; - var isAlreadyDefined = proto.hasOwnProperty(name); - validateMethodOverride(isAlreadyDefined, name); - - if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { - RESERVED_SPEC_KEYS[name](Constructor, property); - } else { - // Setup methods on prototype: - // The following member methods should not be automatically bound: - // 1. Expected ReactClass methods (in the "interface"). - // 2. Overridden methods (that were mixed in). - var isReactClassMethod = ReactClassInterface.hasOwnProperty(name); - var isFunction = typeof property === 'function'; - var shouldAutoBind = isFunction && - !isReactClassMethod && - !isAlreadyDefined && - spec.autobind !== false; - - if (shouldAutoBind) { - autoBindPairs.push(name, property); - proto[name] = property; - } else { - if (isAlreadyDefined) { - var specPolicy = ReactClassInterface[name]; - - // These cases should already be caught by validateMethodOverride. - invariant( - isReactClassMethod && - (specPolicy === 'DEFINE_MANY_MERGED' || - specPolicy === 'DEFINE_MANY'), - 'ReactClass: Unexpected spec policy %s for key %s ' + - 'when mixing in component specs.', - specPolicy, - name, - ); - - // For methods which are defined more than once, call the existing - // methods before calling the new property, merging if appropriate. - if (specPolicy === 'DEFINE_MANY_MERGED') { - proto[name] = createMergedResultFunction(proto[name], property); - } else if (specPolicy === 'DEFINE_MANY') { - proto[name] = createChainedFunction(proto[name], property); - } - } else { - proto[name] = property; - if (__DEV__) { - // Add verbose displayName to the function, which helps when looking - // at profiling tools. - if (typeof property === 'function' && spec.displayName) { - proto[name].displayName = spec.displayName + '_' + name; - } - } - } - } - } - } -} - -function mixStaticSpecIntoComponent(Constructor, statics) { - if (!statics) { - return; - } - for (var name in statics) { - var property = statics[name]; - if (!statics.hasOwnProperty(name)) { - continue; - } - - var isReserved = name in RESERVED_SPEC_KEYS; - invariant( - !isReserved, - 'ReactClass: You are attempting to define a reserved ' + - 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' + - 'as an instance property instead; it will still be accessible on the ' + - 'constructor.', - name, - ); - - var isInherited = name in Constructor; - invariant( - !isInherited, - 'ReactClass: You are attempting to define ' + - '`%s` on your component more than once. This conflict may be ' + - 'due to a mixin.', - name, - ); - Constructor[name] = property; - } -} - -/** - * Merge two objects, but throw if both contain the same key. - * - * @param {object} one The first object, which is mutated. - * @param {object} two The second object - * @return {object} one after it has been mutated to contain everything in two. - */ -function mergeIntoWithNoDuplicateKeys(one, two) { - invariant( - one && two && typeof one === 'object' && typeof two === 'object', - 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.', - ); - - for (var key in two) { - if (two.hasOwnProperty(key)) { - invariant( - one[key] === undefined, - 'mergeIntoWithNoDuplicateKeys(): ' + - 'Tried to merge two objects with the same key: `%s`. This conflict ' + - 'may be due to a mixin; in particular, this may be caused by two ' + - 'getInitialState() or getDefaultProps() methods returning objects ' + - 'with clashing keys.', - key, - ); - one[key] = two[key]; - } - } - return one; -} - -/** - * Creates a function that invokes two functions and merges their return values. - * - * @param {function} one Function to invoke first. - * @param {function} two Function to invoke second. - * @return {function} Function that invokes the two argument functions. - * @private - */ -function createMergedResultFunction(one, two) { - return function mergedResult() { - var a = one.apply(this, arguments); - var b = two.apply(this, arguments); - if (a == null) { - return b; - } else if (b == null) { - return a; - } - var c = {}; - mergeIntoWithNoDuplicateKeys(c, a); - mergeIntoWithNoDuplicateKeys(c, b); - return c; - }; -} - -/** - * Creates a function that invokes two functions and ignores their return vales. - * - * @param {function} one Function to invoke first. - * @param {function} two Function to invoke second. - * @return {function} Function that invokes the two argument functions. - * @private - */ -function createChainedFunction(one, two) { - return function chainedFunction() { - one.apply(this, arguments); - two.apply(this, arguments); - }; -} - -/** - * Binds a method to the component. - * - * @param {object} component Component whose method is going to be bound. - * @param {function} method Method to be bound. - * @return {function} The bound method. - */ -function bindAutoBindMethod(component, method) { - var boundMethod = method.bind(component); - if (__DEV__) { - boundMethod.__reactBoundContext = component; - boundMethod.__reactBoundMethod = method; - boundMethod.__reactBoundArguments = null; - var componentName = component.constructor.displayName; - var _bind = boundMethod.bind; - boundMethod.bind = function(newThis, ...args) { - // User is trying to bind() an autobound method; we effectively will - // ignore the value of "this" that the user is trying to use, so - // let's warn. - if (newThis !== component && newThis !== null) { - warning( - false, - 'bind(): React component methods may only be bound to the ' + - 'component instance.\n\nSee %s', - componentName, - ); - } else if (!args.length) { - warning( - false, - 'bind(): You are binding a component method to the component. ' + - 'React does this for you automatically in a high-performance ' + - 'way, so you can safely remove this call.\n\nSee %s', - componentName, - ); - return boundMethod; - } - var reboundMethod = _bind.apply(boundMethod, arguments); - reboundMethod.__reactBoundContext = component; - reboundMethod.__reactBoundMethod = method; - reboundMethod.__reactBoundArguments = args; - return reboundMethod; - }; - } - return boundMethod; -} - -/** - * Binds all auto-bound methods in a component. - * - * @param {object} component Component whose method is going to be bound. - */ -function bindAutoBindMethods(component) { - var pairs = component.__reactAutoBindPairs; - for (var i = 0; i < pairs.length; i += 2) { - var autoBindKey = pairs[i]; - var method = pairs[i + 1]; - component[autoBindKey] = bindAutoBindMethod(component, method); - } -} - -/** - * Add more to the ReactClass base class. These are all legacy features and - * therefore not already part of the modern ReactComponent. - */ -var ReactClassMixin = { - /** - * TODO: This will be deprecated because state should always keep a consistent - * type signature and the only use case for this, is to avoid that. - */ - replaceState: function(newState, callback) { - this.updater.enqueueReplaceState(this, newState, callback, 'replaceState'); - }, - - /** - * Checks whether or not this composite component is mounted. - * @return {boolean} True if mounted, false otherwise. - * @protected - * @final - */ - isMounted: function() { - return this.updater.isMounted(this); - }, -}; - -var ReactClassComponent = function() {}; -Object.assign( - ReactClassComponent.prototype, - ReactComponent.prototype, - ReactClassMixin, -); - -/** - * Module for creating composite components. - * - * @class ReactClass - */ -var ReactClass = { - /** - * Creates a composite component class given a class specification. - * See https://facebook.github.io/react/docs/react-api.html#createclass - * - * @param {object} spec Class specification (which must define `render`). - * @return {function} Component constructor function. - * @public - */ - createClass: function(spec) { - // To keep our warnings more understandable, we'll use a little hack here to - // ensure that Constructor.name !== 'Constructor'. This makes sure we don't - // unnecessarily identify a class without displayName as 'Constructor'. - var Constructor = identity(function(props, context, updater) { - // This constructor gets overridden by mocks. The argument is used - // by mocks to assert on what gets mounted. - - if (__DEV__) { - warning( - this instanceof Constructor, - 'Something is calling a React component directly. Use a factory or ' + - 'JSX instead. See: https://fb.me/react-legacyfactory', - ); - } - - // Wire up auto-binding - if (this.__reactAutoBindPairs.length) { - bindAutoBindMethods(this); - } - - this.props = props; - this.context = context; - this.refs = emptyObject; - this.updater = updater || ReactNoopUpdateQueue; - - this.state = null; - - // ReactClasses doesn't have constructors. Instead, they use the - // getInitialState and componentWillMount methods for initialization. - - var initialState = this.getInitialState ? this.getInitialState() : null; - if (__DEV__) { - // We allow auto-mocks to proceed as if they're returning null. - if ( - initialState === undefined && this.getInitialState._isMockFunction - ) { - // This is probably bad practice. Consider warning here and - // deprecating this convenience. - initialState = null; - } - } - invariant( - typeof initialState === 'object' && !Array.isArray(initialState), - '%s.getInitialState(): must return an object or null', - Constructor.displayName || 'ReactCompositeComponent', - ); - - this.state = initialState; - }); - Constructor.prototype = new ReactClassComponent(); - Constructor.prototype.constructor = Constructor; - Constructor.prototype.__reactAutoBindPairs = []; - - mixSpecIntoComponent(Constructor, spec); - - // Initialize the defaultProps property after all mixins have been merged. - if (Constructor.getDefaultProps) { - Constructor.defaultProps = Constructor.getDefaultProps(); - } - - if (__DEV__) { - // This is a tag to indicate that the use of these method names is ok, - // since it's used with createClass. If it's not, then it's likely a - // mistake so we'll warn you to use the static property, property - // initializer or constructor respectively. - if (Constructor.getDefaultProps) { - Constructor.getDefaultProps.isReactClassApproved = {}; - } - if (Constructor.prototype.getInitialState) { - Constructor.prototype.getInitialState.isReactClassApproved = {}; - } - } - - invariant( - Constructor.prototype.render, - 'createClass(...): Class specification must implement a `render` method.', - ); - - if (__DEV__) { - warning( - !Constructor.prototype.componentShouldUpdate, - '%s has a method called ' + - 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + - 'The name is phrased as a question because the function is ' + - 'expected to return a value.', - spec.displayName || 'A component', - ); - warning( - !Constructor.prototype.componentWillRecieveProps, - '%s has a method called ' + - 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', - spec.displayName || 'A component', - ); - } - - // Reduce time spent doing lookups by setting these on the prototype. - for (var methodName in ReactClassInterface) { - if (!Constructor.prototype[methodName]) { - Constructor.prototype[methodName] = null; - } - } - - return Constructor; - }, -}; - -module.exports = ReactClass; diff --git a/src/isomorphic/classic/class/__tests__/ReactBind-test.js b/src/isomorphic/classic/class/__tests__/ReactBind-test.js deleted file mode 100644 index 051db5a8fe..0000000000 --- a/src/isomorphic/classic/class/__tests__/ReactBind-test.js +++ /dev/null @@ -1,152 +0,0 @@ -/** - * Copyright 2013-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. - * - * @emails react-core - */ -/*global global:true*/ -'use strict'; - -var React = require('react'); -var ReactTestUtils = require('ReactTestUtils'); - -// TODO: Test render and all stock methods. -describe('autobinding', () => { - it('Holds reference to instance', () => { - var mouseDidEnter = jest.fn(); - var mouseDidLeave = jest.fn(); - var mouseDidClick = jest.fn(); - - var TestBindComponent = React.createClass({ - getInitialState: function() { - return {something: 'hi'}; - }, - onMouseEnter: mouseDidEnter, - onMouseLeave: mouseDidLeave, - onClick: mouseDidClick, - - // auto binding only occurs on top level functions in class defs. - badIdeas: { - badBind: function() { - void this.state.something; - }, - }, - - render: function() { - return ( -
- ); - }, - }); - - var instance1 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - var instance2 = ReactTestUtils.renderIntoDocument(); - var rendered2 = instance2.refs.child; - - expect(function() { - var badIdea = instance1.badIdeas.badBind; - badIdea(); - }).toThrow(); - - expect(instance1.onClick).not.toBe(instance2.onClick); - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.click(rendered2); - expect(mouseDidClick.mock.instances.length).toBe(2); - expect(mouseDidClick.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOver(rendered1); - expect(mouseDidEnter.mock.instances.length).toBe(1); - expect(mouseDidEnter.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOver(rendered2); - expect(mouseDidEnter.mock.instances.length).toBe(2); - expect(mouseDidEnter.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOut(rendered1); - expect(mouseDidLeave.mock.instances.length).toBe(1); - expect(mouseDidLeave.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOut(rendered2); - expect(mouseDidLeave.mock.instances.length).toBe(2); - expect(mouseDidLeave.mock.instances[1]).toBe(instance2); - }); - - it('works with mixins', () => { - var mouseDidClick = jest.fn(); - - var TestMixin = { - onClick: mouseDidClick, - }; - - var TestBindComponent = React.createClass({ - mixins: [TestMixin], - - render: function() { - return
; - }, - }); - - var instance1 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - }); - - it('warns if you try to bind to this', () => { - spyOn(console, 'error'); - - var TestBindComponent = React.createClass({ - handleClick: function() {}, - render: function() { - return
; - }, - }); - - ReactTestUtils.renderIntoDocument(); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: bind(): You are binding a component method to the component. ' + - 'React does this for you automatically in a high-performance ' + - 'way, so you can safely remove this call.\n\nSee TestBindComponent', - ); - }); - - it('does not warn if you pass an auto-bound method to setState', () => { - spyOn(console, 'error'); - - var TestBindComponent = React.createClass({ - getInitialState: function() { - return {foo: 1}; - }, - componentDidMount: function() { - this.setState({foo: 2}, this.handleUpdate); - }, - handleUpdate: function() {}, - render: function() { - return
; - }, - }); - - ReactTestUtils.renderIntoDocument(); - - expectDev(console.error.calls.count()).toBe(0); - }); -}); diff --git a/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js b/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js deleted file mode 100644 index 086329338f..0000000000 --- a/src/isomorphic/classic/class/__tests__/ReactBindOptout-test.js +++ /dev/null @@ -1,206 +0,0 @@ -/** - * Copyright 2013-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. - * - * @emails react-core - */ -/*global global:true*/ -'use strict'; - -var React = require('react'); -var ReactTestUtils = require('ReactTestUtils'); - -// TODO: Test render and all stock methods. -describe('autobind optout', () => { - it('should work with manual binding', () => { - var mouseDidEnter = jest.fn(); - var mouseDidLeave = jest.fn(); - var mouseDidClick = jest.fn(); - - var TestBindComponent = React.createClass({ - autobind: false, - getInitialState: function() { - return {something: 'hi'}; - }, - onMouseEnter: mouseDidEnter, - onMouseLeave: mouseDidLeave, - onClick: mouseDidClick, - - render: function() { - return ( -
- ); - }, - }); - - var instance1 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - var instance2 = ReactTestUtils.renderIntoDocument(); - var rendered2 = instance2.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.click(rendered2); - expect(mouseDidClick.mock.instances.length).toBe(2); - expect(mouseDidClick.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOver(rendered1); - expect(mouseDidEnter.mock.instances.length).toBe(1); - expect(mouseDidEnter.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOver(rendered2); - expect(mouseDidEnter.mock.instances.length).toBe(2); - expect(mouseDidEnter.mock.instances[1]).toBe(instance2); - - ReactTestUtils.Simulate.mouseOut(rendered1); - expect(mouseDidLeave.mock.instances.length).toBe(1); - expect(mouseDidLeave.mock.instances[0]).toBe(instance1); - - ReactTestUtils.Simulate.mouseOut(rendered2); - expect(mouseDidLeave.mock.instances.length).toBe(2); - expect(mouseDidLeave.mock.instances[1]).toBe(instance2); - }); - - it('should not hold reference to instance', () => { - var mouseDidClick = function() { - void this.state.something; - }; - - var TestBindComponent = React.createClass({ - autobind: false, - getInitialState: function() { - return {something: 'hi'}; - }, - onClick: mouseDidClick, - - // auto binding only occurs on top level functions in class defs. - badIdeas: { - badBind: function() { - void this.state.something; - }, - }, - - render: function() { - return
; - }, - }); - - var instance1 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - var instance2 = ReactTestUtils.renderIntoDocument(); - var rendered2 = instance2.refs.child; - - expect(function() { - var badIdea = instance1.badIdeas.badBind; - badIdea(); - }).toThrow(); - - expect(instance1.onClick).toBe(instance2.onClick); - - expect(function() { - ReactTestUtils.Simulate.click(rendered1); - }).toThrow(); - - expect(function() { - ReactTestUtils.Simulate.click(rendered2); - }).toThrow(); - }); - - it('works with mixins that have not opted out of autobinding', () => { - var mouseDidClick = jest.fn(); - - var TestMixin = { - onClick: mouseDidClick, - }; - - var TestBindComponent = React.createClass({ - mixins: [TestMixin], - - render: function() { - return
; - }, - }); - - var instance1 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - }); - - it('works with mixins that have opted out of autobinding', () => { - var mouseDidClick = jest.fn(); - - var TestMixin = { - autobind: false, - onClick: mouseDidClick, - }; - - var TestBindComponent = React.createClass({ - mixins: [TestMixin], - - render: function() { - return
; - }, - }); - - var instance1 = ReactTestUtils.renderIntoDocument(); - var rendered1 = instance1.refs.child; - - ReactTestUtils.Simulate.click(rendered1); - expect(mouseDidClick.mock.instances.length).toBe(1); - expect(mouseDidClick.mock.instances[0]).toBe(instance1); - }); - - it('does not warn if you try to bind to this', () => { - spyOn(console, 'error'); - - var TestBindComponent = React.createClass({ - autobind: false, - handleClick: function() {}, - render: function() { - return
; - }, - }); - - ReactTestUtils.renderIntoDocument(); - - expectDev(console.error.calls.count()).toBe(0); - }); - - it('does not warn if you pass an manually bound method to setState', () => { - spyOn(console, 'error'); - - var TestBindComponent = React.createClass({ - autobind: false, - getInitialState: function() { - return {foo: 1}; - }, - componentDidMount: function() { - this.setState({foo: 2}, this.handleUpdate.bind(this)); - }, - handleUpdate: function() {}, - render: function() { - return
; - }, - }); - - ReactTestUtils.renderIntoDocument(); - - expectDev(console.error.calls.count()).toBe(0); - }); -}); diff --git a/src/isomorphic/classic/class/__tests__/ReactClass-test.js b/src/isomorphic/classic/class/__tests__/ReactClass-test.js deleted file mode 100644 index 4ab5ad7dac..0000000000 --- a/src/isomorphic/classic/class/__tests__/ReactClass-test.js +++ /dev/null @@ -1,348 +0,0 @@ -/** - * Copyright 2013-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. - * - * @emails react-core - */ - -'use strict'; - -var React; -var ReactDOM; -var ReactTestUtils; - -describe('ReactClass-spec', () => { - beforeEach(() => { - React = require('react'); - ReactDOM = require('react-dom'); - ReactTestUtils = require('ReactTestUtils'); - }); - - it('should throw when `render` is not specified', () => { - expect(function() { - React.createClass({}); - }).toThrowError( - 'createClass(...): Class specification must implement a `render` method.', - ); - }); - - it('should copy `displayName` onto the Constructor', () => { - var TestComponent = React.createClass({ - render: function() { - return
; - }, - }); - - expect(TestComponent.displayName).toBe('TestComponent'); - }); - - it('should copy prop types onto the Constructor', () => { - var propValidator = jest.fn(); - var TestComponent = React.createClass({ - propTypes: { - value: propValidator, - }, - render: function() { - return
; - }, - }); - - expect(TestComponent.propTypes).toBeDefined(); - expect(TestComponent.propTypes.value).toBe(propValidator); - }); - - it('should warn on invalid prop types', () => { - spyOn(console, 'error'); - React.createClass({ - displayName: 'Component', - propTypes: { - prop: null, - }, - render: function() { - return {this.props.prop}; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component: prop type `prop` is invalid; ' + - 'it must be a function, usually from React.PropTypes.', - ); - }); - - it('should warn on invalid context types', () => { - spyOn(console, 'error'); - React.createClass({ - displayName: 'Component', - contextTypes: { - prop: null, - }, - render: function() { - return {this.props.prop}; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component: context type `prop` is invalid; ' + - 'it must be a function, usually from React.PropTypes.', - ); - }); - - it('should throw on invalid child context types', () => { - spyOn(console, 'error'); - React.createClass({ - displayName: 'Component', - childContextTypes: { - prop: null, - }, - render: function() { - return {this.props.prop}; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Component: child context type `prop` is invalid; ' + - 'it must be a function, usually from React.PropTypes.', - ); - }); - - it('should warn when mispelling shouldComponentUpdate', () => { - spyOn(console, 'error'); - - React.createClass({ - componentShouldUpdate: function() { - return false; - }, - render: function() { - return
; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: A component has a method called componentShouldUpdate(). Did you ' + - 'mean shouldComponentUpdate()? The name is phrased as a question ' + - 'because the function is expected to return a value.', - ); - - React.createClass({ - displayName: 'NamedComponent', - componentShouldUpdate: function() { - return false; - }, - render: function() { - return
; - }, - }); - expectDev(console.error.calls.count()).toBe(2); - expectDev(console.error.calls.argsFor(1)[0]).toBe( - 'Warning: NamedComponent has a method called componentShouldUpdate(). Did you ' + - 'mean shouldComponentUpdate()? The name is phrased as a question ' + - 'because the function is expected to return a value.', - ); - }); - - it('should warn when mispelling componentWillReceiveProps', () => { - spyOn(console, 'error'); - React.createClass({ - componentWillRecieveProps: function() { - return false; - }, - render: function() { - return
; - }, - }); - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: A component has a method called componentWillRecieveProps(). Did you ' + - 'mean componentWillReceiveProps()?', - ); - }); - - it('should throw if a reserved property is in statics', () => { - expect(function() { - React.createClass({ - statics: { - getDefaultProps: function() { - return { - foo: 0, - }; - }, - }, - - render: function() { - return ; - }, - }); - }).toThrowError( - 'ReactClass: You are attempting to define a reserved property, ' + - '`getDefaultProps`, that shouldn\'t be on the "statics" key. Define ' + - 'it as an instance property instead; it will still be accessible on ' + - 'the constructor.', - ); - }); - - // TODO: Consider actually moving these to statics or drop this unit test. - - xit('should warn when using deprecated non-static spec keys', () => { - spyOn(console, 'error'); - React.createClass({ - mixins: [{}], - propTypes: { - foo: React.PropTypes.string, - }, - contextTypes: { - foo: React.PropTypes.string, - }, - childContextTypes: { - foo: React.PropTypes.string, - }, - render: function() { - return
; - }, - }); - expectDev(console.error.calls.count()).toBe(4); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'createClass(...): `mixins` is now a static property and should ' + - 'be defined inside "statics".', - ); - expectDev(console.error.calls.argsFor(1)[0]).toBe( - 'createClass(...): `propTypes` is now a static property and should ' + - 'be defined inside "statics".', - ); - expectDev(console.error.calls.argsFor(2)[0]).toBe( - 'createClass(...): `contextTypes` is now a static property and ' + - 'should be defined inside "statics".', - ); - expectDev(console.error.calls.argsFor(3)[0]).toBe( - 'createClass(...): `childContextTypes` is now a static property and ' + - 'should be defined inside "statics".', - ); - }); - - it('should support statics', () => { - var Component = React.createClass({ - statics: { - abc: 'def', - def: 0, - ghi: null, - jkl: 'mno', - pqr: function() { - return this; - }, - }, - - render: function() { - return ; - }, - }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); - expect(instance.constructor.abc).toBe('def'); - expect(Component.abc).toBe('def'); - expect(instance.constructor.def).toBe(0); - expect(Component.def).toBe(0); - expect(instance.constructor.ghi).toBe(null); - expect(Component.ghi).toBe(null); - expect(instance.constructor.jkl).toBe('mno'); - expect(Component.jkl).toBe('mno'); - expect(instance.constructor.pqr()).toBe(Component); - expect(Component.pqr()).toBe(Component); - }); - - it('should work with object getInitialState() return values', () => { - var Component = React.createClass({ - getInitialState: function() { - return { - occupation: 'clown', - }; - }, - render: function() { - return ; - }, - }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); - expect(instance.state.occupation).toEqual('clown'); - }); - - it('renders based on context getInitialState', () => { - var Foo = React.createClass({ - contextTypes: { - className: React.PropTypes.string, - }, - getInitialState() { - return {className: this.context.className}; - }, - render() { - return ; - }, - }); - - var Outer = React.createClass({ - childContextTypes: { - className: React.PropTypes.string, - }, - getChildContext() { - return {className: 'foo'}; - }, - render() { - return ; - }, - }); - - var container = document.createElement('div'); - ReactDOM.render(, container); - expect(container.firstChild.className).toBe('foo'); - }); - - it('should throw with non-object getInitialState() return values', () => { - [['an array'], 'a string', 1234].forEach(function(state) { - var Component = React.createClass({ - getInitialState: function() { - return state; - }, - render: function() { - return ; - }, - }); - var instance = ; - expect(function() { - instance = ReactTestUtils.renderIntoDocument(instance); - }).toThrowError( - 'Component.getInitialState(): must return an object or null', - ); - }); - }); - - it('should work with a null getInitialState() return value', () => { - var Component = React.createClass({ - getInitialState: function() { - return null; - }, - render: function() { - return ; - }, - }); - expect(() => - ReactTestUtils.renderIntoDocument()).not.toThrow(); - }); - - it('should throw when using legacy factories', () => { - spyOn(console, 'error'); - var Component = React.createClass({ - render() { - return
; - }, - }); - - expect(() => Component()).toThrow(); - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - 'Warning: Something is calling a React component directly. Use a ' + - 'factory or JSX instead. See: https://fb.me/react-legacyfactory', - ); - }); -}); diff --git a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js b/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js deleted file mode 100644 index 2f079a69fc..0000000000 --- a/src/isomorphic/classic/class/__tests__/ReactClassMixin-test.js +++ /dev/null @@ -1,532 +0,0 @@ -/** - * Copyright 2013-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. - * - * @emails react-core - */ - -'use strict'; - -var React; -var ReactTestUtils; - -var TestComponent; -var TestComponentWithPropTypes; -var TestComponentWithReverseSpec; -var mixinPropValidator; -var componentPropValidator; - -describe('ReactClass-mixin', () => { - beforeEach(() => { - React = require('react'); - ReactTestUtils = require('ReactTestUtils'); - mixinPropValidator = jest.fn(); - componentPropValidator = jest.fn(); - - var MixinA = { - propTypes: { - propA: function() {}, - }, - componentDidMount: function() { - this.props.listener('MixinA didMount'); - }, - }; - - var MixinB = { - mixins: [MixinA], - propTypes: { - propB: function() {}, - }, - componentDidMount: function() { - this.props.listener('MixinB didMount'); - }, - }; - - var MixinBWithReverseSpec = { - componentDidMount: function() { - this.props.listener('MixinBWithReverseSpec didMount'); - }, - mixins: [MixinA], - }; - - var MixinC = { - statics: { - staticC: function() {}, - }, - componentDidMount: function() { - this.props.listener('MixinC didMount'); - }, - }; - - var MixinD = { - propTypes: { - value: mixinPropValidator, - }, - }; - - TestComponent = React.createClass({ - mixins: [MixinB, MixinC, MixinD], - statics: { - staticComponent: function() {}, - }, - propTypes: { - propComponent: function() {}, - }, - componentDidMount: function() { - this.props.listener('Component didMount'); - }, - render: function() { - return
; - }, - }); - - TestComponentWithReverseSpec = React.createClass({ - render: function() { - return
; - }, - componentDidMount: function() { - this.props.listener('Component didMount'); - }, - mixins: [MixinBWithReverseSpec, MixinC, MixinD], - }); - - TestComponentWithPropTypes = React.createClass({ - mixins: [MixinD], - propTypes: { - value: componentPropValidator, - }, - render: function() { - return
; - }, - }); - }); - - it('should support merging propTypes and statics', () => { - var listener = jest.fn(); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); - - var instancePropTypes = instance.constructor.propTypes; - - expect('propA' in instancePropTypes).toBe(true); - expect('propB' in instancePropTypes).toBe(true); - expect('propComponent' in instancePropTypes).toBe(true); - - expect('staticC' in TestComponent).toBe(true); - expect('staticComponent' in TestComponent).toBe(true); - }); - - it('should support chaining delegate functions', () => { - var listener = jest.fn(); - var instance = ; - ReactTestUtils.renderIntoDocument(instance); - - expect(listener.mock.calls).toEqual([ - ['MixinA didMount'], - ['MixinB didMount'], - ['MixinC didMount'], - ['Component didMount'], - ]); - }); - - it('should chain functions regardless of spec property order', () => { - var listener = jest.fn(); - var instance = ; - ReactTestUtils.renderIntoDocument(instance); - - expect(listener.mock.calls).toEqual([ - ['MixinA didMount'], - ['MixinBWithReverseSpec didMount'], - ['MixinC didMount'], - ['Component didMount'], - ]); - }); - - it('should validate prop types via mixins', () => { - expect(TestComponent.propTypes).toBeDefined(); - expect(TestComponent.propTypes.value).toBe(mixinPropValidator); - }); - - it('should override mixin prop types with class prop types', () => { - // Sanity check... - expect(componentPropValidator).not.toBe(mixinPropValidator); - // Actually check... - expect(TestComponentWithPropTypes.propTypes).toBeDefined(); - expect(TestComponentWithPropTypes.propTypes.value).not.toBe( - mixinPropValidator, - ); - expect(TestComponentWithPropTypes.propTypes.value).toBe( - componentPropValidator, - ); - }); - - it('should support mixins with getInitialState()', () => { - var Mixin = { - getInitialState: function() { - return {mixin: true}; - }, - }; - var Component = React.createClass({ - mixins: [Mixin], - getInitialState: function() { - return {component: true}; - }, - render: function() { - return ; - }, - }); - var instance = ReactTestUtils.renderIntoDocument(); - expect(instance.state.component).toBe(true); - expect(instance.state.mixin).toBe(true); - }); - - it('should throw with conflicting getInitialState() methods', () => { - var Mixin = { - getInitialState: function() { - return {x: true}; - }, - }; - var Component = React.createClass({ - mixins: [Mixin], - getInitialState: function() { - return {x: true}; - }, - render: function() { - return ; - }, - }); - expect(function() { - ReactTestUtils.renderIntoDocument(); - }).toThrowError( - 'mergeIntoWithNoDuplicateKeys(): Tried to merge two objects with the ' + - 'same key: `x`. This conflict may be due to a mixin; in particular, ' + - 'this may be caused by two getInitialState() or getDefaultProps() ' + - 'methods returning objects with clashing keys.', - ); - }); - - it('should not mutate objects returned by getInitialState()', () => { - var Mixin = { - getInitialState: function() { - return Object.freeze({mixin: true}); - }, - }; - var Component = React.createClass({ - mixins: [Mixin], - getInitialState: function() { - return Object.freeze({component: true}); - }, - render: function() { - return ; - }, - }); - expect(() => { - ReactTestUtils.renderIntoDocument(); - }).not.toThrow(); - }); - - it('should support statics in mixins', () => { - var Mixin = { - statics: { - foo: 'bar', - }, - }; - var Component = React.createClass({ - mixins: [Mixin], - - statics: { - abc: 'def', - }, - - render: function() { - return ; - }, - }); - var instance = ; - instance = ReactTestUtils.renderIntoDocument(instance); - expect(instance.constructor.foo).toBe('bar'); - expect(Component.foo).toBe('bar'); - expect(instance.constructor.abc).toBe('def'); - expect(Component.abc).toBe('def'); - }); - - it("should throw if mixins override each others' statics", () => { - expect(function() { - var Mixin = { - statics: { - abc: 'foo', - }, - }; - React.createClass({ - mixins: [Mixin], - - statics: { - abc: 'bar', - }, - - render: function() { - return ; - }, - }); - }).toThrowError( - 'ReactClass: You are attempting to define `abc` on your component more ' + - 'than once. This conflict may be due to a mixin.', - ); - }); - - it('should throw if mixins override functions in statics', () => { - expect(function() { - var Mixin = { - statics: { - abc: function() { - console.log('foo'); - }, - }, - }; - React.createClass({ - mixins: [Mixin], - - statics: { - abc: function() { - console.log('bar'); - }, - }, - - render: function() { - return ; - }, - }); - }).toThrowError( - 'ReactClass: You are attempting to define `abc` on your component ' + - 'more than once. This conflict may be due to a mixin.', - ); - }); - - it('should warn if the mixin is undefined', () => { - spyOn(console, 'error'); - - React.createClass({ - mixins: [undefined], - - render: function() { - return ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - "Warning: ReactClass: You're attempting to include a mixin that is " + - 'either null or not an object. Check the mixins included by the ' + - 'component, as well as any mixins they include themselves. ' + - 'Expected object but got undefined.', - ); - }); - - it('should warn if the mixin is null', () => { - spyOn(console, 'error'); - - React.createClass({ - mixins: [null], - - render: function() { - return ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - "Warning: ReactClass: You're attempting to include a mixin that is " + - 'either null or not an object. Check the mixins included by the ' + - 'component, as well as any mixins they include themselves. ' + - 'Expected object but got null.', - ); - }); - - it('should warn if an undefined mixin is included in another mixin', () => { - spyOn(console, 'error'); - - var mixinA = { - mixins: [undefined], - }; - - React.createClass({ - mixins: [mixinA], - - render: function() { - return ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - "Warning: ReactClass: You're attempting to include a mixin that is " + - 'either null or not an object. Check the mixins included by the ' + - 'component, as well as any mixins they include themselves. ' + - 'Expected object but got undefined.', - ); - }); - - it('should warn if a null mixin is included in another mixin', () => { - spyOn(console, 'error'); - - var mixinA = { - mixins: [null], - }; - - React.createClass({ - mixins: [mixinA], - - render: function() { - return ; - }, - }); - - expectDev(console.error.calls.count()).toBe(1); - expectDev(console.error.calls.argsFor(0)[0]).toBe( - "Warning: ReactClass: You're attempting to include a mixin that is " + - 'either null or not an object. Check the mixins included by the ' + - 'component, as well as any mixins they include themselves. ' + - 'Expected object but got null.', - ); - }); - - it('should throw if the mixin is a React component', () => { - expect(function() { - React.createClass({ - mixins: [
], - - render: function() { - return ; - }, - }); - }).toThrowError( - "ReactClass: You're attempting to use a component as a mixin. " + - 'Instead, just use a regular object.', - ); - }); - - it('should throw if the mixin is a React component class', () => { - expect(function() { - var Component = React.createClass({ - render: function() { - return ; - }, - }); - - React.createClass({ - mixins: [Component], - - render: function() { - return ; - }, - }); - }).toThrowError( - "ReactClass: You're attempting to use a component class or function " + - 'as a mixin. Instead, just use a regular object.', - ); - }); - - it('should have bound the mixin methods to the component', () => { - var mixin = { - mixinFunc: function() { - return this; - }, - }; - - var Component = React.createClass({ - mixins: [mixin], - componentDidMount: function() { - expect(this.mixinFunc()).toBe(this); - }, - render: function() { - return ; - }, - }); - ReactTestUtils.renderIntoDocument(); - }); - - it('should include the mixin keys in even if their values are falsy', () => { - var mixin = { - keyWithNullValue: null, - randomCounter: 0, - }; - - var Component = React.createClass({ - mixins: [mixin], - componentDidMount: function() { - expect(this.randomCounter).toBe(0); - expect(this.keyWithNullValue).toBeNull(); - }, - render: function() { - return ; - }, - }); - ReactTestUtils.renderIntoDocument(); - }); - - it('should work with a null getInitialState return value and a mixin', () => { - var Component; - var instance; - - var Mixin = { - getInitialState: function() { - return {foo: 'bar'}; - }, - }; - Component = React.createClass({ - mixins: [Mixin], - getInitialState: function() { - return null; - }, - render: function() { - return ; - }, - }); - expect(() => - ReactTestUtils.renderIntoDocument()).not.toThrow(); - - instance = ReactTestUtils.renderIntoDocument(); - expect(instance.state).toEqual({foo: 'bar'}); - - // Also the other way round should work - var Mixin2 = { - getInitialState: function() { - return null; - }, - }; - Component = React.createClass({ - mixins: [Mixin2], - getInitialState: function() { - return {foo: 'bar'}; - }, - render: function() { - return ; - }, - }); - expect(() => - ReactTestUtils.renderIntoDocument()).not.toThrow(); - - instance = ReactTestUtils.renderIntoDocument(); - expect(instance.state).toEqual({foo: 'bar'}); - - // Multiple mixins should be fine too - Component = React.createClass({ - mixins: [Mixin, Mixin2], - getInitialState: function() { - return {x: true}; - }, - render: function() { - return ; - }, - }); - expect(() => - ReactTestUtils.renderIntoDocument()).not.toThrow(); - - instance = ReactTestUtils.renderIntoDocument(); - expect(instance.state).toEqual({foo: 'bar', x: true}); - }); -});