@samitouri / QOS-React-2 / commits / 801e953334

Move ReactClass, ReactElement and ReactPropTypes into "traditional"

This moves ReactClass, ReactElement and ReactPropTypes into a legacy folder but since it's not quite legacy yet, I call it "classic". These are "classic" because they are decoupled and can be replaced by ES6 classes, JSX and Flow respectively. This also extracts unit tests from ReactCompositeComponent, which was terribly overloaded, into the new corresponding test suites. There is one weird case for ReactContextValidator. This actually happens in core, and technically belongs to ReactCompositeComponent. I'm not sure we will be able to statically validate contexts so this might be a case for dynamic checks even in the future. Leaving the unit tests in classic until we can figure out what to do with them.

Sebastian Markbage committed Dec 12, 2014 at 17:54 UTC 801e95333444e1267331e6e765ca228161ce6e65
17 files changed +1218 -1124
src/classic/__tests__/ReactContextValidator-test.js new
+247
@@ -0,0 +1,247 @@
1 +/**
2 + * Copyright 2013-2014, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @emails react-core
10 + */
11 +
12 +// This test doesn't really have a good home yet. I'm leaving it here since this
13 +// behavior belongs to the old propTypes system yet is currently implemented
14 +// in the core ReactCompositeComponent. It should technically live in core's
15 +// test suite but I'll leave it here to indicate that this is an issue that
16 +// needs to be fixed.
17 +
18 +"use strict";
19 +
20 +var React;
21 +var ReactTestUtils;
22 +
23 +var reactComponentExpect;
24 +var mocks;
25 +
26 +describe('ReactContextValidator', function() {
27 + beforeEach(function() {
28 + require('mock-modules').dumpCache();
29 +
30 + React = require('React');
31 + ReactTestUtils = require('ReactTestUtils');
32 + reactComponentExpect = require('reactComponentExpect');
33 + mocks = require('mocks');
34 +
35 + console.warn = mocks.getMockFunction();
36 + });
37 +
38 + // TODO: This behavior creates a runtime dependency on propTypes. We should
39 + // ensure that this is not required for ES6 classes with Flow.
40 +
41 + it('should filter out context not in contextTypes', function() {
42 + var Component = React.createClass({
43 + contextTypes: {
44 + foo: React.PropTypes.string
45 + },
46 +
47 + render: function() {
48 + return <div />;
49 + }
50 + });
51 +
52 + var ComponentInFooBarContext = React.createClass({
53 + childContextTypes: {
54 + foo: React.PropTypes.string,
55 + bar: React.PropTypes.number
56 + },
57 +
58 + getChildContext: function() {
59 + return {
60 + foo: 'abc',
61 + bar: 123
62 + };
63 + },
64 +
65 + render: function() {
66 + return <Component />;
67 + }
68 + });
69 +
70 + var instance = ReactTestUtils.renderIntoDocument(<ComponentInFooBarContext />);
71 + reactComponentExpect(instance).expectRenderedChild().scalarContextEqual({foo: 'abc'});
72 + });
73 +
74 + it('should filter context properly in callbacks', function() {
75 + var actualComponentWillReceiveProps;
76 + var actualShouldComponentUpdate;
77 + var actualComponentWillUpdate;
78 + var actualComponentDidUpdate;
79 +
80 + var Parent = React.createClass({
81 + childContextTypes: {
82 + foo: React.PropTypes.string.isRequired,
83 + bar: React.PropTypes.string.isRequired
84 + },
85 +
86 + getChildContext: function() {
87 + return {
88 + foo: this.props.foo,
89 + bar: "bar"
90 + };
91 + },
92 +
93 + render: function() {
94 + return <Component />;
95 + }
96 + });
97 +
98 + var Component = React.createClass({
99 + contextTypes: {
100 + foo: React.PropTypes.string
101 + },
102 +
103 + componentWillReceiveProps: function(nextProps, nextContext) {
104 + actualComponentWillReceiveProps = nextContext;
105 + return true;
106 + },
107 +
108 + shouldComponentUpdate: function(nextProps, nextState, nextContext) {
109 + actualShouldComponentUpdate = nextContext;
110 + return true;
111 + },
112 +
113 + componentWillUpdate: function(nextProps, nextState, nextContext) {
114 + actualComponentWillUpdate = nextContext;
115 + },
116 +
117 + componentDidUpdate: function(prevProps, prevState, prevContext) {
118 + actualComponentDidUpdate = prevContext;
119 + },
120 +
121 + render: function() {
122 + return <div />;
123 + }
124 + });
125 +
126 + var instance = <Parent foo="abc" />;
127 + instance = ReactTestUtils.renderIntoDocument(instance);
128 + instance.replaceProps({foo: "def"});
129 + expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
130 + expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
131 + expect(actualComponentWillUpdate).toEqual({foo: 'def'});
132 + expect(actualComponentDidUpdate).toEqual({foo: 'abc'});
133 + });
134 +
135 + it('should check context types', function() {
136 + var Component = React.createClass({
137 + contextTypes: {
138 + foo: React.PropTypes.string.isRequired
139 + },
140 +
141 + render: function() {
142 + return <div />;
143 + }
144 + });
145 +
146 + ReactTestUtils.renderIntoDocument(<Component />);
147 +
148 + expect(console.warn.mock.calls.length).toBe(1);
149 + expect(console.warn.mock.calls[0][0]).toBe(
150 + 'Warning: Required context `foo` was not specified in `Component`.'
151 + );
152 +
153 + var ComponentInFooStringContext = React.createClass({
154 + childContextTypes: {
155 + foo: React.PropTypes.string
156 + },
157 +
158 + getChildContext: function() {
159 + return {
160 + foo: this.props.fooValue
161 + };
162 + },
163 +
164 + render: function() {
165 + return <Component />;
166 + }
167 + });
168 +
169 + ReactTestUtils.renderIntoDocument(
170 + <ComponentInFooStringContext fooValue={'bar'} />
171 + );
172 +
173 + // Previous call should not error
174 + expect(console.warn.mock.calls.length).toBe(1);
175 +
176 + var ComponentInFooNumberContext = React.createClass({
177 + childContextTypes: {
178 + foo: React.PropTypes.number
179 + },
180 +
181 + getChildContext: function() {
182 + return {
183 + foo: this.props.fooValue
184 + };
185 + },
186 +
187 + render: function() {
188 + return <Component />;
189 + }
190 + });
191 +
192 + ReactTestUtils.renderIntoDocument(<ComponentInFooNumberContext fooValue={123} />);
193 +
194 + expect(console.warn.mock.calls.length).toBe(2);
195 + expect(console.warn.mock.calls[1][0]).toBe(
196 + 'Warning: Invalid context `foo` of type `number` supplied ' +
197 + 'to `Component`, expected `string`.' +
198 + ' Check the render method of `ComponentInFooNumberContext`.'
199 + );
200 + });
201 +
202 + it('should check child context types', function() {
203 + var Component = React.createClass({
204 + childContextTypes: {
205 + foo: React.PropTypes.string.isRequired,
206 + bar: React.PropTypes.number
207 + },
208 +
209 + getChildContext: function() {
210 + return this.props.testContext;
211 + },
212 +
213 + render: function() {
214 + return <div />;
215 + }
216 + });
217 +
218 + ReactTestUtils.renderIntoDocument(<Component testContext={{bar: 123}} />);
219 + expect(console.warn.mock.calls.length).toBe(2);
220 + expect(console.warn.mock.calls[0][0]).toBe(
221 + 'Warning: Required child context `foo` was not specified in `Component`.'
222 + );
223 + expect(console.warn.mock.calls[1][0]).toBe(
224 + 'Warning: Required child context `foo` was not specified in `Component`.'
225 + );
226 +
227 + ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 123}} />);
228 +
229 + expect(console.warn.mock.calls.length).toBe(4);
230 + expect(console.warn.mock.calls[3][0]).toBe(
231 + 'Warning: Invalid child context `foo` of type `number` ' +
232 + 'supplied to `Component`, expected `string`.'
233 + );
234 +
235 + ReactTestUtils.renderIntoDocument(
236 + <Component testContext={{foo: 'foo', bar: 123}} />
237 + );
238 +
239 + ReactTestUtils.renderIntoDocument(
240 + <Component testContext={{foo: 'foo'}} />
241 + );
242 +
243 + // Previous calls should not log errors
244 + expect(console.warn.mock.calls.length).toBe(4);
245 + });
246 +
247 +});
src/classic/class/ReactClass.js renamed
src/classic/class/ReactDoNotBindDeprecated.js renamed
src/classic/class/__tests__/ReactBind-test.js renamed
src/classic/class/__tests__/ReactClass-test.js new
+338
@@ -0,0 +1,338 @@
1 +/**
2 + * Copyright 2013-2014, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @emails react-core
10 + */
11 +
12 +"use strict";
13 +
14 +var mocks = require('mocks');
15 +
16 +var React;
17 +var ReactTestUtils;
18 +var reactComponentExpect;
19 +
20 +describe('ReactClass-spec', function() {
21 +
22 + beforeEach(function() {
23 + React = require('React');
24 + ReactTestUtils = require('ReactTestUtils');
25 + reactComponentExpect = require('reactComponentExpect');
26 + });
27 +
28 + it('should throw when `render` is not specified', function() {
29 + expect(function() {
30 + React.createClass({});
31 + }).toThrow(
32 + 'Invariant Violation: createClass(...): Class specification must ' +
33 + 'implement a `render` method.'
34 + );
35 + });
36 +
37 + it('should copy `displayName` onto the Constructor', function() {
38 + var TestComponent = React.createClass({
39 + render: function() {
40 + return <div />;
41 + }
42 + });
43 +
44 + expect(TestComponent.displayName)
45 + .toBe('TestComponent');
46 + });
47 +
48 + it('should copy prop types onto the Constructor', function() {
49 + var propValidator = mocks.getMockFunction();
50 + var TestComponent = React.createClass({
51 + propTypes: {
52 + value: propValidator
53 + },
54 + render: function() {
55 + return <div />;
56 + }
57 + });
58 +
59 + expect(TestComponent.propTypes).toBeDefined();
60 + expect(TestComponent.propTypes.value)
61 + .toBe(propValidator);
62 + });
63 +
64 + it('should throw on invalid prop types', function() {
65 + expect(function() {
66 + React.createClass({
67 + displayName: 'Component',
68 + propTypes: {
69 + prop: null
70 + },
71 + render: function() {
72 + return <span>{this.props.prop}</span>;
73 + }
74 + });
75 + }).toThrow(
76 + 'Invariant Violation: Component: prop type `prop` is invalid; ' +
77 + 'it must be a function, usually from React.PropTypes.'
78 + );
79 + });
80 +
81 + it('should throw on invalid context types', function() {
82 + expect(function() {
83 + React.createClass({
84 + displayName: 'Component',
85 + contextTypes: {
86 + prop: null
87 + },
88 + render: function() {
89 + return <span>{this.props.prop}</span>;
90 + }
91 + });
92 + }).toThrow(
93 + 'Invariant Violation: Component: context type `prop` is invalid; ' +
94 + 'it must be a function, usually from React.PropTypes.'
95 + );
96 + });
97 +
98 + it('should throw on invalid child context types', function() {
99 + expect(function() {
100 + React.createClass({
101 + displayName: 'Component',
102 + childContextTypes: {
103 + prop: null
104 + },
105 + render: function() {
106 + return <span>{this.props.prop}</span>;
107 + }
108 + });
109 + }).toThrow(
110 + 'Invariant Violation: Component: child context type `prop` is invalid; ' +
111 + 'it must be a function, usually from React.PropTypes.'
112 + );
113 + });
114 +
115 + it('should warn when mispelling shouldComponentUpdate', function() {
116 + var warn = console.warn;
117 + console.warn = mocks.getMockFunction();
118 +
119 + try {
120 + React.createClass({
121 + componentShouldUpdate: function() {
122 + return false;
123 + },
124 + render: function() {
125 + return <div />;
126 + }
127 + });
128 + expect(console.warn.mock.calls.length).toBe(1);
129 + expect(console.warn.mock.calls[0][0]).toBe(
130 + 'A component has a method called componentShouldUpdate(). Did you ' +
131 + 'mean shouldComponentUpdate()? The name is phrased as a question ' +
132 + 'because the function is expected to return a value.'
133 + );
134 +
135 + var NamedComponent = React.createClass({
136 + componentShouldUpdate: function() {
137 + return false;
138 + },
139 + render: function() {
140 + return <div />;
141 + }
142 + });
143 + expect(console.warn.mock.calls.length).toBe(2);
144 + expect(console.warn.mock.calls[1][0]).toBe(
145 + 'NamedComponent has a method called componentShouldUpdate(). Did you ' +
146 + 'mean shouldComponentUpdate()? The name is phrased as a question ' +
147 + 'because the function is expected to return a value.'
148 + );
149 +
150 + <NamedComponent />; // Shut up lint
151 + } finally {
152 + console.warn = warn;
153 + }
154 + });
155 +
156 + it('should throw if a reserved property is in statics', function() {
157 + expect(function() {
158 + React.createClass({
159 + statics: {
160 + getDefaultProps: function() {
161 + return {
162 + foo: 0
163 + };
164 + }
165 + },
166 +
167 + render: function() {
168 + return <span />;
169 + }
170 + });
171 + }).toThrow(
172 + 'Invariant Violation: ReactClass: You are attempting to ' +
173 + 'define a reserved property, `getDefaultProps`, that shouldn\'t be on ' +
174 + 'the "statics" key. Define it as an instance property instead; it ' +
175 + 'will still be accessible on the constructor.'
176 + );
177 + });
178 +
179 + // TODO: Consider actually moving these to statics or drop this unit test.
180 +
181 + xit('should warn when using deprecated non-static spec keys', function() {
182 + var warn = console.warn;
183 + console.warn = mocks.getMockFunction();
184 + try {
185 + React.createClass({
186 + mixins: [{}],
187 + propTypes: {
188 + foo: ReactPropTypes.string
189 + },
190 + contextTypes: {
191 + foo: ReactPropTypes.string
192 + },
193 + childContextTypes: {
194 + foo: ReactPropTypes.string
195 + },
196 + render: function() {
197 + return <div />;
198 + }
199 + });
200 + expect(console.warn.mock.calls.length).toBe(4);
201 + expect(console.warn.mock.calls[0][0]).toBe(
202 + 'createClass(...): `mixins` is now a static property and should ' +
203 + 'be defined inside "statics".'
204 + );
205 + expect(console.warn.mock.calls[1][0]).toBe(
206 + 'createClass(...): `propTypes` is now a static property and should ' +
207 + 'be defined inside "statics".'
208 + );
209 + expect(console.warn.mock.calls[2][0]).toBe(
210 + 'createClass(...): `contextTypes` is now a static property and ' +
211 + 'should be defined inside "statics".'
212 + );
213 + expect(console.warn.mock.calls[3][0]).toBe(
214 + 'createClass(...): `childContextTypes` is now a static property and ' +
215 + 'should be defined inside "statics".'
216 + );
217 + } finally {
218 + console.warn = warn;
219 + }
220 + });
221 +
222 + it('should support statics', function() {
223 + var Component = React.createClass({
224 + statics: {
225 + abc: 'def',
226 + def: 0,
227 + ghi: null,
228 + jkl: 'mno',
229 + pqr: function() {
230 + return this;
231 + }
232 + },
233 +
234 + render: function() {
235 + return <span />;
236 + }
237 + });
238 + var instance = <Component />;
239 + instance = ReactTestUtils.renderIntoDocument(instance);
240 + expect(instance.constructor.abc).toBe('def');
241 + expect(Component.abc).toBe('def');
242 + expect(instance.constructor.def).toBe(0);
243 + expect(Component.def).toBe(0);
244 + expect(instance.constructor.ghi).toBe(null);
245 + expect(Component.ghi).toBe(null);
246 + expect(instance.constructor.jkl).toBe('mno');
247 + expect(Component.jkl).toBe('mno');
248 + expect(instance.constructor.pqr()).toBe(Component);
249 + expect(Component.pqr()).toBe(Component);
250 + });
251 +
252 + it('should work with object getInitialState() return values', function() {
253 + var Component = React.createClass({
254 + getInitialState: function() {
255 + return {
256 + occupation: 'clown'
257 + };
258 + },
259 + render: function() {
260 + return <span />;
261 + }
262 + });
263 + var instance = <Component />;
264 + instance = ReactTestUtils.renderIntoDocument(instance);
265 + expect(instance.state.occupation).toEqual('clown');
266 + });
267 +
268 + it('should throw with non-object getInitialState() return values', function() {
269 + [['an array'], 'a string', 1234].forEach(function(state) {
270 + var Component = React.createClass({
271 + getInitialState: function() {
272 + return state;
273 + },
274 + render: function() {
275 + return <span />;
276 + }
277 + });
278 + var instance = <Component />;
279 + expect(function() {
280 + instance = ReactTestUtils.renderIntoDocument(instance);
281 + }).toThrow(
282 + 'Invariant Violation: Component.getInitialState(): ' +
283 + 'must return an object or null'
284 + );
285 + });
286 + });
287 +
288 + it('should work with a null getInitialState() return value', function() {
289 + var Component = React.createClass({
290 + getInitialState: function() {
291 + return null;
292 + },
293 + render: function() {
294 + return <span />;
295 + }
296 + });
297 + expect(
298 + () => ReactTestUtils.renderIntoDocument(<Component />)
299 + ).not.toThrow();
300 + });
301 +
302 + it('should work with object getInitialState() return values', function() {
303 + var Component = React.createClass({
304 + getInitialState: function() {
305 + return {
306 + occupation: 'clown'
307 + };
308 + },
309 + render: function() {
310 + return <span />;
311 + }
312 + });
313 + var instance = <Component />;
314 + instance = ReactTestUtils.renderIntoDocument(instance);
315 + expect(instance.state.occupation).toEqual('clown');
316 + });
317 +
318 + it('should throw with non-object getInitialState() return values', function() {
319 + [['an array'], 'a string', 1234].forEach(function(state) {
320 + var Component = React.createClass({
321 + getInitialState: function() {
322 + return state;
323 + },
324 + render: function() {
325 + return <span />;
326 + }
327 + });
328 + var instance = <Component />;
329 + expect(function() {
330 + instance = ReactTestUtils.renderIntoDocument(instance);
331 + }).toThrow(
332 + 'Invariant Violation: Component.getInitialState(): ' +
333 + 'must return an object or null'
334 + );
335 + });
336 + });
337 +
338 +});
src/classic/class/__tests__/ReactClassMixin-test.js new
+459
@@ -0,0 +1,459 @@
1 +/**
2 + * Copyright 2013-2014, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @emails react-core
10 + */
11 +
12 +"use strict";
13 +
14 +var mocks = require('mocks');
15 +
16 +var React;
17 +var ReactTestUtils;
18 +var reactComponentExpect;
19 +
20 +var TestComponent;
21 +var TestComponentWithPropTypes;
22 +var TestComponentWithReverseSpec;
23 +var mixinPropValidator;
24 +var componentPropValidator;
25 +
26 +describe('ReactClass-mixin', function() {
27 +
28 + beforeEach(function() {
29 + React = require('React');
30 + ReactTestUtils = require('ReactTestUtils');
31 + reactComponentExpect = require('reactComponentExpect');
32 + mixinPropValidator = mocks.getMockFunction();
33 + componentPropValidator = mocks.getMockFunction();
34 +
35 + var MixinA = {
36 + propTypes: {
37 + propA: function() {}
38 + },
39 + componentDidMount: function() {
40 + this.props.listener('MixinA didMount');
41 + }
42 + };
43 +
44 + var MixinB = {
45 + mixins: [MixinA],
46 + propTypes: {
47 + propB: function() {}
48 + },
49 + componentDidMount: function() {
50 + this.props.listener('MixinB didMount');
51 + }
52 + };
53 +
54 + var MixinBWithReverseSpec = {
55 + componentDidMount: function() {
56 + this.props.listener('MixinBWithReverseSpec didMount');
57 + },
58 + mixins: [MixinA]
59 + };
60 +
61 + var MixinC = {
62 + statics: {
63 + staticC: function() {}
64 + },
65 + componentDidMount: function() {
66 + this.props.listener('MixinC didMount');
67 + }
68 + };
69 +
70 + var MixinD = {
71 + propTypes: {
72 + value: mixinPropValidator
73 + }
74 + };
75 +
76 + TestComponent = React.createClass({
77 + mixins: [MixinB, MixinC, MixinD],
78 + statics: {
79 + staticComponent: function() {}
80 + },
81 + propTypes: {
82 + propComponent: function() {}
83 + },
84 + componentDidMount: function() {
85 + this.props.listener('Component didMount');
86 + },
87 + render: function() {
88 + return <div />;
89 + }
90 + });
91 +
92 + TestComponentWithReverseSpec = React.createClass({
93 + render: function() {
94 + return <div />;
95 + },
96 + componentDidMount: function() {
97 + this.props.listener('Component didMount');
98 + },
99 + mixins: [MixinBWithReverseSpec, MixinC, MixinD]
100 + });
101 +
102 + TestComponentWithPropTypes = React.createClass({
103 + mixins: [MixinD],
104 + propTypes: {
105 + value: componentPropValidator
106 + },
107 + render: function() {
108 + return <div />;
109 + }
110 + });
111 + });
112 +
113 + it('should support merging propTypes and statics', function() {
114 + var listener = mocks.getMockFunction();
115 + var instance = <TestComponent listener={listener} />;
116 + instance = ReactTestUtils.renderIntoDocument(instance);
117 +
118 + var instancePropTypes = instance.constructor.propTypes;
119 +
120 + expect('propA' in instancePropTypes).toBe(true);
121 + expect('propB' in instancePropTypes).toBe(true);
122 + expect('propComponent' in instancePropTypes).toBe(true);
123 +
124 + expect('staticC' in TestComponent).toBe(true);
125 + expect('staticComponent' in TestComponent).toBe(true);
126 + });
127 +
128 + it('should support chaining delegate functions', function() {
129 + var listener = mocks.getMockFunction();
130 + var instance = <TestComponent listener={listener} />;
131 + instance = ReactTestUtils.renderIntoDocument(instance);
132 +
133 + expect(listener.mock.calls).toEqual([
134 + ['MixinA didMount'],
135 + ['MixinB didMount'],
136 + ['MixinC didMount'],
137 + ['Component didMount']
138 + ]);
139 + });
140 +
141 + it('should chain functions regardless of spec property order', function() {
142 + var listener = mocks.getMockFunction();
143 + var instance = <TestComponentWithReverseSpec listener={listener} />;
144 + instance = ReactTestUtils.renderIntoDocument(instance);
145 +
146 + expect(listener.mock.calls).toEqual([
147 + ['MixinA didMount'],
148 + ['MixinBWithReverseSpec didMount'],
149 + ['MixinC didMount'],
150 + ['Component didMount']
151 + ]);
152 + });
153 +
154 + it('should validate prop types via mixins', function() {
155 + expect(TestComponent.propTypes).toBeDefined();
156 + expect(TestComponent.propTypes.value)
157 + .toBe(mixinPropValidator);
158 + });
159 +
160 + it('should override mixin prop types with class prop types', function() {
161 + // Sanity check...
162 + expect(componentPropValidator).toNotBe(mixinPropValidator);
163 + // Actually check...
164 + expect(TestComponentWithPropTypes.propTypes)
165 + .toBeDefined();
166 + expect(TestComponentWithPropTypes.propTypes.value)
167 + .toNotBe(mixinPropValidator);
168 + expect(TestComponentWithPropTypes.propTypes.value)
169 + .toBe(componentPropValidator);
170 + });
171 +
172 +
173 + it('should support mixins with getInitialState()', function() {
174 + var Mixin = {
175 + getInitialState: function() {
176 + return {mixin: true};
177 + }
178 + };
179 + var Component = React.createClass({
180 + mixins: [Mixin],
181 + getInitialState: function() {
182 + return {component: true};
183 + },
184 + render: function() {
185 + return <span />;
186 + }
187 + });
188 + var instance = <Component />;
189 + instance = ReactTestUtils.renderIntoDocument(instance);
190 + expect(instance.state.component).toBe(true);
191 + expect(instance.state.mixin).toBe(true);
192 + });
193 +
194 + it('should throw with conflicting getInitialState() methods', function() {
195 + var Mixin = {
196 + getInitialState: function() {
197 + return {x: true};
198 + }
199 + };
200 + var Component = React.createClass({
201 + mixins: [Mixin],
202 + getInitialState: function() {
203 + return {x: true};
204 + },
205 + render: function() {
206 + return <span />;
207 + }
208 + });
209 + var instance = <Component />;
210 + expect(function() {
211 + instance = ReactTestUtils.renderIntoDocument(instance);
212 + }).toThrow(
213 + 'Invariant Violation: mergeIntoWithNoDuplicateKeys(): ' +
214 + 'Tried to merge two objects with the same key: `x`. This conflict ' +
215 + 'may be due to a mixin; in particular, this may be caused by two ' +
216 + 'getInitialState() or getDefaultProps() methods returning objects ' +
217 + 'with clashing keys.'
218 + );
219 + });
220 +
221 + it('should not mutate objects returned by getInitialState()', function() {
222 + var Mixin = {
223 + getInitialState: function() {
224 + return Object.freeze({mixin: true});
225 + }
226 + };
227 + var Component = React.createClass({
228 + mixins: [Mixin],
229 + getInitialState: function() {
230 + return Object.freeze({component: true});
231 + },
232 + render: function() {
233 + return <span />;
234 + }
235 + });
236 + expect(() => {
237 + ReactTestUtils.renderIntoDocument(<Component />);
238 + }).not.toThrow();
239 + });
240 +
241 + it('should support statics in mixins', function() {
242 + var Mixin = {
243 + statics: {
244 + foo: 'bar'
245 + }
246 + };
247 + var Component = React.createClass({
248 + mixins: [Mixin],
249 +
250 + statics: {
251 + abc: 'def'
252 + },
253 +
254 + render: function() {
255 + return <span />;
256 + }
257 + });
258 + var instance = <Component />;
259 + instance = ReactTestUtils.renderIntoDocument(instance);
260 + expect(instance.constructor.foo).toBe('bar');
261 + expect(Component.foo).toBe('bar');
262 + expect(instance.constructor.abc).toBe('def');
263 + expect(Component.abc).toBe('def');
264 + });
265 +
266 + it("should throw if mixins override each others' statics", function() {
267 + expect(function() {
268 + var Mixin = {
269 + statics: {
270 + abc: 'foo'
271 + }
272 + };
273 + React.createClass({
274 + mixins: [Mixin],
275 +
276 + statics: {
277 + abc: 'bar'
278 + },
279 +
280 + render: function() {
281 + return <span />;
282 + }
283 + });
284 + }).toThrow(
285 + 'Invariant Violation: ReactClass: You are attempting to ' +
286 + 'define `abc` on your component more than once. This conflict may be ' +
287 + 'due to a mixin.'
288 + );
289 + });
290 +
291 + it("should throw if mixins override functions in statics", function() {
292 + expect(function() {
293 + var Mixin = {
294 + statics: {
295 + abc: function() { console.log('foo'); }
296 + }
297 + };
298 + React.createClass({
299 + mixins: [Mixin],
300 +
301 + statics: {
302 + abc: function() { console.log('bar'); }
303 + },
304 +
305 + render: function() {
306 + return <span />;
307 + }
308 + });
309 + }).toThrow(
310 + 'Invariant Violation: ReactClass: You are attempting to ' +
311 + 'define `abc` on your component more than once. This conflict may be ' +
312 + 'due to a mixin.'
313 + );
314 + });
315 +
316 + it("should throw if the mixin is a React component", function() {
317 + expect(function() {
318 + React.createClass({
319 + mixins: [<div />],
320 +
321 + render: function() {
322 + return <span />;
323 + }
324 + });
325 + }).toThrow(
326 + 'Invariant Violation: ReactClass: You\'re attempting to ' +
327 + 'use a component as a mixin. Instead, just use a regular object.'
328 + );
329 + });
330 +
331 + it("should throw if the mixin is a React component class", function() {
332 + expect(function() {
333 + var Component = React.createClass({
334 + render: function() {
335 + return <span />;
336 + }
337 + });
338 +
339 + React.createClass({
340 + mixins: [Component],
341 +
342 + render: function() {
343 + return <span />;
344 + }
345 + });
346 + }).toThrow(
347 + 'Invariant Violation: ReactClass: You\'re attempting to ' +
348 + 'use a component class as a mixin. Instead, just use a regular object.'
349 + );
350 + });
351 +
352 + it('should have bound the mixin methods to the component', function() {
353 + var mixin = {
354 + mixinFunc: function() {return this;}
355 + };
356 +
357 + var Component = React.createClass({
358 + mixins: [mixin],
359 + componentDidMount: function() {
360 + expect(this.mixinFunc()).toBe(this);
361 + },
362 + render: function() {
363 + return <span />;
364 + }
365 + });
366 + var instance = <Component />;
367 + instance = ReactTestUtils.renderIntoDocument(instance);
368 + });
369 +
370 + it('should include the mixin keys in even if their values are falsy',
371 + function() {
372 + var mixin = {
373 + keyWithNullValue: null,
374 + randomCounter: 0
375 + };
376 +
377 + var Component = React.createClass({
378 + mixins: [mixin],
379 + componentDidMount: function() {
380 + expect(this.randomCounter).toBe(0);
381 + expect(this.keyWithNullValue).toBeNull();
382 + },
383 + render: function() {
384 + return <span />;
385 + }
386 + });
387 + var instance = <Component />;
388 + instance = ReactTestUtils.renderIntoDocument(instance);
389 + });
390 +
391 + it('should work with a null getInitialState return value and a mixin', () => {
392 + var Component;
393 + var instance;
394 +
395 + var Mixin = {
396 + getInitialState: function() {
397 + return {foo: 'bar'};
398 + }
399 + };
400 + Component = React.createClass({
401 + mixins: [Mixin],
402 + getInitialState: function() {
403 + return null;
404 + },
405 + render: function() {
406 + return <span />;
407 + }
408 + });
409 + expect(
410 + () => ReactTestUtils.renderIntoDocument(<Component />)
411 + ).not.toThrow();
412 +
413 + instance = <Component />;
414 + instance = ReactTestUtils.renderIntoDocument(instance);
415 + expect(instance.state).toEqual({foo: 'bar'});
416 +
417 + // Also the other way round should work
418 + var Mixin2 = {
419 + getInitialState: function() {
420 + return null;
421 + }
422 + };
423 + Component = React.createClass({
424 + mixins: [Mixin2],
425 + getInitialState: function() {
426 + return {foo: 'bar'};
427 + },
428 + render: function() {
429 + return <span />;
430 + }
431 + });
432 + expect(
433 + () => ReactTestUtils.renderIntoDocument(<Component />)
434 + ).not.toThrow();
435 +
436 + instance = <Component />;
437 + instance = ReactTestUtils.renderIntoDocument(instance);
438 + expect(instance.state).toEqual({foo: 'bar'});
439 +
440 + // Multiple mixins should be fine too
441 + Component = React.createClass({
442 + mixins: [Mixin, Mixin2],
443 + getInitialState: function() {
444 + return {x: true};
445 + },
446 + render: function() {
447 + return <span />;
448 + }
449 + });
450 + expect(
451 + () => ReactTestUtils.renderIntoDocument(<Component />)
452 + ).not.toThrow();
453 +
454 + instance = <Component />;
455 + instance = ReactTestUtils.renderIntoDocument(instance);
456 + expect(instance.state).toEqual({foo: 'bar', x: true});
457 + });
458 +
459 +});
src/classic/element/ReactElement.js renamed
src/classic/element/ReactElementValidator.js renamed
src/classic/element/__tests__/ReactElement-test.js renamed
+56
@@ -11,6 +11,8 @@
11
12 "use strict";
13
14 +var mocks;
15 +
16 var React;
17 var ReactElement;
18 var ReactTestUtils;
@@ -21,6 +23,8 @@ describe('ReactElement', function() {
23 beforeEach(function() {
24 require('mock-modules').dumpCache();
25
26 + mocks = require('mocks');
27 +
28 React = require('React');
29 ReactElement = require('ReactElement');
30 ReactTestUtils = require('ReactTestUtils');
@@ -370,4 +374,56 @@ describe('ReactElement', function() {
374 expect(element.constructor).toBe(object.constructor);
375 });
376
377 + it('should use default prop value when removing a prop', function() {
378 + var Component = React.createClass({
379 + getDefaultProps: function() {
380 + return {fruit: 'persimmon'};
381 + },
382 + render: function() {
383 + return <span />;
384 + }
385 + });
386 +
387 + var container = document.createElement('div');
388 + var instance = React.render(
389 + <Component fruit="mango" />,
390 + container
391 + );
392 + expect(instance.props.fruit).toBe('mango');
393 +
394 + React.render(<Component />, container);
395 + expect(instance.props.fruit).toBe('persimmon');
396 + });
397 +
398 + it('should normalize props with default values', function() {
399 + var warn = console.warn;
400 + console.warn = mocks.getMockFunction();
401 +
402 + var Component = React.createClass({
403 + propTypes: {prop: React.PropTypes.string.isRequired},
404 + getDefaultProps: function() {
405 + return {prop: 'testKey'};
406 + },
407 + getInitialState: function() {
408 + return {prop: this.props.prop + 'State'};
409 + },
410 + render: function() {
411 + return <span>{this.props.prop}</span>;
412 + }
413 + });
414 +
415 + var instance = ReactTestUtils.renderIntoDocument(<Component />);
416 + expect(instance.props.prop).toBe('testKey');
417 + expect(instance.state.prop).toBe('testKeyState');
418 +
419 + ReactTestUtils.renderIntoDocument(<Component prop={null} />);
420 +
421 + expect(console.warn.mock.calls.length).toBe(1);
422 + expect(console.warn.mock.calls[0][0]).toBe(
423 + 'Warning: Required prop `prop` was not specified in `Component`.'
424 + );
425 +
426 + console.warn = warn;
427 + });
428 +
429 });
src/classic/element/__tests__/ReactElementValidator-test.js new
+110
@@ -0,0 +1,110 @@
1 +/**
2 + * Copyright 2013-2014, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @emails react-core
10 + */
11 +
12 +"use strict";
13 +
14 +var React;
15 +var ReactTestUtils;
16 +
17 +describe('ReactElementValidator', function() {
18 + var ComponentClass;
19 +
20 + beforeEach(function() {
21 + require('mock-modules').dumpCache();
22 +
23 + React = require('React');
24 + ReactTestUtils = require('ReactTestUtils');
25 + ComponentClass = React.createClass({
26 + render: function() { return <div />; }
27 + });
28 + });
29 +
30 + // TODO: These warnings currently come from the composite component, but
31 + // they should be moved into the ReactElementValidator.
32 +
33 + it('should give context for PropType errors in nested components.', () => {
34 + // In this test, we're making sure that if a proptype error is found in a
35 + // component, we give a small hint as to which parent instantiated that
36 + // component as per warnings about key usage in ReactElementValidator.
37 + spyOn(console, 'warn');
38 + var MyComp = React.createClass({
39 + propTypes: {
40 + color: React.PropTypes.string
41 + },
42 + render: function() {
43 + return <div>My color is {this.color}</div>;
44 + }
45 + });
46 + var ParentComp = React.createClass({
47 + render: function() {
48 + return <MyComp color={123} />;
49 + }
50 + });
51 + ReactTestUtils.renderIntoDocument(<ParentComp />);
52 + expect(console.warn.calls[0].args[0]).toBe(
53 + 'Warning: Invalid prop `color` of type `number` supplied to `MyComp`, ' +
54 + 'expected `string`. Check the render method of `ParentComp`.'
55 + );
56 + });
57 +
58 + it('should check default prop values', function() {
59 + spyOn(console, 'warn');
60 +
61 + var Component = React.createClass({
62 + propTypes: {prop: React.PropTypes.string.isRequired},
63 + getDefaultProps: function() {
64 + return {prop: null};
65 + },
66 + render: function() {
67 + return <span>{this.props.prop}</span>;
68 + }
69 + });
70 +
71 + ReactTestUtils.renderIntoDocument(<Component />);
72 +
73 + expect(console.warn.calls.length).toBe(1);
74 + expect(console.warn.calls[0].args[0]).toBe(
75 + 'Warning: Required prop `prop` was not specified in `Component`.'
76 + );
77 + });
78 +
79 + it('should check declared prop types', function() {
80 + spyOn(console, 'warn');
81 +
82 + var Component = React.createClass({
83 + propTypes: {
84 + prop: React.PropTypes.string.isRequired
85 + },
86 + render: function() {
87 + return <span>{this.props.prop}</span>;
88 + }
89 + });
90 +
91 + ReactTestUtils.renderIntoDocument(<Component />);
92 + ReactTestUtils.renderIntoDocument(<Component prop={42} />);
93 +
94 + expect(console.warn.calls.length).toBe(2);
95 + expect(console.warn.calls[0].args[0]).toBe(
96 + 'Warning: Required prop `prop` was not specified in `Component`.'
97 + );
98 +
99 + expect(console.warn.calls[1].args[0]).toBe(
100 + 'Warning: Invalid prop `prop` of type `number` supplied to ' +
101 + '`Component`, expected `string`.'
102 + );
103 +
104 + ReactTestUtils.renderIntoDocument(<Component prop="string" />);
105 +
106 + // Should not error for strings
107 + expect(console.warn.calls.length).toBe(2);
108 + });
109 +
110 +});
src/classic/propTypes/ReactPropTypeLocationNames.js renamed
src/classic/propTypes/ReactPropTypeLocations.js renamed
src/classic/propTypes/ReactPropTypes.js renamed
src/classic/propTypes/__tests__/ReactPropTypes-test.js renamed
src/core/__tests__/ReactCompositeComponent-test.js
+8 -890
@@ -85,31 +85,6 @@ describe('ReactCompositeComponent', function() {
85 console.warn = warn;
86 });
87
88 - it('should give context for PropType errors in nested components.', () => {
89 - // In this test, we're making sure that if a proptype error is found in a
90 - // component, we give a small hint as to which parent instantiated that
91 - // component as per warnings about key usage in ReactElementValidator.
92 - spyOn(console, 'warn');
93 - var MyComp = React.createClass({
94 - propTypes: {
95 - color: ReactPropTypes.string
96 - },
97 - render: function() {
98 - return <div>My color is {this.color}</div>;
99 - }
100 - });
101 - var ParentComp = React.createClass({
102 - render: function() {
103 - return <MyComp color={123} />;
104 - }
105 - });
106 - ReactTestUtils.renderIntoDocument(<ParentComp />);
107 - expect(console.warn.calls[0].args[0]).toBe(
108 - 'Warning: Invalid prop `color` of type `number` supplied to `MyComp`, ' +
109 - 'expected `string`. Check the render method of `ParentComp`.'
110 - );
111 - });
112 -
88 it('should support rendering to different child types over time', function() {
89 var instance = <MorphingComponent />;
90 instance = ReactTestUtils.renderIntoDocument(instance);
@@ -299,152 +274,6 @@ describe('ReactCompositeComponent', function() {
274 expect(inputProps.prop).not.toBeDefined();
275 });
276
302 - it('should use default prop value when removing a prop', function() {
303 - var Component = React.createClass({
304 - getDefaultProps: function() {
305 - return {fruit: 'persimmon'};
306 - },
307 - render: function() {
308 - return <span />;
309 - }
310 - });
311 -
312 - var container = document.createElement('div');
313 - var instance = React.render(
314 - <Component fruit="mango" />,
315 - container
316 - );
317 - expect(instance.props.fruit).toBe('mango');
318 -
319 - React.render(<Component />, container);
320 - expect(instance.props.fruit).toBe('persimmon');
321 - });
322 -
323 - it('should normalize props with default values', function() {
324 - var Component = React.createClass({
325 - propTypes: {prop: ReactPropTypes.string.isRequired},
326 - getDefaultProps: function() {
327 - return {prop: 'testKey'};
328 - },
329 - getInitialState: function() {
330 - return {prop: this.props.prop + 'State'};
331 - },
332 - render: function() {
333 - return <span>{this.props.prop}</span>;
334 - }
335 - });
336 -
337 - var instance = ReactTestUtils.renderIntoDocument(<Component />);
338 - reactComponentExpect(instance).scalarPropsEqual({prop: 'testKey'});
339 - reactComponentExpect(instance).scalarStateEqual({prop: 'testKeyState'});
340 -
341 - ReactTestUtils.renderIntoDocument(<Component prop={null} />);
342 -
343 - expect(console.warn.mock.calls.length).toBe(1);
344 - expect(console.warn.mock.calls[0][0]).toBe(
345 - 'Warning: Required prop `prop` was not specified in `Component`.'
346 - );
347 - });
348 -
349 - it('should check default prop values', function() {
350 - var Component = React.createClass({
351 - propTypes: {prop: ReactPropTypes.string.isRequired},
352 - getDefaultProps: function() {
353 - return {prop: null};
354 - },
355 - render: function() {
356 - return <span>{this.props.prop}</span>;
357 - }
358 - });
359 -
360 - ReactTestUtils.renderIntoDocument(<Component />);
361 -
362 - expect(console.warn.mock.calls.length).toBe(1);
363 - expect(console.warn.mock.calls[0][0]).toBe(
364 - 'Warning: Required prop `prop` was not specified in `Component`.'
365 - );
366 - });
367 -
368 - it('should check declared prop types', function() {
369 - var Component = React.createClass({
370 - propTypes: {
371 - prop: ReactPropTypes.string.isRequired
372 - },
373 - render: function() {
374 - return <span>{this.props.prop}</span>;
375 - }
376 - });
377 -
378 - ReactTestUtils.renderIntoDocument(<Component />);
379 - ReactTestUtils.renderIntoDocument(<Component prop={42} />);
380 -
381 - expect(console.warn.mock.calls.length).toBe(2);
382 - expect(console.warn.mock.calls[0][0]).toBe(
383 - 'Warning: Required prop `prop` was not specified in `Component`.'
384 - );
385 -
386 - expect(console.warn.mock.calls[1][0]).toBe(
387 - 'Warning: Invalid prop `prop` of type `number` supplied to ' +
388 - '`Component`, expected `string`.'
389 - );
390 -
391 - ReactTestUtils.renderIntoDocument(<Component prop="string" />);
392 -
393 - // Should not error for strings
394 - expect(console.warn.mock.calls.length).toBe(2);
395 - });
396 -
397 - it('should throw on invalid prop types', function() {
398 - expect(function() {
399 - React.createClass({
400 - displayName: 'Component',
401 - propTypes: {
402 - prop: null
403 - },
404 - render: function() {
405 - return <span>{this.props.prop}</span>;
406 - }
407 - });
408 - }).toThrow(
409 - 'Invariant Violation: Component: prop type `prop` is invalid; ' +
410 - 'it must be a function, usually from React.PropTypes.'
411 - );
412 - });
413 -
414 - it('should throw on invalid context types', function() {
415 - expect(function() {
416 - React.createClass({
417 - displayName: 'Component',
418 - contextTypes: {
419 - prop: null
420 - },
421 - render: function() {
422 - return <span>{this.props.prop}</span>;
423 - }
424 - });
425 - }).toThrow(
426 - 'Invariant Violation: Component: context type `prop` is invalid; ' +
427 - 'it must be a function, usually from React.PropTypes.'
428 - );
429 - });
430 -
431 - it('should throw on invalid child context types', function() {
432 - expect(function() {
433 - React.createClass({
434 - displayName: 'Component',
435 - childContextTypes: {
436 - prop: null
437 - },
438 - render: function() {
439 - return <span>{this.props.prop}</span>;
440 - }
441 - });
442 - }).toThrow(
443 - 'Invariant Violation: Component: child context type `prop` is invalid; ' +
444 - 'it must be a function, usually from React.PropTypes.'
445 - );
446 - });
447 -
277 it('should not allow `forceUpdate` on unmounted components', function() {
278 var container = document.createElement('div');
279 document.documentElement.appendChild(container);
@@ -574,228 +403,6 @@ describe('ReactCompositeComponent', function() {
403 expect(ReactCurrentOwner.current).toBe(null);
404 });
405
577 - it('should support mixins with getInitialState()', function() {
578 - var Mixin = {
579 - getInitialState: function() {
580 - return {mixin: true};
581 - }
582 - };
583 - var Component = React.createClass({
584 - mixins: [Mixin],
585 - getInitialState: function() {
586 - return {component: true};
587 - },
588 - render: function() {
589 - return <span />;
590 - }
591 - });
592 - var instance = <Component />;
593 - instance = ReactTestUtils.renderIntoDocument(instance);
594 - expect(instance.state.component).toBe(true);
595 - expect(instance.state.mixin).toBe(true);
596 - });
597 -
598 - it('should throw with conflicting getInitialState() methods', function() {
599 - var Mixin = {
600 - getInitialState: function() {
601 - return {x: true};
602 - }
603 - };
604 - var Component = React.createClass({
605 - mixins: [Mixin],
606 - getInitialState: function() {
607 - return {x: true};
608 - },
609 - render: function() {
610 - return <span />;
611 - }
612 - });
613 - var instance = <Component />;
614 - expect(function() {
615 - instance = ReactTestUtils.renderIntoDocument(instance);
616 - }).toThrow(
617 - 'Invariant Violation: mergeIntoWithNoDuplicateKeys(): ' +
618 - 'Tried to merge two objects with the same key: `x`. This conflict ' +
619 - 'may be due to a mixin; in particular, this may be caused by two ' +
620 - 'getInitialState() or getDefaultProps() methods returning objects ' +
621 - 'with clashing keys.'
622 - );
623 - });
624 -
625 - it('should not mutate objects returned by getInitialState()', function() {
626 - var Mixin = {
627 - getInitialState: function() {
628 - return Object.freeze({mixin: true});
629 - }
630 - };
631 - var Component = React.createClass({
632 - mixins: [Mixin],
633 - getInitialState: function() {
634 - return Object.freeze({component: true});
635 - },
636 - render: function() {
637 - return <span />;
638 - }
639 - });
640 - expect(() => {
641 - ReactTestUtils.renderIntoDocument(<Component />);
642 - }).not.toThrow();
643 - });
644 -
645 - it('should work with object getInitialState() return values', function() {
646 - var Component = React.createClass({
647 - getInitialState: function() {
648 - return {
649 - occupation: 'clown'
650 - };
651 - },
652 - render: function() {
653 - return <span />;
654 - }
655 - });
656 - var instance = <Component />;
657 - instance = ReactTestUtils.renderIntoDocument(instance);
658 - expect(instance.state.occupation).toEqual('clown');
659 - });
660 -
661 - it('should throw with non-object getInitialState() return values', function() {
662 - [['an array'], 'a string', 1234].forEach(function(state) {
663 - var Component = React.createClass({
664 - getInitialState: function() {
665 - return state;
666 - },
667 - render: function() {
668 - return <span />;
669 - }
670 - });
671 - var instance = <Component />;
672 - expect(function() {
673 - instance = ReactTestUtils.renderIntoDocument(instance);
674 - }).toThrow(
675 - 'Invariant Violation: Component.getInitialState(): ' +
676 - 'must return an object or null'
677 - );
678 - });
679 - });
680 -
681 - it('should work with a null getInitialState() return value', function() {
682 - var Component = React.createClass({
683 - getInitialState: function() {
684 - return null;
685 - },
686 - render: function() {
687 - return <span />;
688 - }
689 - });
690 - expect(
691 - () => ReactTestUtils.renderIntoDocument(<Component />)
692 - ).not.toThrow();
693 - });
694 -
695 - it('should work with a null getInitialState return value and a mixin', () => {
696 - var Component;
697 - var instance;
698 -
699 - var Mixin = {
700 - getInitialState: function() {
701 - return {foo: 'bar'};
702 - }
703 - };
704 - Component = React.createClass({
705 - mixins: [Mixin],
706 - getInitialState: function() {
707 - return null;
708 - },
709 - render: function() {
710 - return <span />;
711 - }
712 - });
713 - expect(
714 - () => ReactTestUtils.renderIntoDocument(<Component />)
715 - ).not.toThrow();
716 -
717 - instance = <Component />;
718 - instance = ReactTestUtils.renderIntoDocument(instance);
719 - expect(instance.state).toEqual({foo: 'bar'});
720 -
721 - // Also the other way round should work
722 - var Mixin2 = {
723 - getInitialState: function() {
724 - return null;
725 - }
726 - };
727 - Component = React.createClass({
728 - mixins: [Mixin2],
729 - getInitialState: function() {
730 - return {foo: 'bar'};
731 - },
732 - render: function() {
733 - return <span />;
734 - }
735 - });
736 - expect(
737 - () => ReactTestUtils.renderIntoDocument(<Component />)
738 - ).not.toThrow();
739 -
740 - instance = <Component />;
741 - instance = ReactTestUtils.renderIntoDocument(instance);
742 - expect(instance.state).toEqual({foo: 'bar'});
743 -
744 - // Multiple mixins should be fine too
745 - Component = React.createClass({
746 - mixins: [Mixin, Mixin2],
747 - getInitialState: function() {
748 - return {x: true};
749 - },
750 - render: function() {
751 - return <span />;
752 - }
753 - });
754 - expect(
755 - () => ReactTestUtils.renderIntoDocument(<Component />)
756 - ).not.toThrow();
757 -
758 - instance = <Component />;
759 - instance = ReactTestUtils.renderIntoDocument(instance);
760 - expect(instance.state).toEqual({foo: 'bar', x: true});
761 - });
762 -
763 - it('should work with object getInitialState() return values', function() {
764 - var Component = React.createClass({
765 - getInitialState: function() {
766 - return {
767 - occupation: 'clown'
768 - };
769 - },
770 - render: function() {
771 - return <span />;
772 - }
773 - });
774 - var instance = <Component />;
775 - instance = ReactTestUtils.renderIntoDocument(instance);
776 - expect(instance.state.occupation).toEqual('clown');
777 - });
778 -
779 - it('should throw with non-object getInitialState() return values', function() {
780 - [['an array'], 'a string', 1234].forEach(function(state) {
781 - var Component = React.createClass({
782 - getInitialState: function() {
783 - return state;
784 - },
785 - render: function() {
786 - return <span />;
787 - }
788 - });
789 - var instance = <Component />;
790 - expect(function() {
791 - instance = ReactTestUtils.renderIntoDocument(instance);
792 - }).toThrow(
793 - 'Invariant Violation: Component.getInitialState(): ' +
794 - 'must return an object or null'
795 - );
796 - });
797 - });
798 -
406 it('should call componentWillUnmount before unmounting', function() {
407 var container = document.createElement('div');
408 var innerUnmounted = false;
@@ -866,97 +473,15 @@ describe('ReactCompositeComponent', function() {
473 }
474 });
475
869 - it('should warn when mispelling shouldComponentUpdate', function() {
870 - var warn = console.warn;
871 - console.warn = mocks.getMockFunction();
476 + it('should pass context', function() {
477 + var childInstance = null;
478 + var grandchildInstance = null;
479
873 - try {
874 - React.createClass({
875 - componentShouldUpdate: function() {
876 - return false;
877 - },
878 - render: function() {
879 - return <div />;
880 - }
881 - });
882 - expect(console.warn.mock.calls.length).toBe(1);
883 - expect(console.warn.mock.calls[0][0]).toBe(
884 - 'A component has a method called componentShouldUpdate(). Did you ' +
885 - 'mean shouldComponentUpdate()? The name is phrased as a question ' +
886 - 'because the function is expected to return a value.'
887 - );
888 -
889 - var NamedComponent = React.createClass({
890 - componentShouldUpdate: function() {
891 - return false;
892 - },
893 - render: function() {
894 - return <div />;
895 - }
896 - });
897 - expect(console.warn.mock.calls.length).toBe(2);
898 - expect(console.warn.mock.calls[1][0]).toBe(
899 - 'NamedComponent has a method called componentShouldUpdate(). Did you ' +
900 - 'mean shouldComponentUpdate()? The name is phrased as a question ' +
901 - 'because the function is expected to return a value.'
902 - );
903 -
904 - <NamedComponent />; // Shut up lint
905 - } finally {
906 - console.warn = warn;
907 - }
908 - });
909 -
910 - xit('should warn when using deprecated non-static spec keys', function() {
911 - var warn = console.warn;
912 - console.warn = mocks.getMockFunction();
913 - try {
914 - React.createClass({
915 - mixins: [{}],
916 - propTypes: {
917 - foo: ReactPropTypes.string
918 - },
919 - contextTypes: {
920 - foo: ReactPropTypes.string
921 - },
922 - childContextTypes: {
923 - foo: ReactPropTypes.string
924 - },
925 - render: function() {
926 - return <div />;
927 - }
928 - });
929 - expect(console.warn.mock.calls.length).toBe(4);
930 - expect(console.warn.mock.calls[0][0]).toBe(
931 - 'createClass(...): `mixins` is now a static property and should ' +
932 - 'be defined inside "statics".'
933 - );
934 - expect(console.warn.mock.calls[1][0]).toBe(
935 - 'createClass(...): `propTypes` is now a static property and should ' +
936 - 'be defined inside "statics".'
937 - );
938 - expect(console.warn.mock.calls[2][0]).toBe(
939 - 'createClass(...): `contextTypes` is now a static property and ' +
940 - 'should be defined inside "statics".'
941 - );
942 - expect(console.warn.mock.calls[3][0]).toBe(
943 - 'createClass(...): `childContextTypes` is now a static property and ' +
944 - 'should be defined inside "statics".'
945 - );
946 - } finally {
947 - console.warn = warn;
948 - }
949 - });
950 -
951 - it('should pass context', function() {
952 - var childInstance = null;
953 - var grandchildInstance = null;
954 -
955 - var Parent = React.createClass({
956 - childContextTypes: {
957 - foo: ReactPropTypes.string,
958 - depth: ReactPropTypes.number
959 - },
480 + var Parent = React.createClass({
481 + childContextTypes: {
482 + foo: ReactPropTypes.string,
483 + depth: ReactPropTypes.number
484 + },
485
486 getChildContext: function() {
487 return {
@@ -1074,413 +599,6 @@ describe('ReactCompositeComponent', function() {
599
600 });
601
1077 - it('should check context types', function() {
1078 - var Component = React.createClass({
1079 - contextTypes: {
1080 - foo: ReactPropTypes.string.isRequired
1081 - },
1082 -
1083 - render: function() {
1084 - return <div />;
1085 - }
1086 - });
1087 -
1088 - ReactTestUtils.renderIntoDocument(<Component />);
1089 -
1090 - expect(console.warn.mock.calls.length).toBe(1);
1091 - expect(console.warn.mock.calls[0][0]).toBe(
1092 - 'Warning: Required context `foo` was not specified in `Component`.'
1093 - );
1094 -
1095 - var ComponentInFooStringContext = React.createClass({
1096 - childContextTypes: {
1097 - foo: ReactPropTypes.string
1098 - },
1099 -
1100 - getChildContext: function() {
1101 - return {
1102 - foo: this.props.fooValue
1103 - };
1104 - },
1105 -
1106 - render: function() {
1107 - return <Component />;
1108 - }
1109 - });
1110 -
1111 - ReactTestUtils.renderIntoDocument(<ComponentInFooStringContext fooValue={'bar'} />);
1112 -
1113 - // Previous call should not error
1114 - expect(console.warn.mock.calls.length).toBe(1);
1115 -
1116 - var ComponentInFooNumberContext = React.createClass({
1117 - childContextTypes: {
1118 - foo: ReactPropTypes.number
1119 - },
1120 -
1121 - getChildContext: function() {
1122 - return {
1123 - foo: this.props.fooValue
1124 - };
1125 - },
1126 -
1127 - render: function() {
1128 - return <Component />;
1129 - }
1130 - });
1131 -
1132 - ReactTestUtils.renderIntoDocument(<ComponentInFooNumberContext fooValue={123} />);
1133 -
1134 - expect(console.warn.mock.calls.length).toBe(2);
1135 - expect(console.warn.mock.calls[1][0]).toBe(
1136 - 'Warning: Invalid context `foo` of type `number` supplied ' +
1137 - 'to `Component`, expected `string`.' +
1138 - ' Check the render method of `ComponentInFooNumberContext`.'
1139 - );
1140 - });
1141 -
1142 - it('should check child context types', function() {
1143 - var Component = React.createClass({
1144 - childContextTypes: {
1145 - foo: ReactPropTypes.string.isRequired,
1146 - bar: ReactPropTypes.number
1147 - },
1148 -
1149 - getChildContext: function() {
1150 - return this.props.testContext;
1151 - },
1152 -
1153 - render: function() {
1154 - return <div />;
1155 - }
1156 - });
1157 -
1158 - ReactTestUtils.renderIntoDocument(<Component testContext={{bar: 123}} />);
1159 - expect(console.warn.mock.calls.length).toBe(2);
1160 - expect(console.warn.mock.calls[0][0]).toBe(
1161 - 'Warning: Required child context `foo` was not specified in `Component`.'
1162 - );
1163 - expect(console.warn.mock.calls[1][0]).toBe(
1164 - 'Warning: Required child context `foo` was not specified in `Component`.'
1165 - );
1166 -
1167 - ReactTestUtils.renderIntoDocument(<Component testContext={{foo: 123}} />);
1168 -
1169 - expect(console.warn.mock.calls.length).toBe(4);
1170 - expect(console.warn.mock.calls[3][0]).toBe(
1171 - 'Warning: Invalid child context `foo` of type `number` ' +
1172 - 'supplied to `Component`, expected `string`.'
1173 - );
1174 -
1175 - ReactTestUtils.renderIntoDocument(
1176 - <Component testContext={{foo: 'foo', bar: 123}} />
1177 - );
1178 -
1179 - ReactTestUtils.renderIntoDocument(
1180 - <Component testContext={{foo: 'foo'}} />
1181 - );
1182 -
1183 - // Previous calls should not log errors
1184 - expect(console.warn.mock.calls.length).toBe(4);
1185 - });
1186 -
1187 - it('should filter out context not in contextTypes', function() {
1188 - var Component = React.createClass({
1189 - contextTypes: {
1190 - foo: ReactPropTypes.string
1191 - },
1192 -
1193 - render: function() {
1194 - return <div />;
1195 - }
1196 - });
1197 -
1198 - var ComponentInFooBarContext = React.createClass({
1199 - childContextTypes: {
1200 - foo: ReactPropTypes.string,
1201 - bar: ReactPropTypes.number
1202 - },
1203 -
1204 - getChildContext: function() {
1205 - return {
1206 - foo: 'abc',
1207 - bar: 123
1208 - };
1209 - },
1210 -
1211 - render: function() {
1212 - return <Component />;
1213 - }
1214 - });
1215 -
1216 - var instance = ReactTestUtils.renderIntoDocument(<ComponentInFooBarContext />);
1217 - reactComponentExpect(instance).expectRenderedChild().scalarContextEqual({foo: 'abc'});
1218 - });
1219 -
1220 - it('should filter context properly in callbacks', function() {
1221 - var actualComponentWillReceiveProps;
1222 - var actualShouldComponentUpdate;
1223 - var actualComponentWillUpdate;
1224 - var actualComponentDidUpdate;
1225 -
1226 - var Parent = React.createClass({
1227 - childContextTypes: {
1228 - foo: ReactPropTypes.string.isRequired,
1229 - bar: ReactPropTypes.string.isRequired
1230 - },
1231 -
1232 - getChildContext: function() {
1233 - return {
1234 - foo: this.props.foo,
1235 - bar: "bar"
1236 - };
1237 - },
1238 -
1239 - render: function() {
1240 - return <Component />;
1241 - }
1242 - });
1243 -
1244 - var Component = React.createClass({
1245 - contextTypes: {
1246 - foo: ReactPropTypes.string
1247 - },
1248 -
1249 - componentWillReceiveProps: function(nextProps, nextContext) {
1250 - actualComponentWillReceiveProps = nextContext;
1251 - return true;
1252 - },
1253 -
1254 - shouldComponentUpdate: function(nextProps, nextState, nextContext) {
1255 - actualShouldComponentUpdate = nextContext;
1256 - return true;
1257 - },
1258 -
1259 - componentWillUpdate: function(nextProps, nextState, nextContext) {
1260 - actualComponentWillUpdate = nextContext;
1261 - },
1262 -
1263 - componentDidUpdate: function(prevProps, prevState, prevContext) {
1264 - actualComponentDidUpdate = prevContext;
1265 - },
1266 -
1267 - render: function() {
1268 - return <div />;
1269 - }
1270 - });
1271 -
1272 - var instance = <Parent foo="abc" />;
1273 - instance = ReactTestUtils.renderIntoDocument(instance);
1274 - instance.replaceProps({foo: "def"});
1275 - expect(actualComponentWillReceiveProps).toEqual({foo: 'def'});
1276 - expect(actualShouldComponentUpdate).toEqual({foo: 'def'});
1277 - expect(actualComponentWillUpdate).toEqual({foo: 'def'});
1278 - expect(actualComponentDidUpdate).toEqual({foo: 'abc'});
1279 - });
1280 -
1281 - it('should support statics', function() {
1282 - var Component = React.createClass({
1283 - statics: {
1284 - abc: 'def',
1285 - def: 0,
1286 - ghi: null,
1287 - jkl: 'mno',
1288 - pqr: function() {
1289 - return this;
1290 - }
1291 - },
1292 -
1293 - render: function() {
1294 - return <span />;
1295 - }
1296 - });
1297 - var instance = <Component />;
1298 - instance = ReactTestUtils.renderIntoDocument(instance);
1299 - expect(instance.constructor.abc).toBe('def');
1300 - expect(Component.abc).toBe('def');
1301 - expect(instance.constructor.def).toBe(0);
1302 - expect(Component.def).toBe(0);
1303 - expect(instance.constructor.ghi).toBe(null);
1304 - expect(Component.ghi).toBe(null);
1305 - expect(instance.constructor.jkl).toBe('mno');
1306 - expect(Component.jkl).toBe('mno');
1307 - expect(instance.constructor.pqr()).toBe(Component);
1308 - expect(Component.pqr()).toBe(Component);
1309 - });
1310 -
1311 - it('should throw if a reserved property is in statics', function() {
1312 - expect(function() {
1313 - React.createClass({
1314 - statics: {
1315 - getDefaultProps: function() {
1316 - return {
1317 - foo: 0
1318 - };
1319 - }
1320 - },
1321 -
1322 - render: function() {
1323 - return <span />;
1324 - }
1325 - });
1326 - }).toThrow(
1327 - 'Invariant Violation: ReactClass: You are attempting to ' +
1328 - 'define a reserved property, `getDefaultProps`, that shouldn\'t be on ' +
1329 - 'the "statics" key. Define it as an instance property instead; it ' +
1330 - 'will still be accessible on the constructor.'
1331 - );
1332 - });
1333 -
1334 - it('should support statics in mixins', function() {
1335 - var Mixin = {
1336 - statics: {
1337 - foo: 'bar'
1338 - }
1339 - };
1340 - var Component = React.createClass({
1341 - mixins: [Mixin],
1342 -
1343 - statics: {
1344 - abc: 'def'
1345 - },
1346 -
1347 - render: function() {
1348 - return <span />;
1349 - }
1350 - });
1351 - var instance = <Component />;
1352 - instance = ReactTestUtils.renderIntoDocument(instance);
1353 - expect(instance.constructor.foo).toBe('bar');
1354 - expect(Component.foo).toBe('bar');
1355 - expect(instance.constructor.abc).toBe('def');
1356 - expect(Component.abc).toBe('def');
1357 - });
1358 -
1359 - it("should throw if mixins override each others' statics", function() {
1360 - expect(function() {
1361 - var Mixin = {
1362 - statics: {
1363 - abc: 'foo'
1364 - }
1365 - };
1366 - React.createClass({
1367 - mixins: [Mixin],
1368 -
1369 - statics: {
1370 - abc: 'bar'
1371 - },
1372 -
1373 - render: function() {
1374 - return <span />;
1375 - }
1376 - });
1377 - }).toThrow(
1378 - 'Invariant Violation: ReactClass: You are attempting to ' +
1379 - 'define `abc` on your component more than once. This conflict may be ' +
1380 - 'due to a mixin.'
1381 - );
1382 - });
1383 -
1384 - it("should throw if mixins override functions in statics", function() {
1385 - expect(function() {
1386 - var Mixin = {
1387 - statics: {
1388 - abc: function() { console.log('foo'); }
1389 - }
1390 - };
1391 - React.createClass({
1392 - mixins: [Mixin],
1393 -
1394 - statics: {
1395 - abc: function() { console.log('bar'); }
1396 - },
1397 -
1398 - render: function() {
1399 - return <span />;
1400 - }
1401 - });
1402 - }).toThrow(
1403 - 'Invariant Violation: ReactClass: You are attempting to ' +
1404 - 'define `abc` on your component more than once. This conflict may be ' +
1405 - 'due to a mixin.'
1406 - );
1407 - });
1408 -
1409 - it("should throw if the mixin is a React component", function() {
1410 - expect(function() {
1411 - React.createClass({
1412 - mixins: [<div />],
1413 -
1414 - render: function() {
1415 - return <span />;
1416 - }
1417 - });
1418 - }).toThrow(
1419 - 'Invariant Violation: ReactClass: You\'re attempting to ' +
1420 - 'use a component as a mixin. Instead, just use a regular object.'
1421 - );
1422 - });
1423 -
1424 - it("should throw if the mixin is a React component class", function() {
1425 - expect(function() {
1426 - var Component = React.createClass({
1427 - render: function() {
1428 - return <span />;
1429 - }
1430 - });
1431 -
1432 - React.createClass({
1433 - mixins: [Component],
1434 -
1435 - render: function() {
1436 - return <span />;
1437 - }
1438 - });
1439 - }).toThrow(
1440 - 'Invariant Violation: ReactClass: You\'re attempting to ' +
1441 - 'use a component class as a mixin. Instead, just use a regular object.'
1442 - );
1443 - });
1444 -
1445 - it('should have bound the mixin methods to the component', function() {
1446 - var mixin = {
1447 - mixinFunc: function() {return this;}
1448 - };
1449 -
1450 - var Component = React.createClass({
1451 - mixins: [mixin],
1452 - componentDidMount: function() {
1453 - expect(this.mixinFunc()).toBe(this);
1454 - },
1455 - render: function() {
1456 - return <span />;
1457 - }
1458 - });
1459 - var instance = <Component />;
1460 - instance = ReactTestUtils.renderIntoDocument(instance);
1461 - });
1462 -
1463 - it('should include the mixin keys in even if their values are falsy',
1464 - function() {
1465 - var mixin = {
1466 - keyWithNullValue: null,
1467 - randomCounter: 0
1468 - };
1469 -
1470 - var Component = React.createClass({
1471 - mixins: [mixin],
1472 - componentDidMount: function() {
1473 - expect(this.randomCounter).toBe(0);
1474 - expect(this.keyWithNullValue).toBeNull();
1475 - },
1476 - render: function() {
1477 - return <span />;
1478 - }
1479 - });
1480 - var instance = <Component />;
1481 - instance = ReactTestUtils.renderIntoDocument(instance);
1482 - });
1483 -
602 it('should disallow nested render calls', function() {
603 spyOn(console, 'warn');
604 var Inner = React.createClass({
src/core/__tests__/ReactCompositeComponentMixin-test.js deleted
-171
@@ -1,171 +0,0 @@
1 -/**
2 - * Copyright 2013-2014, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - * @emails react-core
10 - */
11 -
12 -"use strict";
13 -
14 -var mocks = require('mocks');
15 -
16 -var React;
17 -var ReactTestUtils;
18 -var reactComponentExpect;
19 -
20 -var TestComponent;
21 -var TestComponentWithPropTypes;
22 -var TestComponentWithReverseSpec;
23 -var mixinPropValidator;
24 -var componentPropValidator;
25 -
26 -describe('ReactCompositeComponent-mixin', function() {
27 -
28 - beforeEach(function() {
29 - React = require('React');
30 - ReactTestUtils = require('ReactTestUtils');
31 - reactComponentExpect = require('reactComponentExpect');
32 - mixinPropValidator = mocks.getMockFunction();
33 - componentPropValidator = mocks.getMockFunction();
34 -
35 - var MixinA = {
36 - propTypes: {
37 - propA: function() {}
38 - },
39 - componentDidMount: function() {
40 - this.props.listener('MixinA didMount');
41 - }
42 - };
43 -
44 - var MixinB = {
45 - mixins: [MixinA],
46 - propTypes: {
47 - propB: function() {}
48 - },
49 - componentDidMount: function() {
50 - this.props.listener('MixinB didMount');
51 - }
52 - };
53 -
54 - var MixinBWithReverseSpec = {
55 - componentDidMount: function() {
56 - this.props.listener('MixinBWithReverseSpec didMount');
57 - },
58 - mixins: [MixinA]
59 - };
60 -
61 - var MixinC = {
62 - statics: {
63 - staticC: function() {}
64 - },
65 - componentDidMount: function() {
66 - this.props.listener('MixinC didMount');
67 - }
68 - };
69 -
70 - var MixinD = {
71 - propTypes: {
72 - value: mixinPropValidator
73 - }
74 - };
75 -
76 - TestComponent = React.createClass({
77 - mixins: [MixinB, MixinC, MixinD],
78 - statics: {
79 - staticComponent: function() {}
80 - },
81 - propTypes: {
82 - propComponent: function() {}
83 - },
84 - componentDidMount: function() {
85 - this.props.listener('Component didMount');
86 - },
87 - render: function() {
88 - return <div />;
89 - }
90 - });
91 -
92 - TestComponentWithReverseSpec = React.createClass({
93 - render: function() {
94 - return <div />;
95 - },
96 - componentDidMount: function() {
97 - this.props.listener('Component didMount');
98 - },
99 - mixins: [MixinBWithReverseSpec, MixinC, MixinD]
100 - });
101 -
102 - TestComponentWithPropTypes = React.createClass({
103 - mixins: [MixinD],
104 - propTypes: {
105 - value: componentPropValidator
106 - },
107 - render: function() {
108 - return <div />;
109 - }
110 - });
111 - });
112 -
113 - it('should support merging propTypes and statics', function() {
114 - var listener = mocks.getMockFunction();
115 - var instance = <TestComponent listener={listener} />;
116 - instance = ReactTestUtils.renderIntoDocument(instance);
117 -
118 - var instancePropTypes = instance.constructor.propTypes;
119 -
120 - expect('propA' in instancePropTypes).toBe(true);
121 - expect('propB' in instancePropTypes).toBe(true);
122 - expect('propComponent' in instancePropTypes).toBe(true);
123 -
124 - expect('staticC' in TestComponent).toBe(true);
125 - expect('staticComponent' in TestComponent).toBe(true);
126 - });
127 -
128 - it('should support chaining delegate functions', function() {
129 - var listener = mocks.getMockFunction();
130 - var instance = <TestComponent listener={listener} />;
131 - instance = ReactTestUtils.renderIntoDocument(instance);
132 -
133 - expect(listener.mock.calls).toEqual([
134 - ['MixinA didMount'],
135 - ['MixinB didMount'],
136 - ['MixinC didMount'],
137 - ['Component didMount']
138 - ]);
139 - });
140 -
141 - it('should chain functions regardless of spec property order', function() {
142 - var listener = mocks.getMockFunction();
143 - var instance = <TestComponentWithReverseSpec listener={listener} />;
144 - instance = ReactTestUtils.renderIntoDocument(instance);
145 -
146 - expect(listener.mock.calls).toEqual([
147 - ['MixinA didMount'],
148 - ['MixinBWithReverseSpec didMount'],
149 - ['MixinC didMount'],
150 - ['Component didMount']
151 - ]);
152 - });
153 -
154 - it('should validate prop types via mixins', function() {
155 - expect(TestComponent.propTypes).toBeDefined();
156 - expect(TestComponent.propTypes.value)
157 - .toBe(mixinPropValidator);
158 - });
159 -
160 - it('should override mixin prop types with class prop types', function() {
161 - // Sanity check...
162 - expect(componentPropValidator).toNotBe(mixinPropValidator);
163 - // Actually check...
164 - expect(TestComponentWithPropTypes.propTypes)
165 - .toBeDefined();
166 - expect(TestComponentWithPropTypes.propTypes.value)
167 - .toNotBe(mixinPropValidator);
168 - expect(TestComponentWithPropTypes.propTypes.value)
169 - .toBe(componentPropValidator);
170 - });
171 -});
src/core/__tests__/ReactCompositeComponentSpec-test.js deleted
-63
@@ -1,63 +0,0 @@
1 -/**
2 - * Copyright 2013-2014, Facebook, Inc.
3 - * All rights reserved.
4 - *
5 - * This source code is licensed under the BSD-style license found in the
6 - * LICENSE file in the root directory of this source tree. An additional grant
7 - * of patent rights can be found in the PATENTS file in the same directory.
8 - *
9 - * @emails react-core
10 - */
11 -
12 -"use strict";
13 -
14 -var mocks = require('mocks');
15 -
16 -var React;
17 -var ReactTestUtils;
18 -var reactComponentExpect;
19 -
20 -describe('ReactCompositeComponent-spec', function() {
21 -
22 - beforeEach(function() {
23 - React = require('React');
24 - ReactTestUtils = require('ReactTestUtils');
25 - reactComponentExpect = require('reactComponentExpect');
26 - });
27 -
28 - it('should throw when `render` is not specified', function() {
29 - expect(function() {
30 - React.createClass({});
31 - }).toThrow(
32 - 'Invariant Violation: createClass(...): Class specification must ' +
33 - 'implement a `render` method.'
34 - );
35 - });
36 -
37 - it('should copy `displayName` onto the Constructor', function() {
38 - var TestComponent = React.createClass({
39 - render: function() {
40 - return <div />;
41 - }
42 - });
43 -
44 - expect(TestComponent.displayName)
45 - .toBe('TestComponent');
46 - });
47 -
48 - it('should copy prop types onto the Constructor', function() {
49 - var propValidator = mocks.getMockFunction();
50 - var TestComponent = React.createClass({
51 - propTypes: {
52 - value: propValidator
53 - },
54 - render: function() {
55 - return <div />;
56 - }
57 - });
58 -
59 - expect(TestComponent.propTypes).toBeDefined();
60 - expect(TestComponent.propTypes.value)
61 - .toBe(propValidator);
62 - });
63 -});