diff --git a/src/classic/__tests__/ReactContextValidator-test.js b/src/classic/__tests__/ReactContextValidator-test.js
new file mode 100644
index 0000000000..3f9f8c017b
--- /dev/null
+++ b/src/classic/__tests__/ReactContextValidator-test.js
@@ -0,0 +1,247 @@
+/**
+ * Copyright 2013-2014, 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
+ */
+
+// This test doesn't really have a good home yet. I'm leaving it here since this
+// behavior belongs to the old propTypes system yet is currently implemented
+// in the core ReactCompositeComponent. It should technically live in core's
+// test suite but I'll leave it here to indicate that this is an issue that
+// needs to be fixed.
+
+"use strict";
+
+var React;
+var ReactTestUtils;
+
+var reactComponentExpect;
+var mocks;
+
+describe('ReactContextValidator', function() {
+ beforeEach(function() {
+ require('mock-modules').dumpCache();
+
+ React = require('React');
+ ReactTestUtils = require('ReactTestUtils');
+ reactComponentExpect = require('reactComponentExpect');
+ mocks = require('mocks');
+
+ console.warn = mocks.getMockFunction();
+ });
+
+ // TODO: This behavior creates a runtime dependency on propTypes. We should
+ // ensure that this is not required for ES6 classes with Flow.
+
+ it('should filter out context not in contextTypes', function() {
+ var Component = React.createClass({
+ contextTypes: {
+ foo: React.PropTypes.string
+ },
+
+ render: function() {
+ return
;
+ }
+ });
+
+ var ComponentInFooBarContext = React.createClass({
+ childContextTypes: {
+ foo: React.PropTypes.string,
+ bar: React.PropTypes.number
+ },
+
+ getChildContext: function() {
+ return {
+ foo: 'abc',
+ bar: 123
+ };
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+
+ var instance = ReactTestUtils.renderIntoDocument();
+ reactComponentExpect(instance).expectRenderedChild().scalarContextEqual({foo: 'abc'});
+ });
+
+ it('should filter context properly in callbacks', function() {
+ var actualComponentWillReceiveProps;
+ var actualShouldComponentUpdate;
+ var actualComponentWillUpdate;
+ var actualComponentDidUpdate;
+
+ var Parent = React.createClass({
+ childContextTypes: {
+ foo: React.PropTypes.string.isRequired,
+ bar: React.PropTypes.string.isRequired
+ },
+
+ getChildContext: function() {
+ return {
+ foo: this.props.foo,
+ bar: "bar"
+ };
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+
+ var Component = React.createClass({
+ contextTypes: {
+ foo: React.PropTypes.string
+ },
+
+ componentWillReceiveProps: function(nextProps, nextContext) {
+ actualComponentWillReceiveProps = nextContext;
+ return true;
+ },
+
+ shouldComponentUpdate: function(nextProps, nextState, nextContext) {
+ actualShouldComponentUpdate = nextContext;
+ return true;
+ },
+
+ componentWillUpdate: function(nextProps, nextState, nextContext) {
+ actualComponentWillUpdate = nextContext;
+ },
+
+ componentDidUpdate: function(prevProps, prevState, prevContext) {
+ actualComponentDidUpdate = prevContext;
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+
+ var instance = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ instance.replaceProps({foo: "def"});
+ expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
+ expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
+ expect(actualComponentWillUpdate).toEqual({foo: 'def'});
+ expect(actualComponentDidUpdate).toEqual({foo: 'abc'});
+ });
+
+ it('should check context types', function() {
+ var Component = React.createClass({
+ contextTypes: {
+ foo: React.PropTypes.string.isRequired
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+
+ ReactTestUtils.renderIntoDocument();
+
+ expect(console.warn.mock.calls.length).toBe(1);
+ expect(console.warn.mock.calls[0][0]).toBe(
+ 'Warning: Required context `foo` was not specified in `Component`.'
+ );
+
+ var ComponentInFooStringContext = React.createClass({
+ childContextTypes: {
+ foo: React.PropTypes.string
+ },
+
+ getChildContext: function() {
+ return {
+ foo: this.props.fooValue
+ };
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+
+ ReactTestUtils.renderIntoDocument(
+
+ );
+
+ // Previous call should not error
+ expect(console.warn.mock.calls.length).toBe(1);
+
+ var ComponentInFooNumberContext = React.createClass({
+ childContextTypes: {
+ foo: React.PropTypes.number
+ },
+
+ getChildContext: function() {
+ return {
+ foo: this.props.fooValue
+ };
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+
+ ReactTestUtils.renderIntoDocument();
+
+ expect(console.warn.mock.calls.length).toBe(2);
+ expect(console.warn.mock.calls[1][0]).toBe(
+ 'Warning: Invalid context `foo` of type `number` supplied ' +
+ 'to `Component`, expected `string`.' +
+ ' Check the render method of `ComponentInFooNumberContext`.'
+ );
+ });
+
+ it('should check child context types', function() {
+ var Component = React.createClass({
+ childContextTypes: {
+ foo: React.PropTypes.string.isRequired,
+ bar: React.PropTypes.number
+ },
+
+ getChildContext: function() {
+ return this.props.testContext;
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+
+ ReactTestUtils.renderIntoDocument();
+ expect(console.warn.mock.calls.length).toBe(2);
+ expect(console.warn.mock.calls[0][0]).toBe(
+ 'Warning: Required child context `foo` was not specified in `Component`.'
+ );
+ expect(console.warn.mock.calls[1][0]).toBe(
+ 'Warning: Required child context `foo` was not specified in `Component`.'
+ );
+
+ ReactTestUtils.renderIntoDocument();
+
+ expect(console.warn.mock.calls.length).toBe(4);
+ expect(console.warn.mock.calls[3][0]).toBe(
+ 'Warning: Invalid child context `foo` of type `number` ' +
+ 'supplied to `Component`, expected `string`.'
+ );
+
+ ReactTestUtils.renderIntoDocument(
+
+ );
+
+ ReactTestUtils.renderIntoDocument(
+
+ );
+
+ // Previous calls should not log errors
+ expect(console.warn.mock.calls.length).toBe(4);
+ });
+
+});
diff --git a/src/class/ReactClass.js b/src/classic/class/ReactClass.js
similarity index 100%
rename from src/class/ReactClass.js
rename to src/classic/class/ReactClass.js
diff --git a/src/core/ReactDoNotBindDeprecated.js b/src/classic/class/ReactDoNotBindDeprecated.js
similarity index 100%
rename from src/core/ReactDoNotBindDeprecated.js
rename to src/classic/class/ReactDoNotBindDeprecated.js
diff --git a/src/core/__tests__/ReactBind-test.js b/src/classic/class/__tests__/ReactBind-test.js
similarity index 100%
rename from src/core/__tests__/ReactBind-test.js
rename to src/classic/class/__tests__/ReactBind-test.js
diff --git a/src/classic/class/__tests__/ReactClass-test.js b/src/classic/class/__tests__/ReactClass-test.js
new file mode 100644
index 0000000000..edabe5a057
--- /dev/null
+++ b/src/classic/class/__tests__/ReactClass-test.js
@@ -0,0 +1,338 @@
+/**
+ * Copyright 2013-2014, 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 mocks = require('mocks');
+
+var React;
+var ReactTestUtils;
+var reactComponentExpect;
+
+describe('ReactClass-spec', function() {
+
+ beforeEach(function() {
+ React = require('React');
+ ReactTestUtils = require('ReactTestUtils');
+ reactComponentExpect = require('reactComponentExpect');
+ });
+
+ it('should throw when `render` is not specified', function() {
+ expect(function() {
+ React.createClass({});
+ }).toThrow(
+ 'Invariant Violation: createClass(...): Class specification must ' +
+ 'implement a `render` method.'
+ );
+ });
+
+ it('should copy `displayName` onto the Constructor', function() {
+ var TestComponent = React.createClass({
+ render: function() {
+ return ;
+ }
+ });
+
+ expect(TestComponent.displayName)
+ .toBe('TestComponent');
+ });
+
+ it('should copy prop types onto the Constructor', function() {
+ var propValidator = mocks.getMockFunction();
+ var TestComponent = React.createClass({
+ propTypes: {
+ value: propValidator
+ },
+ render: function() {
+ return ;
+ }
+ });
+
+ expect(TestComponent.propTypes).toBeDefined();
+ expect(TestComponent.propTypes.value)
+ .toBe(propValidator);
+ });
+
+ it('should throw on invalid prop types', function() {
+ expect(function() {
+ React.createClass({
+ displayName: 'Component',
+ propTypes: {
+ prop: null
+ },
+ render: function() {
+ return {this.props.prop};
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: Component: prop type `prop` is invalid; ' +
+ 'it must be a function, usually from React.PropTypes.'
+ );
+ });
+
+ it('should throw on invalid context types', function() {
+ expect(function() {
+ React.createClass({
+ displayName: 'Component',
+ contextTypes: {
+ prop: null
+ },
+ render: function() {
+ return {this.props.prop};
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: Component: context type `prop` is invalid; ' +
+ 'it must be a function, usually from React.PropTypes.'
+ );
+ });
+
+ it('should throw on invalid child context types', function() {
+ expect(function() {
+ React.createClass({
+ displayName: 'Component',
+ childContextTypes: {
+ prop: null
+ },
+ render: function() {
+ return {this.props.prop};
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: Component: child context type `prop` is invalid; ' +
+ 'it must be a function, usually from React.PropTypes.'
+ );
+ });
+
+ it('should warn when mispelling shouldComponentUpdate', function() {
+ var warn = console.warn;
+ console.warn = mocks.getMockFunction();
+
+ try {
+ React.createClass({
+ componentShouldUpdate: function() {
+ return false;
+ },
+ render: function() {
+ return ;
+ }
+ });
+ expect(console.warn.mock.calls.length).toBe(1);
+ expect(console.warn.mock.calls[0][0]).toBe(
+ '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.'
+ );
+
+ var NamedComponent = React.createClass({
+ componentShouldUpdate: function() {
+ return false;
+ },
+ render: function() {
+ return ;
+ }
+ });
+ expect(console.warn.mock.calls.length).toBe(2);
+ expect(console.warn.mock.calls[1][0]).toBe(
+ '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.'
+ );
+
+ ; // Shut up lint
+ } finally {
+ console.warn = warn;
+ }
+ });
+
+ it('should throw if a reserved property is in statics', function() {
+ expect(function() {
+ React.createClass({
+ statics: {
+ getDefaultProps: function() {
+ return {
+ foo: 0
+ };
+ }
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: 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', function() {
+ var warn = console.warn;
+ console.warn = mocks.getMockFunction();
+ try {
+ React.createClass({
+ mixins: [{}],
+ propTypes: {
+ foo: ReactPropTypes.string
+ },
+ contextTypes: {
+ foo: ReactPropTypes.string
+ },
+ childContextTypes: {
+ foo: ReactPropTypes.string
+ },
+ render: function() {
+ return ;
+ }
+ });
+ expect(console.warn.mock.calls.length).toBe(4);
+ expect(console.warn.mock.calls[0][0]).toBe(
+ 'createClass(...): `mixins` is now a static property and should ' +
+ 'be defined inside "statics".'
+ );
+ expect(console.warn.mock.calls[1][0]).toBe(
+ 'createClass(...): `propTypes` is now a static property and should ' +
+ 'be defined inside "statics".'
+ );
+ expect(console.warn.mock.calls[2][0]).toBe(
+ 'createClass(...): `contextTypes` is now a static property and ' +
+ 'should be defined inside "statics".'
+ );
+ expect(console.warn.mock.calls[3][0]).toBe(
+ 'createClass(...): `childContextTypes` is now a static property and ' +
+ 'should be defined inside "statics".'
+ );
+ } finally {
+ console.warn = warn;
+ }
+ });
+
+ it('should support statics', function() {
+ 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', function() {
+ 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('should throw with non-object getInitialState() return values', function() {
+ [['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);
+ }).toThrow(
+ 'Invariant Violation: Component.getInitialState(): ' +
+ 'must return an object or null'
+ );
+ });
+ });
+
+ it('should work with a null getInitialState() return value', function() {
+ var Component = React.createClass({
+ getInitialState: function() {
+ return null;
+ },
+ render: function() {
+ return ;
+ }
+ });
+ expect(
+ () => ReactTestUtils.renderIntoDocument()
+ ).not.toThrow();
+ });
+
+ it('should work with object getInitialState() return values', function() {
+ 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('should throw with non-object getInitialState() return values', function() {
+ [['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);
+ }).toThrow(
+ 'Invariant Violation: Component.getInitialState(): ' +
+ 'must return an object or null'
+ );
+ });
+ });
+
+});
diff --git a/src/classic/class/__tests__/ReactClassMixin-test.js b/src/classic/class/__tests__/ReactClassMixin-test.js
new file mode 100644
index 0000000000..1db776f590
--- /dev/null
+++ b/src/classic/class/__tests__/ReactClassMixin-test.js
@@ -0,0 +1,459 @@
+/**
+ * Copyright 2013-2014, 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 mocks = require('mocks');
+
+var React;
+var ReactTestUtils;
+var reactComponentExpect;
+
+var TestComponent;
+var TestComponentWithPropTypes;
+var TestComponentWithReverseSpec;
+var mixinPropValidator;
+var componentPropValidator;
+
+describe('ReactClass-mixin', function() {
+
+ beforeEach(function() {
+ React = require('React');
+ ReactTestUtils = require('ReactTestUtils');
+ reactComponentExpect = require('reactComponentExpect');
+ mixinPropValidator = mocks.getMockFunction();
+ componentPropValidator = mocks.getMockFunction();
+
+ 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', function() {
+ var listener = mocks.getMockFunction();
+ 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', function() {
+ var listener = mocks.getMockFunction();
+ var instance = ;
+ 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', function() {
+ var listener = mocks.getMockFunction();
+ var instance = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+
+ expect(listener.mock.calls).toEqual([
+ ['MixinA didMount'],
+ ['MixinBWithReverseSpec didMount'],
+ ['MixinC didMount'],
+ ['Component didMount']
+ ]);
+ });
+
+ it('should validate prop types via mixins', function() {
+ expect(TestComponent.propTypes).toBeDefined();
+ expect(TestComponent.propTypes.value)
+ .toBe(mixinPropValidator);
+ });
+
+ it('should override mixin prop types with class prop types', function() {
+ // Sanity check...
+ expect(componentPropValidator).toNotBe(mixinPropValidator);
+ // Actually check...
+ expect(TestComponentWithPropTypes.propTypes)
+ .toBeDefined();
+ expect(TestComponentWithPropTypes.propTypes.value)
+ .toNotBe(mixinPropValidator);
+ expect(TestComponentWithPropTypes.propTypes.value)
+ .toBe(componentPropValidator);
+ });
+
+
+ it('should support mixins with getInitialState()', function() {
+ var Mixin = {
+ getInitialState: function() {
+ return {mixin: true};
+ }
+ };
+ var Component = React.createClass({
+ mixins: [Mixin],
+ getInitialState: function() {
+ return {component: true};
+ },
+ render: function() {
+ return ;
+ }
+ });
+ var instance = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ expect(instance.state.component).toBe(true);
+ expect(instance.state.mixin).toBe(true);
+ });
+
+ it('should throw with conflicting getInitialState() methods', function() {
+ var Mixin = {
+ getInitialState: function() {
+ return {x: true};
+ }
+ };
+ var Component = React.createClass({
+ mixins: [Mixin],
+ getInitialState: function() {
+ return {x: true};
+ },
+ render: function() {
+ return ;
+ }
+ });
+ var instance = ;
+ expect(function() {
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ }).toThrow(
+ 'Invariant Violation: 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()', function() {
+ 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', function() {
+ 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", function() {
+ expect(function() {
+ var Mixin = {
+ statics: {
+ abc: 'foo'
+ }
+ };
+ React.createClass({
+ mixins: [Mixin],
+
+ statics: {
+ abc: 'bar'
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: 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", function() {
+ expect(function() {
+ var Mixin = {
+ statics: {
+ abc: function() { console.log('foo'); }
+ }
+ };
+ React.createClass({
+ mixins: [Mixin],
+
+ statics: {
+ abc: function() { console.log('bar'); }
+ },
+
+ render: function() {
+ return ;
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: 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 the mixin is a React component", function() {
+ expect(function() {
+ React.createClass({
+ mixins: [],
+
+ render: function() {
+ return ;
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: 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", function() {
+ expect(function() {
+ var Component = React.createClass({
+ render: function() {
+ return ;
+ }
+ });
+
+ React.createClass({
+ mixins: [Component],
+
+ render: function() {
+ return ;
+ }
+ });
+ }).toThrow(
+ 'Invariant Violation: ReactClass: You\'re attempting to ' +
+ 'use a component class as a mixin. Instead, just use a regular object.'
+ );
+ });
+
+ it('should have bound the mixin methods to the component', function() {
+ var mixin = {
+ mixinFunc: function() {return this;}
+ };
+
+ var Component = React.createClass({
+ mixins: [mixin],
+ componentDidMount: function() {
+ expect(this.mixinFunc()).toBe(this);
+ },
+ render: function() {
+ return ;
+ }
+ });
+ var instance = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ });
+
+ it('should include the mixin keys in even if their values are falsy',
+ function() {
+ 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 ;
+ }
+ });
+ var instance = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ });
+
+ 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 = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ 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 = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ 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 = ;
+ instance = ReactTestUtils.renderIntoDocument(instance);
+ expect(instance.state).toEqual({foo: 'bar', x: true});
+ });
+
+});
diff --git a/src/core/ReactElement.js b/src/classic/element/ReactElement.js
similarity index 100%
rename from src/core/ReactElement.js
rename to src/classic/element/ReactElement.js
diff --git a/src/core/ReactElementValidator.js b/src/classic/element/ReactElementValidator.js
similarity index 100%
rename from src/core/ReactElementValidator.js
rename to src/classic/element/ReactElementValidator.js
diff --git a/src/core/__tests__/ReactElement-test.js b/src/classic/element/__tests__/ReactElement-test.js
similarity index 87%
rename from src/core/__tests__/ReactElement-test.js
rename to src/classic/element/__tests__/ReactElement-test.js
index c4c348fff1..0f64f24d8b 100644
--- a/src/core/__tests__/ReactElement-test.js
+++ b/src/classic/element/__tests__/ReactElement-test.js
@@ -11,6 +11,8 @@
"use strict";
+var mocks;
+
var React;
var ReactElement;
var ReactTestUtils;
@@ -21,6 +23,8 @@ describe('ReactElement', function() {
beforeEach(function() {
require('mock-modules').dumpCache();
+ mocks = require('mocks');
+
React = require('React');
ReactElement = require('ReactElement');
ReactTestUtils = require('ReactTestUtils');
@@ -370,4 +374,56 @@ describe('ReactElement', function() {
expect(element.constructor).toBe(object.constructor);
});
+ it('should use default prop value when removing a prop', function() {
+ var Component = React.createClass({
+ getDefaultProps: function() {
+ return {fruit: 'persimmon'};
+ },
+ render: function() {
+ return ;
+ }
+ });
+
+ var container = document.createElement('div');
+ var instance = React.render(
+ ,
+ container
+ );
+ expect(instance.props.fruit).toBe('mango');
+
+ React.render(, container);
+ expect(instance.props.fruit).toBe('persimmon');
+ });
+
+ it('should normalize props with default values', function() {
+ var warn = console.warn;
+ console.warn = mocks.getMockFunction();
+
+ var Component = React.createClass({
+ propTypes: {prop: React.PropTypes.string.isRequired},
+ getDefaultProps: function() {
+ return {prop: 'testKey'};
+ },
+ getInitialState: function() {
+ return {prop: this.props.prop + 'State'};
+ },
+ render: function() {
+ return {this.props.prop};
+ }
+ });
+
+ var instance = ReactTestUtils.renderIntoDocument();
+ expect(instance.props.prop).toBe('testKey');
+ expect(instance.state.prop).toBe('testKeyState');
+
+ ReactTestUtils.renderIntoDocument();
+
+ expect(console.warn.mock.calls.length).toBe(1);
+ expect(console.warn.mock.calls[0][0]).toBe(
+ 'Warning: Required prop `prop` was not specified in `Component`.'
+ );
+
+ console.warn = warn;
+ });
+
});
diff --git a/src/classic/element/__tests__/ReactElementValidator-test.js b/src/classic/element/__tests__/ReactElementValidator-test.js
new file mode 100644
index 0000000000..490dc9182f
--- /dev/null
+++ b/src/classic/element/__tests__/ReactElementValidator-test.js
@@ -0,0 +1,110 @@
+/**
+ * Copyright 2013-2014, 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;
+
+describe('ReactElementValidator', function() {
+ var ComponentClass;
+
+ beforeEach(function() {
+ require('mock-modules').dumpCache();
+
+ React = require('React');
+ ReactTestUtils = require('ReactTestUtils');
+ ComponentClass = React.createClass({
+ render: function() { return ; }
+ });
+ });
+
+ // TODO: These warnings currently come from the composite component, but
+ // they should be moved into the ReactElementValidator.
+
+ it('should give context for PropType errors in nested components.', () => {
+ // In this test, we're making sure that if a proptype error is found in a
+ // component, we give a small hint as to which parent instantiated that
+ // component as per warnings about key usage in ReactElementValidator.
+ spyOn(console, 'warn');
+ var MyComp = React.createClass({
+ propTypes: {
+ color: React.PropTypes.string
+ },
+ render: function() {
+ return My color is {this.color}
;
+ }
+ });
+ var ParentComp = React.createClass({
+ render: function() {
+ return ;
+ }
+ });
+ ReactTestUtils.renderIntoDocument();
+ expect(console.warn.calls[0].args[0]).toBe(
+ 'Warning: Invalid prop `color` of type `number` supplied to `MyComp`, ' +
+ 'expected `string`. Check the render method of `ParentComp`.'
+ );
+ });
+
+ it('should check default prop values', function() {
+ spyOn(console, 'warn');
+
+ var Component = React.createClass({
+ propTypes: {prop: React.PropTypes.string.isRequired},
+ getDefaultProps: function() {
+ return {prop: null};
+ },
+ render: function() {
+ return {this.props.prop};
+ }
+ });
+
+ ReactTestUtils.renderIntoDocument();
+
+ expect(console.warn.calls.length).toBe(1);
+ expect(console.warn.calls[0].args[0]).toBe(
+ 'Warning: Required prop `prop` was not specified in `Component`.'
+ );
+ });
+
+ it('should check declared prop types', function() {
+ spyOn(console, 'warn');
+
+ var Component = React.createClass({
+ propTypes: {
+ prop: React.PropTypes.string.isRequired
+ },
+ render: function() {
+ return {this.props.prop};
+ }
+ });
+
+ ReactTestUtils.renderIntoDocument();
+ ReactTestUtils.renderIntoDocument();
+
+ expect(console.warn.calls.length).toBe(2);
+ expect(console.warn.calls[0].args[0]).toBe(
+ 'Warning: Required prop `prop` was not specified in `Component`.'
+ );
+
+ expect(console.warn.calls[1].args[0]).toBe(
+ 'Warning: Invalid prop `prop` of type `number` supplied to ' +
+ '`Component`, expected `string`.'
+ );
+
+ ReactTestUtils.renderIntoDocument();
+
+ // Should not error for strings
+ expect(console.warn.calls.length).toBe(2);
+ });
+
+});
diff --git a/src/core/ReactPropTypeLocationNames.js b/src/classic/propTypes/ReactPropTypeLocationNames.js
similarity index 100%
rename from src/core/ReactPropTypeLocationNames.js
rename to src/classic/propTypes/ReactPropTypeLocationNames.js
diff --git a/src/core/ReactPropTypeLocations.js b/src/classic/propTypes/ReactPropTypeLocations.js
similarity index 100%
rename from src/core/ReactPropTypeLocations.js
rename to src/classic/propTypes/ReactPropTypeLocations.js
diff --git a/src/core/ReactPropTypes.js b/src/classic/propTypes/ReactPropTypes.js
similarity index 100%
rename from src/core/ReactPropTypes.js
rename to src/classic/propTypes/ReactPropTypes.js
diff --git a/src/core/__tests__/ReactPropTypes-test.js b/src/classic/propTypes/__tests__/ReactPropTypes-test.js
similarity index 100%
rename from src/core/__tests__/ReactPropTypes-test.js
rename to src/classic/propTypes/__tests__/ReactPropTypes-test.js
diff --git a/src/core/__tests__/ReactCompositeComponent-test.js b/src/core/__tests__/ReactCompositeComponent-test.js
index 299a5ccf5c..101f2218e6 100644
--- a/src/core/__tests__/ReactCompositeComponent-test.js
+++ b/src/core/__tests__/ReactCompositeComponent-test.js
@@ -85,31 +85,6 @@ describe('ReactCompositeComponent', function() {
console.warn = warn;
});
- it('should give context for PropType errors in nested components.', () => {
- // In this test, we're making sure that if a proptype error is found in a
- // component, we give a small hint as to which parent instantiated that
- // component as per warnings about key usage in ReactElementValidator.
- spyOn(console, 'warn');
- var MyComp = React.createClass({
- propTypes: {
- color: ReactPropTypes.string
- },
- render: function() {
- return My color is {this.color}
;
- }
- });
- var ParentComp = React.createClass({
- render: function() {
- return ;
- }
- });
- ReactTestUtils.renderIntoDocument();
- expect(console.warn.calls[0].args[0]).toBe(
- 'Warning: Invalid prop `color` of type `number` supplied to `MyComp`, ' +
- 'expected `string`. Check the render method of `ParentComp`.'
- );
- });
-
it('should support rendering to different child types over time', function() {
var instance = ;
instance = ReactTestUtils.renderIntoDocument(instance);
@@ -299,152 +274,6 @@ describe('ReactCompositeComponent', function() {
expect(inputProps.prop).not.toBeDefined();
});
- it('should use default prop value when removing a prop', function() {
- var Component = React.createClass({
- getDefaultProps: function() {
- return {fruit: 'persimmon'};
- },
- render: function() {
- return ;
- }
- });
-
- var container = document.createElement('div');
- var instance = React.render(
- ,
- container
- );
- expect(instance.props.fruit).toBe('mango');
-
- React.render(, container);
- expect(instance.props.fruit).toBe('persimmon');
- });
-
- it('should normalize props with default values', function() {
- var Component = React.createClass({
- propTypes: {prop: ReactPropTypes.string.isRequired},
- getDefaultProps: function() {
- return {prop: 'testKey'};
- },
- getInitialState: function() {
- return {prop: this.props.prop + 'State'};
- },
- render: function() {
- return {this.props.prop};
- }
- });
-
- var instance = ReactTestUtils.renderIntoDocument();
- reactComponentExpect(instance).scalarPropsEqual({prop: 'testKey'});
- reactComponentExpect(instance).scalarStateEqual({prop: 'testKeyState'});
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.warn.mock.calls.length).toBe(1);
- expect(console.warn.mock.calls[0][0]).toBe(
- 'Warning: Required prop `prop` was not specified in `Component`.'
- );
- });
-
- it('should check default prop values', function() {
- var Component = React.createClass({
- propTypes: {prop: ReactPropTypes.string.isRequired},
- getDefaultProps: function() {
- return {prop: null};
- },
- render: function() {
- return {this.props.prop};
- }
- });
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.warn.mock.calls.length).toBe(1);
- expect(console.warn.mock.calls[0][0]).toBe(
- 'Warning: Required prop `prop` was not specified in `Component`.'
- );
- });
-
- it('should check declared prop types', function() {
- var Component = React.createClass({
- propTypes: {
- prop: ReactPropTypes.string.isRequired
- },
- render: function() {
- return {this.props.prop};
- }
- });
-
- ReactTestUtils.renderIntoDocument();
- ReactTestUtils.renderIntoDocument();
-
- expect(console.warn.mock.calls.length).toBe(2);
- expect(console.warn.mock.calls[0][0]).toBe(
- 'Warning: Required prop `prop` was not specified in `Component`.'
- );
-
- expect(console.warn.mock.calls[1][0]).toBe(
- 'Warning: Invalid prop `prop` of type `number` supplied to ' +
- '`Component`, expected `string`.'
- );
-
- ReactTestUtils.renderIntoDocument();
-
- // Should not error for strings
- expect(console.warn.mock.calls.length).toBe(2);
- });
-
- it('should throw on invalid prop types', function() {
- expect(function() {
- React.createClass({
- displayName: 'Component',
- propTypes: {
- prop: null
- },
- render: function() {
- return {this.props.prop};
- }
- });
- }).toThrow(
- 'Invariant Violation: Component: prop type `prop` is invalid; ' +
- 'it must be a function, usually from React.PropTypes.'
- );
- });
-
- it('should throw on invalid context types', function() {
- expect(function() {
- React.createClass({
- displayName: 'Component',
- contextTypes: {
- prop: null
- },
- render: function() {
- return {this.props.prop};
- }
- });
- }).toThrow(
- 'Invariant Violation: Component: context type `prop` is invalid; ' +
- 'it must be a function, usually from React.PropTypes.'
- );
- });
-
- it('should throw on invalid child context types', function() {
- expect(function() {
- React.createClass({
- displayName: 'Component',
- childContextTypes: {
- prop: null
- },
- render: function() {
- return {this.props.prop};
- }
- });
- }).toThrow(
- 'Invariant Violation: Component: child context type `prop` is invalid; ' +
- 'it must be a function, usually from React.PropTypes.'
- );
- });
-
it('should not allow `forceUpdate` on unmounted components', function() {
var container = document.createElement('div');
document.documentElement.appendChild(container);
@@ -574,228 +403,6 @@ describe('ReactCompositeComponent', function() {
expect(ReactCurrentOwner.current).toBe(null);
});
- it('should support mixins with getInitialState()', function() {
- var Mixin = {
- getInitialState: function() {
- return {mixin: true};
- }
- };
- var Component = React.createClass({
- mixins: [Mixin],
- getInitialState: function() {
- return {component: true};
- },
- render: function() {
- return ;
- }
- });
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state.component).toBe(true);
- expect(instance.state.mixin).toBe(true);
- });
-
- it('should throw with conflicting getInitialState() methods', function() {
- var Mixin = {
- getInitialState: function() {
- return {x: true};
- }
- };
- var Component = React.createClass({
- mixins: [Mixin],
- getInitialState: function() {
- return {x: true};
- },
- render: function() {
- return ;
- }
- });
- var instance = ;
- expect(function() {
- instance = ReactTestUtils.renderIntoDocument(instance);
- }).toThrow(
- 'Invariant Violation: 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()', function() {
- 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 work with object getInitialState() return values', function() {
- 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('should throw with non-object getInitialState() return values', function() {
- [['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);
- }).toThrow(
- 'Invariant Violation: Component.getInitialState(): ' +
- 'must return an object or null'
- );
- });
- });
-
- it('should work with a null getInitialState() return value', function() {
- var Component = React.createClass({
- getInitialState: function() {
- return null;
- },
- render: function() {
- return ;
- }
- });
- expect(
- () => ReactTestUtils.renderIntoDocument()
- ).not.toThrow();
- });
-
- 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 = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- 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 = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- 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 = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- expect(instance.state).toEqual({foo: 'bar', x: true});
- });
-
- it('should work with object getInitialState() return values', function() {
- 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('should throw with non-object getInitialState() return values', function() {
- [['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);
- }).toThrow(
- 'Invariant Violation: Component.getInitialState(): ' +
- 'must return an object or null'
- );
- });
- });
-
it('should call componentWillUnmount before unmounting', function() {
var container = document.createElement('div');
var innerUnmounted = false;
@@ -866,88 +473,6 @@ describe('ReactCompositeComponent', function() {
}
});
- it('should warn when mispelling shouldComponentUpdate', function() {
- var warn = console.warn;
- console.warn = mocks.getMockFunction();
-
- try {
- React.createClass({
- componentShouldUpdate: function() {
- return false;
- },
- render: function() {
- return ;
- }
- });
- expect(console.warn.mock.calls.length).toBe(1);
- expect(console.warn.mock.calls[0][0]).toBe(
- '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.'
- );
-
- var NamedComponent = React.createClass({
- componentShouldUpdate: function() {
- return false;
- },
- render: function() {
- return ;
- }
- });
- expect(console.warn.mock.calls.length).toBe(2);
- expect(console.warn.mock.calls[1][0]).toBe(
- '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.'
- );
-
- ; // Shut up lint
- } finally {
- console.warn = warn;
- }
- });
-
- xit('should warn when using deprecated non-static spec keys', function() {
- var warn = console.warn;
- console.warn = mocks.getMockFunction();
- try {
- React.createClass({
- mixins: [{}],
- propTypes: {
- foo: ReactPropTypes.string
- },
- contextTypes: {
- foo: ReactPropTypes.string
- },
- childContextTypes: {
- foo: ReactPropTypes.string
- },
- render: function() {
- return ;
- }
- });
- expect(console.warn.mock.calls.length).toBe(4);
- expect(console.warn.mock.calls[0][0]).toBe(
- 'createClass(...): `mixins` is now a static property and should ' +
- 'be defined inside "statics".'
- );
- expect(console.warn.mock.calls[1][0]).toBe(
- 'createClass(...): `propTypes` is now a static property and should ' +
- 'be defined inside "statics".'
- );
- expect(console.warn.mock.calls[2][0]).toBe(
- 'createClass(...): `contextTypes` is now a static property and ' +
- 'should be defined inside "statics".'
- );
- expect(console.warn.mock.calls[3][0]).toBe(
- 'createClass(...): `childContextTypes` is now a static property and ' +
- 'should be defined inside "statics".'
- );
- } finally {
- console.warn = warn;
- }
- });
-
it('should pass context', function() {
var childInstance = null;
var grandchildInstance = null;
@@ -1074,413 +599,6 @@ describe('ReactCompositeComponent', function() {
});
- it('should check context types', function() {
- var Component = React.createClass({
- contextTypes: {
- foo: ReactPropTypes.string.isRequired
- },
-
- render: function() {
- return ;
- }
- });
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.warn.mock.calls.length).toBe(1);
- expect(console.warn.mock.calls[0][0]).toBe(
- 'Warning: Required context `foo` was not specified in `Component`.'
- );
-
- var ComponentInFooStringContext = React.createClass({
- childContextTypes: {
- foo: ReactPropTypes.string
- },
-
- getChildContext: function() {
- return {
- foo: this.props.fooValue
- };
- },
-
- render: function() {
- return ;
- }
- });
-
- ReactTestUtils.renderIntoDocument();
-
- // Previous call should not error
- expect(console.warn.mock.calls.length).toBe(1);
-
- var ComponentInFooNumberContext = React.createClass({
- childContextTypes: {
- foo: ReactPropTypes.number
- },
-
- getChildContext: function() {
- return {
- foo: this.props.fooValue
- };
- },
-
- render: function() {
- return ;
- }
- });
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.warn.mock.calls.length).toBe(2);
- expect(console.warn.mock.calls[1][0]).toBe(
- 'Warning: Invalid context `foo` of type `number` supplied ' +
- 'to `Component`, expected `string`.' +
- ' Check the render method of `ComponentInFooNumberContext`.'
- );
- });
-
- it('should check child context types', function() {
- var Component = React.createClass({
- childContextTypes: {
- foo: ReactPropTypes.string.isRequired,
- bar: ReactPropTypes.number
- },
-
- getChildContext: function() {
- return this.props.testContext;
- },
-
- render: function() {
- return ;
- }
- });
-
- ReactTestUtils.renderIntoDocument();
- expect(console.warn.mock.calls.length).toBe(2);
- expect(console.warn.mock.calls[0][0]).toBe(
- 'Warning: Required child context `foo` was not specified in `Component`.'
- );
- expect(console.warn.mock.calls[1][0]).toBe(
- 'Warning: Required child context `foo` was not specified in `Component`.'
- );
-
- ReactTestUtils.renderIntoDocument();
-
- expect(console.warn.mock.calls.length).toBe(4);
- expect(console.warn.mock.calls[3][0]).toBe(
- 'Warning: Invalid child context `foo` of type `number` ' +
- 'supplied to `Component`, expected `string`.'
- );
-
- ReactTestUtils.renderIntoDocument(
-
- );
-
- ReactTestUtils.renderIntoDocument(
-
- );
-
- // Previous calls should not log errors
- expect(console.warn.mock.calls.length).toBe(4);
- });
-
- it('should filter out context not in contextTypes', function() {
- var Component = React.createClass({
- contextTypes: {
- foo: ReactPropTypes.string
- },
-
- render: function() {
- return ;
- }
- });
-
- var ComponentInFooBarContext = React.createClass({
- childContextTypes: {
- foo: ReactPropTypes.string,
- bar: ReactPropTypes.number
- },
-
- getChildContext: function() {
- return {
- foo: 'abc',
- bar: 123
- };
- },
-
- render: function() {
- return ;
- }
- });
-
- var instance = ReactTestUtils.renderIntoDocument();
- reactComponentExpect(instance).expectRenderedChild().scalarContextEqual({foo: 'abc'});
- });
-
- it('should filter context properly in callbacks', function() {
- var actualComponentWillReceiveProps;
- var actualShouldComponentUpdate;
- var actualComponentWillUpdate;
- var actualComponentDidUpdate;
-
- var Parent = React.createClass({
- childContextTypes: {
- foo: ReactPropTypes.string.isRequired,
- bar: ReactPropTypes.string.isRequired
- },
-
- getChildContext: function() {
- return {
- foo: this.props.foo,
- bar: "bar"
- };
- },
-
- render: function() {
- return ;
- }
- });
-
- var Component = React.createClass({
- contextTypes: {
- foo: ReactPropTypes.string
- },
-
- componentWillReceiveProps: function(nextProps, nextContext) {
- actualComponentWillReceiveProps = nextContext;
- return true;
- },
-
- shouldComponentUpdate: function(nextProps, nextState, nextContext) {
- actualShouldComponentUpdate = nextContext;
- return true;
- },
-
- componentWillUpdate: function(nextProps, nextState, nextContext) {
- actualComponentWillUpdate = nextContext;
- },
-
- componentDidUpdate: function(prevProps, prevState, prevContext) {
- actualComponentDidUpdate = prevContext;
- },
-
- render: function() {
- return ;
- }
- });
-
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- instance.replaceProps({foo: "def"});
- expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
- expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
- expect(actualComponentWillUpdate).toEqual({foo: 'def'});
- expect(actualComponentDidUpdate).toEqual({foo: 'abc'});
- });
-
- it('should support statics', function() {
- 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 throw if a reserved property is in statics', function() {
- expect(function() {
- React.createClass({
- statics: {
- getDefaultProps: function() {
- return {
- foo: 0
- };
- }
- },
-
- render: function() {
- return ;
- }
- });
- }).toThrow(
- 'Invariant Violation: 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.'
- );
- });
-
- it('should support statics in mixins', function() {
- 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", function() {
- expect(function() {
- var Mixin = {
- statics: {
- abc: 'foo'
- }
- };
- React.createClass({
- mixins: [Mixin],
-
- statics: {
- abc: 'bar'
- },
-
- render: function() {
- return ;
- }
- });
- }).toThrow(
- 'Invariant Violation: 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", function() {
- expect(function() {
- var Mixin = {
- statics: {
- abc: function() { console.log('foo'); }
- }
- };
- React.createClass({
- mixins: [Mixin],
-
- statics: {
- abc: function() { console.log('bar'); }
- },
-
- render: function() {
- return ;
- }
- });
- }).toThrow(
- 'Invariant Violation: 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 the mixin is a React component", function() {
- expect(function() {
- React.createClass({
- mixins: [],
-
- render: function() {
- return ;
- }
- });
- }).toThrow(
- 'Invariant Violation: 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", function() {
- expect(function() {
- var Component = React.createClass({
- render: function() {
- return ;
- }
- });
-
- React.createClass({
- mixins: [Component],
-
- render: function() {
- return ;
- }
- });
- }).toThrow(
- 'Invariant Violation: ReactClass: You\'re attempting to ' +
- 'use a component class as a mixin. Instead, just use a regular object.'
- );
- });
-
- it('should have bound the mixin methods to the component', function() {
- var mixin = {
- mixinFunc: function() {return this;}
- };
-
- var Component = React.createClass({
- mixins: [mixin],
- componentDidMount: function() {
- expect(this.mixinFunc()).toBe(this);
- },
- render: function() {
- return ;
- }
- });
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- });
-
- it('should include the mixin keys in even if their values are falsy',
- function() {
- 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 ;
- }
- });
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
- });
-
it('should disallow nested render calls', function() {
spyOn(console, 'warn');
var Inner = React.createClass({
diff --git a/src/core/__tests__/ReactCompositeComponentMixin-test.js b/src/core/__tests__/ReactCompositeComponentMixin-test.js
deleted file mode 100644
index f76e657b76..0000000000
--- a/src/core/__tests__/ReactCompositeComponentMixin-test.js
+++ /dev/null
@@ -1,171 +0,0 @@
-/**
- * Copyright 2013-2014, 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 mocks = require('mocks');
-
-var React;
-var ReactTestUtils;
-var reactComponentExpect;
-
-var TestComponent;
-var TestComponentWithPropTypes;
-var TestComponentWithReverseSpec;
-var mixinPropValidator;
-var componentPropValidator;
-
-describe('ReactCompositeComponent-mixin', function() {
-
- beforeEach(function() {
- React = require('React');
- ReactTestUtils = require('ReactTestUtils');
- reactComponentExpect = require('reactComponentExpect');
- mixinPropValidator = mocks.getMockFunction();
- componentPropValidator = mocks.getMockFunction();
-
- 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', function() {
- var listener = mocks.getMockFunction();
- 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', function() {
- var listener = mocks.getMockFunction();
- var instance = ;
- 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', function() {
- var listener = mocks.getMockFunction();
- var instance = ;
- instance = ReactTestUtils.renderIntoDocument(instance);
-
- expect(listener.mock.calls).toEqual([
- ['MixinA didMount'],
- ['MixinBWithReverseSpec didMount'],
- ['MixinC didMount'],
- ['Component didMount']
- ]);
- });
-
- it('should validate prop types via mixins', function() {
- expect(TestComponent.propTypes).toBeDefined();
- expect(TestComponent.propTypes.value)
- .toBe(mixinPropValidator);
- });
-
- it('should override mixin prop types with class prop types', function() {
- // Sanity check...
- expect(componentPropValidator).toNotBe(mixinPropValidator);
- // Actually check...
- expect(TestComponentWithPropTypes.propTypes)
- .toBeDefined();
- expect(TestComponentWithPropTypes.propTypes.value)
- .toNotBe(mixinPropValidator);
- expect(TestComponentWithPropTypes.propTypes.value)
- .toBe(componentPropValidator);
- });
-});
diff --git a/src/core/__tests__/ReactCompositeComponentSpec-test.js b/src/core/__tests__/ReactCompositeComponentSpec-test.js
deleted file mode 100644
index 63f5ff277e..0000000000
--- a/src/core/__tests__/ReactCompositeComponentSpec-test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * Copyright 2013-2014, 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 mocks = require('mocks');
-
-var React;
-var ReactTestUtils;
-var reactComponentExpect;
-
-describe('ReactCompositeComponent-spec', function() {
-
- beforeEach(function() {
- React = require('React');
- ReactTestUtils = require('ReactTestUtils');
- reactComponentExpect = require('reactComponentExpect');
- });
-
- it('should throw when `render` is not specified', function() {
- expect(function() {
- React.createClass({});
- }).toThrow(
- 'Invariant Violation: createClass(...): Class specification must ' +
- 'implement a `render` method.'
- );
- });
-
- it('should copy `displayName` onto the Constructor', function() {
- var TestComponent = React.createClass({
- render: function() {
- return ;
- }
- });
-
- expect(TestComponent.displayName)
- .toBe('TestComponent');
- });
-
- it('should copy prop types onto the Constructor', function() {
- var propValidator = mocks.getMockFunction();
- var TestComponent = React.createClass({
- propTypes: {
- value: propValidator
- },
- render: function() {
- return ;
- }
- });
-
- expect(TestComponent.propTypes).toBeDefined();
- expect(TestComponent.propTypes.value)
- .toBe(propValidator);
- });
-});