diff --git a/src/core/React.js b/src/core/React.js index 2c63e8795b..511742b5c2 100644 --- a/src/core/React.js +++ b/src/core/React.js @@ -50,6 +50,7 @@ var React = { ), renderComponentToString: ReactServerRendering.renderComponentToString, unmountAndReleaseReactRootNode: ReactMount.unmountAndReleaseReactRootNode, + isValidClass: ReactCompositeComponent.isValidClass, isValidComponent: ReactComponent.isValidComponent }; diff --git a/src/core/ReactCompositeComponent.js b/src/core/ReactCompositeComponent.js index aab39a4265..08edadb7ef 100644 --- a/src/core/ReactCompositeComponent.js +++ b/src/core/ReactCompositeComponent.js @@ -956,6 +956,19 @@ var ReactCompositeComponent = { return ConvenienceConstructor; }, + /** + * Checks if a value is a valid component constructor. + * + * @param {*} + * @return {boolean} + * @public + */ + isValidClass: function(componentClass) { + return componentClass instanceof Function && + 'componentConstructor' in componentClass && + componentClass.componentConstructor instanceof Function; + }, + /** * TODO: Delete this when all callers have been updated to rely on this * behavior being the default. diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js index 752ab19fb4..bc9db48ef8 100644 --- a/src/core/__tests__/ReactCompositeComponent-test.js +++ b/src/core/__tests__/ReactCompositeComponent-test.js @@ -381,4 +381,30 @@ describe('ReactCompositeComponent', function() { ); }); + it('should detect valid CompositeComponent classes', function() { + var Component = React.createClass({ + render: function() { + return
; + } + }); + + expect(React.isValidClass(Component)).toBe(true); + }); + + it('should detect invalid CompositeComponent classes', function() { + var FnComponent = function() { + return false; + } + + var NullComponent = null; + + var TrickFnComponent = function() { + return true; + } + TrickFnComponent.componentConstructor = true; + + expect(React.isValidClass(FnComponent)).toBe(false); + expect(React.isValidClass(NullComponent)).toBe(false); + expect(React.isValidClass(TrickFnComponent)).toBe(false); + }); }); diff --git a/src/core/__tests__/ReactDOM-test.js b/src/core/__tests__/ReactDOM-test.js index fdd88c6757..bd7ce73fdb 100644 --- a/src/core/__tests__/ReactDOM-test.js +++ b/src/core/__tests__/ReactDOM-test.js @@ -23,11 +23,10 @@ var React = require('React'); var ReactDOM = require('ReactDOM'); -var ReactTestUtils = require('ReactTestUtils'); -var React = require('React'); var ReactMount = require('ReactMount'); +var ReactTestUtils = require('ReactTestUtils'); -describe('ref swapping', function() { +describe('ReactDOM', function() { // TODO: uncomment this test once we can run in phantom, which // supports real submit events. /* @@ -115,4 +114,8 @@ describe('ref swapping', function() { var dog = root.childNodes[0]; expect(dog.className).toBe('bigdog'); }); + + it('should be a valid class', function() { + expect(React.isValidClass(ReactDOM.div)).toBe(true); + }); });