@samitouri / QOS-React-2 / commits / 70bf3e1306

Give useful error when using two copies of React

If we don't error here, we end up with a confusing error later on in this.getDOMNode() where ReactMount doesn't have the proper container registered in its object.

Ben Alpert committed May 14, 2014 at 19:12 UTC 70bf3e1306395a2bd1e65bce60b5511875b00800
3 files changed +668 -619
src/browser/ui/ReactMount.js
+17 -1
@@ -19,8 +19,9 @@
19 "use strict";
20
21 var DOMProperty = require('DOMProperty');
22 -var ReactCurrentOwner = require('ReactCurrentOwner');
22 var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
23 +var ReactCurrentOwner = require('ReactCurrentOwner');
24 +var ReactDescriptor = require('ReactDescriptor');
25 var ReactInstanceHandles = require('ReactInstanceHandles');
26 var ReactPerf = require('ReactPerf');
27
@@ -335,6 +336,21 @@ var ReactMount = {
336 * @return {ReactComponent} Component instance rendered in `container`.
337 */
338 renderComponent: function(nextDescriptor, container, callback) {
339 + invariant(
340 + ReactDescriptor.isValidDescriptor(nextDescriptor),
341 + 'renderComponent(): Invalid component descriptor.%s',
342 + (
343 + ReactDescriptor.isValidFactory(nextDescriptor) ?
344 + ' Instead of passing a component class, make sure to instantiate ' +
345 + 'it first by calling it with props.' :
346 + // Check if it quacks like a descriptor
347 + typeof nextDescriptor.props !== "undefined" ?
348 + ' This may be caused by unintentionally loading two independent ' +
349 + 'copies of React.' :
350 + ''
351 + )
352 + );
353 +
354 var prevComponent = instancesByReactRootID[getReactRootID(container)];
355
356 if (prevComponent) {
src/browser/ui/__tests__/ReactMount-test.js
+24
@@ -24,6 +24,7 @@ var mocks = require('mocks');
24 describe('ReactMount', function() {
25 var React = require('React');
26 var ReactMount = require('ReactMount');
27 + var ReactTestUtils = require('ReactTestUtils');
28
29 describe('constructAndRenderComponentByID', function() {
30 it('throws if given an id for a component that doesn\'t exist', function() {
@@ -37,6 +38,29 @@ describe('ReactMount', function() {
38 });
39 });
40
41 + it('throws when given a factory', function() {
42 + expect(function() {
43 + ReactTestUtils.renderIntoDocument(React.DOM.div);
44 + }).toThrow(
45 + 'Invariant Violation: renderComponent(): Invalid component descriptor. ' +
46 + 'Instead of passing a component class, make sure to instantiate it ' +
47 + 'first by calling it with props.'
48 + );
49 +
50 + var Component = React.createClass({
51 + render: function() {
52 + return <div />;
53 + }
54 + });
55 + expect(function() {
56 + ReactTestUtils.renderIntoDocument(Component);
57 + }).toThrow(
58 + 'Invariant Violation: renderComponent(): Invalid component descriptor. ' +
59 + 'Instead of passing a component class, make sure to instantiate it ' +
60 + 'first by calling it with props.'
61 + );
62 + });
63 +
64 it('should render different components in same root', function() {
65 var container = document.createElement('container');
66 document.documentElement.appendChild(container);
src/core/__tests__/ReactPropTypes-test.js
+627 -618
@@ -19,12 +19,11 @@
19
20 "use strict";
21
22 +var PropTypes;
23 +var React;
24 +var ReactPropTypeLocations;
25 var ReactTestUtils;
26
24 -var PropTypes = require('ReactPropTypes');
25 -var React = require('React');
26 -var ReactPropTypeLocations = require('ReactPropTypeLocations');
27 -
27 var Component;
28 var MyComponent;
29 var requiredMessage =
@@ -53,713 +52,701 @@ function typeCheckPass(declaration, value) {
52 expect(error).toBe(undefined);
53 }
54
56 -describe('Primitive Types', function() {
57 - it("should warn for invalid strings", function() {
58 - typeCheckFail(
59 - PropTypes.string,
60 - [],
61 - 'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
62 - 'expected `string`.'
63 - );
64 - typeCheckFail(
65 - PropTypes.string,
66 - false,
67 - 'Invalid prop `testProp` of type `boolean` supplied to ' +
68 - '`testComponent`, expected `string`.'
69 - );
70 - typeCheckFail(
71 - PropTypes.string,
72 - 0,
73 - 'Invalid prop `testProp` of type `number` supplied to ' +
74 - '`testComponent`, expected `string`.'
75 - );
76 - typeCheckFail(
77 - PropTypes.string,
78 - {},
79 - 'Invalid prop `testProp` of type `object` supplied to ' +
80 - '`testComponent`, expected `string`.'
81 - );
55 +describe('ReactPropTypes', function() {
56 + beforeEach(function() {
57 + PropTypes = require('ReactPropTypes');
58 + React = require('React');
59 + ReactPropTypeLocations = require('ReactPropTypeLocations');
60 + ReactTestUtils = require('ReactTestUtils');
61 });
62
84 - it('should fail date and regexp correctly', function() {
85 - typeCheckFail(
86 - PropTypes.string,
87 - new Date(),
88 - 'Invalid prop `testProp` of type `date` supplied to ' +
89 - '`testComponent`, expected `string`.'
90 - );
91 - typeCheckFail(
92 - PropTypes.string,
93 - /please/,
94 - 'Invalid prop `testProp` of type `regexp` supplied to ' +
95 - '`testComponent`, expected `string`.'
96 - );
97 - });
63 + describe('Primitive Types', function() {
64 + it("should warn for invalid strings", function() {
65 + typeCheckFail(
66 + PropTypes.string,
67 + [],
68 + 'Invalid prop `testProp` of type `array` supplied to ' +
69 + '`testComponent`, expected `string`.'
70 + );
71 + typeCheckFail(
72 + PropTypes.string,
73 + false,
74 + 'Invalid prop `testProp` of type `boolean` supplied to ' +
75 + '`testComponent`, expected `string`.'
76 + );
77 + typeCheckFail(
78 + PropTypes.string,
79 + 0,
80 + 'Invalid prop `testProp` of type `number` supplied to ' +
81 + '`testComponent`, expected `string`.'
82 + );
83 + typeCheckFail(
84 + PropTypes.string,
85 + {},
86 + 'Invalid prop `testProp` of type `object` supplied to ' +
87 + '`testComponent`, expected `string`.'
88 + );
89 + });
90
99 - it("should not warn for valid values", function() {
100 - typeCheckPass(PropTypes.array, []);
101 - typeCheckPass(PropTypes.bool, false);
102 - typeCheckPass(PropTypes.func, function() {});
103 - typeCheckPass(PropTypes.number, 0);
104 - typeCheckPass(PropTypes.string, '');
105 - typeCheckPass(PropTypes.object, {});
106 - typeCheckPass(PropTypes.object, new Date());
107 - typeCheckPass(PropTypes.object, /please/);
108 - });
91 + it('should fail date and regexp correctly', function() {
92 + typeCheckFail(
93 + PropTypes.string,
94 + new Date(),
95 + 'Invalid prop `testProp` of type `date` supplied to ' +
96 + '`testComponent`, expected `string`.'
97 + );
98 + typeCheckFail(
99 + PropTypes.string,
100 + /please/,
101 + 'Invalid prop `testProp` of type `regexp` supplied to ' +
102 + '`testComponent`, expected `string`.'
103 + );
104 + });
105
110 - it("should be implicitly optional and not warn without values", function() {
111 - typeCheckPass(PropTypes.string, null);
112 - typeCheckPass(PropTypes.string, undefined);
113 - });
106 + it("should not warn for valid values", function() {
107 + typeCheckPass(PropTypes.array, []);
108 + typeCheckPass(PropTypes.bool, false);
109 + typeCheckPass(PropTypes.func, function() {});
110 + typeCheckPass(PropTypes.number, 0);
111 + typeCheckPass(PropTypes.string, '');
112 + typeCheckPass(PropTypes.object, {});
113 + typeCheckPass(PropTypes.object, new Date());
114 + typeCheckPass(PropTypes.object, /please/);
115 + });
116
115 - it("should warn for missing required values", function() {
116 - typeCheckFail(PropTypes.string.isRequired, null, requiredMessage);
117 - typeCheckFail(PropTypes.string.isRequired, undefined, requiredMessage);
118 - });
119 -});
117 + it("should be implicitly optional and not warn without values", function() {
118 + typeCheckPass(PropTypes.string, null);
119 + typeCheckPass(PropTypes.string, undefined);
120 + });
121
121 -describe('Any type', function() {
122 - it('should should accept any value', function() {
123 - typeCheckPass(PropTypes.any, 0);
124 - typeCheckPass(PropTypes.any, 'str');
125 - typeCheckPass(PropTypes.any, []);
122 + it("should warn for missing required values", function() {
123 + typeCheckFail(PropTypes.string.isRequired, null, requiredMessage);
124 + typeCheckFail(PropTypes.string.isRequired, undefined, requiredMessage);
125 + });
126 });
127
128 - it("should be implicitly optional and not warn without values", function() {
129 - typeCheckPass(PropTypes.any, null);
130 - typeCheckPass(PropTypes.any, undefined);
131 - });
128 + describe('Any type', function() {
129 + it('should should accept any value', function() {
130 + typeCheckPass(PropTypes.any, 0);
131 + typeCheckPass(PropTypes.any, 'str');
132 + typeCheckPass(PropTypes.any, []);
133 + });
134
133 - it("should warn for missing required values", function() {
134 - typeCheckFail(PropTypes.any.isRequired, null, requiredMessage);
135 - typeCheckFail(PropTypes.any.isRequired, undefined, requiredMessage);
136 - });
137 -});
135 + it("should be implicitly optional and not warn without values", function() {
136 + typeCheckPass(PropTypes.any, null);
137 + typeCheckPass(PropTypes.any, undefined);
138 + });
139
139 -describe('ArrayOf Type', function() {
140 - it('should support the arrayOf propTypes', function() {
141 - typeCheckPass(PropTypes.arrayOf(PropTypes.number), [1, 2, 3]);
142 - typeCheckPass(PropTypes.arrayOf(PropTypes.string), ['a', 'b', 'c']);
143 - typeCheckPass(PropTypes.arrayOf(PropTypes.oneOf(['a', 'b'])), ['a', 'b']);
140 + it("should warn for missing required values", function() {
141 + typeCheckFail(PropTypes.any.isRequired, null, requiredMessage);
142 + typeCheckFail(PropTypes.any.isRequired, undefined, requiredMessage);
143 + });
144 });
145
146 - it('should support arrayOf with complex types', function() {
147 - typeCheckPass(
148 - PropTypes.arrayOf(PropTypes.shape({a: PropTypes.number.isRequired})),
149 - [{a: 1}, {a: 2}]
150 - );
146 + describe('ArrayOf Type', function() {
147 + it('should support the arrayOf propTypes', function() {
148 + typeCheckPass(PropTypes.arrayOf(PropTypes.number), [1, 2, 3]);
149 + typeCheckPass(PropTypes.arrayOf(PropTypes.string), ['a', 'b', 'c']);
150 + typeCheckPass(PropTypes.arrayOf(PropTypes.oneOf(['a', 'b'])), ['a', 'b']);
151 + });
152
152 - function Thing() {}
153 - typeCheckPass(
154 - PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
155 - [new Thing(), new Thing()]
156 - );
157 - });
153 + it('should support arrayOf with complex types', function() {
154 + typeCheckPass(
155 + PropTypes.arrayOf(PropTypes.shape({a: PropTypes.number.isRequired})),
156 + [{a: 1}, {a: 2}]
157 + );
158
159 - it('should warn with invalid items in the array', function() {
160 - typeCheckFail(
161 - PropTypes.arrayOf(PropTypes.number),
162 - [1, 2, 'b'],
163 - 'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
164 - 'expected `number`.'
165 - );
166 - });
159 + function Thing() {}
160 + typeCheckPass(
161 + PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
162 + [new Thing(), new Thing()]
163 + );
164 + });
165
168 - it('should warn with invalid complex types', function() {
169 - function Thing() {}
170 - var name = Thing.name || '<<anonymous>>';
166 + it('should warn with invalid items in the array', function() {
167 + typeCheckFail(
168 + PropTypes.arrayOf(PropTypes.number),
169 + [1, 2, 'b'],
170 + 'Invalid prop `2` of type `string` supplied to `testComponent`, ' +
171 + 'expected `number`.'
172 + );
173 + });
174
172 - typeCheckFail(
173 - PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
174 - [new Thing(), 'xyz'],
175 - 'Invalid prop `1` supplied to `testComponent`, expected instance of `' +
176 - name + '`.'
177 - );
178 - });
175 + it('should warn with invalid complex types', function() {
176 + function Thing() {}
177 + var name = Thing.name || '<<anonymous>>';
178
180 - it('should warn when passed something other than an array', function() {
181 - typeCheckFail(
182 - PropTypes.arrayOf(PropTypes.number),
183 - {'0': 'maybe-array', length: 1},
184 - 'Invalid prop `testProp` of type `object` supplied to `testComponent`, ' +
185 - 'expected an array.'
186 - );
187 - typeCheckFail(
188 - PropTypes.arrayOf(PropTypes.number),
189 - 123,
190 - 'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
191 - 'expected an array.'
192 - );
193 - typeCheckFail(
194 - PropTypes.arrayOf(PropTypes.number),
195 - 'string',
196 - 'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
197 - 'expected an array.'
198 - );
199 - });
179 + typeCheckFail(
180 + PropTypes.arrayOf(PropTypes.instanceOf(Thing)),
181 + [new Thing(), 'xyz'],
182 + 'Invalid prop `1` supplied to `testComponent`, expected instance of `' +
183 + name + '`.'
184 + );
185 + });
186
201 - it('should not warn when passing an empty array', function() {
202 - typeCheckPass(PropTypes.arrayOf(PropTypes.number), []);
203 - });
187 + it('should warn when passed something other than an array', function() {
188 + typeCheckFail(
189 + PropTypes.arrayOf(PropTypes.number),
190 + {'0': 'maybe-array', length: 1},
191 + 'Invalid prop `testProp` of type `object` supplied to ' +
192 + '`testComponent`, expected an array.'
193 + );
194 + typeCheckFail(
195 + PropTypes.arrayOf(PropTypes.number),
196 + 123,
197 + 'Invalid prop `testProp` of type `number` supplied to ' +
198 + '`testComponent`, expected an array.'
199 + );
200 + typeCheckFail(
201 + PropTypes.arrayOf(PropTypes.number),
202 + 'string',
203 + 'Invalid prop `testProp` of type `string` supplied to ' +
204 + '`testComponent`, expected an array.'
205 + );
206 + });
207
205 - it("should be implicitly optional and not warn without values", function() {
206 - typeCheckPass(PropTypes.arrayOf(PropTypes.number), null);
207 - typeCheckPass(PropTypes.arrayOf(PropTypes.number), undefined);
208 - });
208 + it('should not warn when passing an empty array', function() {
209 + typeCheckPass(PropTypes.arrayOf(PropTypes.number), []);
210 + });
211
210 - it("should warn for missing required values", function() {
211 - typeCheckFail(
212 - PropTypes.arrayOf(PropTypes.number).isRequired, null, requiredMessage
213 - );
214 - typeCheckFail(
215 - PropTypes.arrayOf(PropTypes.number).isRequired, undefined, requiredMessage
216 - );
212 + it("should be implicitly optional and not warn without values", function() {
213 + typeCheckPass(PropTypes.arrayOf(PropTypes.number), null);
214 + typeCheckPass(PropTypes.arrayOf(PropTypes.number), undefined);
215 + });
216 +
217 + it("should warn for missing required values", function() {
218 + typeCheckFail(
219 + PropTypes.arrayOf(PropTypes.number).isRequired,
220 + null,
221 + requiredMessage
222 + );
223 + typeCheckFail(
224 + PropTypes.arrayOf(PropTypes.number).isRequired,
225 + undefined,
226 + requiredMessage
227 + );
228 + });
229 });
218 -});
230
220 -describe('Component Type', function() {
221 - beforeEach(function() {
222 - require('mock-modules').dumpCache();
223 - ReactTestUtils = require('ReactTestUtils');
224 - Component = React.createClass({
225 - propTypes: {
226 - label: PropTypes.component.isRequired
227 - },
231 + describe('Component Type', function() {
232 + beforeEach(function() {
233 + Component = React.createClass({
234 + propTypes: {
235 + label: PropTypes.component.isRequired
236 + },
237
229 - render: function() {
230 - return <div>{this.props.label}</div>;
231 - }
238 + render: function() {
239 + return <div>{this.props.label}</div>;
240 + }
241 + });
242 + spyOn(console, 'warn');
243 });
233 - spyOn(console, 'warn');
234 - });
244
236 - it('should support components', () => {
237 - typeCheckPass(PropTypes.component, <div />);
238 - });
245 + it('should support components', () => {
246 + typeCheckPass(PropTypes.component, <div />);
247 + });
248
240 - it('should not support multiple components or scalar values', () => {
241 - var message = 'Invalid prop `testProp` supplied to `testComponent`, ' +
242 - 'expected a React component.';
243 - typeCheckFail(PropTypes.component, [<div />, <div />], message);
244 - typeCheckFail(PropTypes.component, 123, message);
245 - typeCheckFail(PropTypes.component, 'foo', message);
246 - typeCheckFail(PropTypes.component, false, message);
247 - });
249 + it('should not support multiple components or scalar values', () => {
250 + var message = 'Invalid prop `testProp` supplied to `testComponent`, ' +
251 + 'expected a React component.';
252 + typeCheckFail(PropTypes.component, [<div />, <div />], message);
253 + typeCheckFail(PropTypes.component, 123, message);
254 + typeCheckFail(PropTypes.component, 'foo', message);
255 + typeCheckFail(PropTypes.component, false, message);
256 + });
257
249 - it('should be able to define a single child as label', () => {
250 - var instance = <Component label={<div />} />;
251 - instance = ReactTestUtils.renderIntoDocument(instance);
258 + it('should be able to define a single child as label', () => {
259 + var instance = <Component label={<div />} />;
260 + instance = ReactTestUtils.renderIntoDocument(instance);
261
253 - expect(console.warn.argsForCall.length).toBe(0);
254 - });
262 + expect(console.warn.argsForCall.length).toBe(0);
263 + });
264
256 - it('should warn when passing no label and isRequired is set', () => {
257 - var instance = <Component />;
258 - instance = ReactTestUtils.renderIntoDocument(instance);
265 + it('should warn when passing no label and isRequired is set', () => {
266 + var instance = <Component />;
267 + instance = ReactTestUtils.renderIntoDocument(instance);
268
260 - expect(console.warn.argsForCall.length).toBe(1);
261 - });
269 + expect(console.warn.argsForCall.length).toBe(1);
270 + });
271
263 - it("should be implicitly optional and not warn without values", function() {
264 - typeCheckPass(PropTypes.component, null);
265 - typeCheckPass(PropTypes.component, undefined);
266 - });
272 + it("should be implicitly optional and not warn without values", function() {
273 + typeCheckPass(PropTypes.component, null);
274 + typeCheckPass(PropTypes.component, undefined);
275 + });
276
268 - it("should warn for missing required values", function() {
269 - typeCheckFail(PropTypes.component.isRequired, null, requiredMessage);
270 - typeCheckFail(PropTypes.component.isRequired, undefined, requiredMessage);
277 + it("should warn for missing required values", function() {
278 + typeCheckFail(PropTypes.component.isRequired, null, requiredMessage);
279 + typeCheckFail(PropTypes.component.isRequired, undefined, requiredMessage);
280 + });
281 });
272 -});
282
274 -describe('Instance Types', function() {
275 - it("should warn for invalid instances", function() {
276 - function Person() {}
277 - var personName = Person.name || '<<anonymous>>';
278 - var dateName = Date.name || '<<anonymous>>';
279 - var regExpName = RegExp.name || '<<anonymous>>';
280 -
281 - typeCheckFail(
282 - PropTypes.instanceOf(Person),
283 - false,
284 - 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
285 - 'instance of `' + personName + '`.'
286 - );
287 - typeCheckFail(
288 - PropTypes.instanceOf(Person),
289 - {},
290 - 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
291 - 'instance of `' + personName + '`.'
292 - );
293 - typeCheckFail(
294 - PropTypes.instanceOf(Person),
295 - '',
296 - 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
297 - 'instance of `' + personName + '`.'
298 - );
299 - typeCheckFail(
300 - PropTypes.instanceOf(Date),
301 - {},
302 - 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
303 - 'instance of `' + dateName + '`.'
304 - );
305 - typeCheckFail(
306 - PropTypes.instanceOf(RegExp),
307 - {},
308 - 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
309 - 'instance of `' + regExpName + '`.'
310 - );
311 - });
283 + describe('Instance Types', function() {
284 + it("should warn for invalid instances", function() {
285 + function Person() {}
286 + var personName = Person.name || '<<anonymous>>';
287 + var dateName = Date.name || '<<anonymous>>';
288 + var regExpName = RegExp.name || '<<anonymous>>';
289
313 - it("should not warn for valid values", function() {
314 - function Person() {}
315 - function Engineer() {}
316 - Engineer.prototype = new Person();
290 + typeCheckFail(
291 + PropTypes.instanceOf(Person),
292 + false,
293 + 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
294 + 'instance of `' + personName + '`.'
295 + );
296 + typeCheckFail(
297 + PropTypes.instanceOf(Person),
298 + {},
299 + 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
300 + 'instance of `' + personName + '`.'
301 + );
302 + typeCheckFail(
303 + PropTypes.instanceOf(Person),
304 + '',
305 + 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
306 + 'instance of `' + personName + '`.'
307 + );
308 + typeCheckFail(
309 + PropTypes.instanceOf(Date),
310 + {},
311 + 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
312 + 'instance of `' + dateName + '`.'
313 + );
314 + typeCheckFail(
315 + PropTypes.instanceOf(RegExp),
316 + {},
317 + 'Invalid prop `testProp` supplied to `testComponent`, expected ' +
318 + 'instance of `' + regExpName + '`.'
319 + );
320 + });
321
318 - typeCheckPass(PropTypes.instanceOf(Person), new Person());
319 - typeCheckPass(PropTypes.instanceOf(Person), new Engineer());
322 + it("should not warn for valid values", function() {
323 + function Person() {}
324 + function Engineer() {}
325 + Engineer.prototype = new Person();
326
321 - typeCheckPass(PropTypes.instanceOf(Date), new Date());
322 - typeCheckPass(PropTypes.instanceOf(RegExp), /please/);
323 - });
327 + typeCheckPass(PropTypes.instanceOf(Person), new Person());
328 + typeCheckPass(PropTypes.instanceOf(Person), new Engineer());
329
325 - it("should be implicitly optional and not warn without values", function() {
326 - typeCheckPass(PropTypes.instanceOf(String), null);
327 - typeCheckPass(PropTypes.instanceOf(String), undefined);
328 - });
330 + typeCheckPass(PropTypes.instanceOf(Date), new Date());
331 + typeCheckPass(PropTypes.instanceOf(RegExp), /please/);
332 + });
333
330 - it("should warn for missing required values", function() {
331 - typeCheckFail(
332 - PropTypes.instanceOf(String).isRequired, null, requiredMessage
333 - );
334 - typeCheckFail(
335 - PropTypes.instanceOf(String).isRequired, undefined, requiredMessage
336 - );
337 - });
338 -});
334 + it("should be implicitly optional and not warn without values", function() {
335 + typeCheckPass(PropTypes.instanceOf(String), null);
336 + typeCheckPass(PropTypes.instanceOf(String), undefined);
337 + });
338
340 -describe('React Component Types', function() {
341 - beforeEach(function() {
342 - MyComponent = React.createClass({
343 - render: function() {
344 - return <div />;
345 - }
339 + it("should warn for missing required values", function() {
340 + typeCheckFail(
341 + PropTypes.instanceOf(String).isRequired, null, requiredMessage
342 + );
343 + typeCheckFail(
344 + PropTypes.instanceOf(String).isRequired, undefined, requiredMessage
345 + );
346 });
347 });
348
349 - it('should warn for invalid values', function() {
350 - var failMessage = 'Invalid prop `testProp` supplied to `testComponent`, ' +
351 - 'expected a renderable prop.';
352 - typeCheckFail(PropTypes.renderable, true, failMessage);
353 - typeCheckFail(PropTypes.renderable, function() {}, failMessage);
354 - typeCheckFail(PropTypes.renderable, {key: function() {}}, failMessage);
355 - });
349 + describe('React Component Types', function() {
350 + beforeEach(function() {
351 + MyComponent = React.createClass({
352 + render: function() {
353 + return <div />;
354 + }
355 + });
356 + });
357
357 - it('should not warn for valid values', function() {
358 - typeCheckPass(PropTypes.renderable, <div />);
359 - typeCheckPass(PropTypes.renderable, false);
360 - typeCheckPass(PropTypes.renderable, <MyComponent />);
361 - typeCheckPass(PropTypes.renderable, 'Some string');
362 - typeCheckPass(PropTypes.renderable, []);
363 - typeCheckPass(PropTypes.renderable, {});
364 - typeCheckPass(PropTypes.renderable, [
365 - 123,
366 - 'Some string',
367 - <div />,
368 - ['Another string', [456], <span />, <MyComponent />],
369 - <MyComponent />
370 - ]);
371 -
372 - // Object of rendereable things
373 - typeCheckPass(PropTypes.renderable, {
374 - k0: 123,
375 - k1: 'Some string',
376 - k2: <div />,
377 - k3: {
378 - k30: <MyComponent />,
379 - k31: {k310: <a />},
380 - k32: 'Another string'
381 - }
358 + it('should warn for invalid values', function() {
359 + var failMessage = 'Invalid prop `testProp` supplied to ' +
360 + '`testComponent`, expected a renderable prop.';
361 + typeCheckFail(PropTypes.renderable, true, failMessage);
362 + typeCheckFail(PropTypes.renderable, function() {}, failMessage);
363 + typeCheckFail(PropTypes.renderable, {key: function() {}}, failMessage);
364 });
383 - });
365
385 - it('should not warn for null/undefined if not required', function() {
386 - typeCheckPass(PropTypes.renderable, null);
387 - typeCheckPass(PropTypes.renderable, undefined);
388 - });
366 + it('should not warn for valid values', function() {
367 + typeCheckPass(PropTypes.renderable, <div />);
368 + typeCheckPass(PropTypes.renderable, false);
369 + typeCheckPass(PropTypes.renderable, <MyComponent />);
370 + typeCheckPass(PropTypes.renderable, 'Some string');
371 + typeCheckPass(PropTypes.renderable, []);
372 + typeCheckPass(PropTypes.renderable, {});
373 + typeCheckPass(PropTypes.renderable, [
374 + 123,
375 + 'Some string',
376 + <div />,
377 + ['Another string', [456], <span />, <MyComponent />],
378 + <MyComponent />
379 + ]);
380 +
381 + // Object of rendereable things
382 + typeCheckPass(PropTypes.renderable, {
383 + k0: 123,
384 + k1: 'Some string',
385 + k2: <div />,
386 + k3: {
387 + k30: <MyComponent />,
388 + k31: {k310: <a />},
389 + k32: 'Another string'
390 + }
391 + });
392 + });
393
390 - it('should warn for missing required values', function() {
391 - typeCheckFail(
392 - PropTypes.renderable.isRequired,
393 - null,
394 - 'Required prop `testProp` was not specified in `testComponent`.'
395 - );
396 - typeCheckFail(
397 - PropTypes.renderable.isRequired,
398 - undefined,
399 - 'Required prop `testProp` was not specified in `testComponent`.'
400 - );
401 - });
394 + it('should not warn for null/undefined if not required', function() {
395 + typeCheckPass(PropTypes.renderable, null);
396 + typeCheckPass(PropTypes.renderable, undefined);
397 + });
398
403 - it('should accept empty array & object for required props', function() {
404 - typeCheckPass(PropTypes.renderable.isRequired, []);
405 - typeCheckPass(PropTypes.renderable.isRequired, {});
406 - });
407 -});
399 + it('should warn for missing required values', function() {
400 + typeCheckFail(
401 + PropTypes.renderable.isRequired,
402 + null,
403 + 'Required prop `testProp` was not specified in `testComponent`.'
404 + );
405 + typeCheckFail(
406 + PropTypes.renderable.isRequired,
407 + undefined,
408 + 'Required prop `testProp` was not specified in `testComponent`.'
409 + );
410 + });
411
409 -describe('ObjectOf Type', function() {
410 - it('should support the objectOf propTypes', function() {
411 - typeCheckPass(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
412 - typeCheckPass(
413 - PropTypes.objectOf(PropTypes.string),
414 - {a: 'a', b: 'b', c: 'c'}
415 - );
416 - typeCheckPass(
417 - PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])),
418 - {a: 'a', b: 'b'}
419 - );
412 + it('should accept empty array & object for required props', function() {
413 + typeCheckPass(PropTypes.renderable.isRequired, []);
414 + typeCheckPass(PropTypes.renderable.isRequired, {});
415 + });
416 });
417
422 - it('should support objectOf with complex types', function() {
423 - typeCheckPass(
424 - PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
425 - {a: {a: 1}, b: {a: 2}}
426 - );
427 -
428 - function Thing() {}
429 - typeCheckPass(
430 - PropTypes.objectOf(PropTypes.instanceOf(Thing)),
431 - {a: new Thing(), b: new Thing()}
432 - );
433 - });
418 + describe('ObjectOf Type', function() {
419 + it('should support the objectOf propTypes', function() {
420 + typeCheckPass(PropTypes.objectOf(PropTypes.number), {a: 1, b: 2, c: 3});
421 + typeCheckPass(
422 + PropTypes.objectOf(PropTypes.string),
423 + {a: 'a', b: 'b', c: 'c'}
424 + );
425 + typeCheckPass(
426 + PropTypes.objectOf(PropTypes.oneOf(['a', 'b'])),
427 + {a: 'a', b: 'b'}
428 + );
429 + });
430
435 - it('should warn with invalid items in the object', function() {
436 - typeCheckFail(
437 - PropTypes.objectOf(PropTypes.number),
438 - {a: 1, b: 2, c: 'b'},
439 - 'Invalid prop `c` of type `string` supplied to `testComponent`, ' +
440 - 'expected `number`.'
441 - );
442 - });
431 + it('should support objectOf with complex types', function() {
432 + typeCheckPass(
433 + PropTypes.objectOf(PropTypes.shape({a: PropTypes.number.isRequired})),
434 + {a: {a: 1}, b: {a: 2}}
435 + );
436
444 - it('should warn with invalid complex types', function() {
445 - function Thing() {}
446 - var name = Thing.name || '<<anonymous>>';
437 + function Thing() {}
438 + typeCheckPass(
439 + PropTypes.objectOf(PropTypes.instanceOf(Thing)),
440 + {a: new Thing(), b: new Thing()}
441 + );
442 + });
443
448 - typeCheckFail(
449 - PropTypes.objectOf(PropTypes.instanceOf(Thing)),
450 - {a: new Thing(), b: 'xyz'},
451 - 'Invalid prop `b` supplied to `testComponent`, expected instance of `' +
452 - name + '`.'
453 - );
454 - });
444 + it('should warn with invalid items in the object', function() {
445 + typeCheckFail(
446 + PropTypes.objectOf(PropTypes.number),
447 + {a: 1, b: 2, c: 'b'},
448 + 'Invalid prop `c` of type `string` supplied to `testComponent`, ' +
449 + 'expected `number`.'
450 + );
451 + });
452
456 - it('should warn when passed something other than an object', function() {
457 - typeCheckFail(
458 - PropTypes.objectOf(PropTypes.number),
459 - [1, 2],
460 - 'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
461 - 'expected an object.'
462 - );
463 - typeCheckFail(
464 - PropTypes.objectOf(PropTypes.number),
465 - 123,
466 - 'Invalid prop `testProp` of type `number` supplied to `testComponent`, ' +
467 - 'expected an object.'
468 - );
469 - typeCheckFail(
470 - PropTypes.objectOf(PropTypes.number),
471 - 'string',
472 - 'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
473 - 'expected an object.'
474 - );
475 - });
453 + it('should warn with invalid complex types', function() {
454 + function Thing() {}
455 + var name = Thing.name || '<<anonymous>>';
456
477 - it('should not warn when passing an empty object', function() {
478 - typeCheckPass(PropTypes.objectOf(PropTypes.number), {});
479 - });
457 + typeCheckFail(
458 + PropTypes.objectOf(PropTypes.instanceOf(Thing)),
459 + {a: new Thing(), b: 'xyz'},
460 + 'Invalid prop `b` supplied to `testComponent`, expected instance of `' +
461 + name + '`.'
462 + );
463 + });
464
481 - it("should be implicitly optional and not warn without values", function() {
482 - typeCheckPass(PropTypes.objectOf(PropTypes.number), null);
483 - typeCheckPass(PropTypes.objectOf(PropTypes.number), undefined);
484 - });
465 + it('should warn when passed something other than an object', function() {
466 + typeCheckFail(
467 + PropTypes.objectOf(PropTypes.number),
468 + [1, 2],
469 + 'Invalid prop `testProp` of type `array` supplied to ' +
470 + '`testComponent`, expected an object.'
471 + );
472 + typeCheckFail(
473 + PropTypes.objectOf(PropTypes.number),
474 + 123,
475 + 'Invalid prop `testProp` of type `number` supplied to ' +
476 + '`testComponent`, expected an object.'
477 + );
478 + typeCheckFail(
479 + PropTypes.objectOf(PropTypes.number),
480 + 'string',
481 + 'Invalid prop `testProp` of type `string` supplied to ' +
482 + '`testComponent`, expected an object.'
483 + );
484 + });
485
486 - it("should warn for missing required values", function() {
487 - typeCheckFail(
488 - PropTypes.objectOf(PropTypes.number).isRequired,
489 - null,
490 - requiredMessage
491 - );
492 - typeCheckFail(
493 - PropTypes.objectOf(PropTypes.number).isRequired,
494 - undefined,
495 - requiredMessage
496 - );
497 - });
498 -});
486 + it('should not warn when passing an empty object', function() {
487 + typeCheckPass(PropTypes.objectOf(PropTypes.number), {});
488 + });
489
500 -describe('OneOf Types', function() {
501 - it("should warn for invalid strings", function() {
502 - typeCheckFail(
503 - PropTypes.oneOf(['red', 'blue']),
504 - true,
505 - 'Invalid prop `testProp` of value `true` supplied to `testComponent`, ' +
506 - 'expected one of ["red","blue"].'
507 - );
508 - typeCheckFail(
509 - PropTypes.oneOf(['red', 'blue']),
510 - [],
511 - 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
512 - 'expected one of ["red","blue"].'
513 - );
514 - typeCheckFail(
515 - PropTypes.oneOf(['red', 'blue']),
516 - '',
517 - 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
518 - 'expected one of ["red","blue"].'
519 - );
520 - typeCheckFail(
521 - PropTypes.oneOf([0, 'false']),
522 - false,
523 - 'Invalid prop `testProp` of value `false` supplied to `testComponent`, ' +
524 - 'expected one of [0,"false"].'
525 - );
526 - });
490 + it("should be implicitly optional and not warn without values", function() {
491 + typeCheckPass(PropTypes.objectOf(PropTypes.number), null);
492 + typeCheckPass(PropTypes.objectOf(PropTypes.number), undefined);
493 + });
494
528 - it("should not warn for valid values", function() {
529 - typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'red');
530 - typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'blue');
495 + it("should warn for missing required values", function() {
496 + typeCheckFail(
497 + PropTypes.objectOf(PropTypes.number).isRequired,
498 + null,
499 + requiredMessage
500 + );
501 + typeCheckFail(
502 + PropTypes.objectOf(PropTypes.number).isRequired,
503 + undefined,
504 + requiredMessage
505 + );
506 + });
507 });
508
533 - it("should be implicitly optional and not warn without values", function() {
534 - typeCheckPass(PropTypes.oneOf(['red', 'blue']), null);
535 - typeCheckPass(PropTypes.oneOf(['red', 'blue']), undefined);
536 - });
509 + describe('OneOf Types', function() {
510 + it("should warn for invalid strings", function() {
511 + typeCheckFail(
512 + PropTypes.oneOf(['red', 'blue']),
513 + true,
514 + 'Invalid prop `testProp` of value `true` supplied to ' +
515 + '`testComponent`, expected one of ["red","blue"].'
516 + );
517 + typeCheckFail(
518 + PropTypes.oneOf(['red', 'blue']),
519 + [],
520 + 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
521 + 'expected one of ["red","blue"].'
522 + );
523 + typeCheckFail(
524 + PropTypes.oneOf(['red', 'blue']),
525 + '',
526 + 'Invalid prop `testProp` of value `` supplied to `testComponent`, ' +
527 + 'expected one of ["red","blue"].'
528 + );
529 + typeCheckFail(
530 + PropTypes.oneOf([0, 'false']),
531 + false,
532 + 'Invalid prop `testProp` of value `false` supplied to ' +
533 + '`testComponent`, expected one of [0,"false"].'
534 + );
535 + });
536
538 - it("should warn for missing required values", function() {
539 - typeCheckFail(
540 - PropTypes.oneOf(['red', 'blue']).isRequired,
541 - null,
542 - requiredMessage
543 - );
544 - typeCheckFail(
545 - PropTypes.oneOf(['red', 'blue']).isRequired,
546 - undefined,
547 - requiredMessage
548 - );
549 - });
550 -});
537 + it("should not warn for valid values", function() {
538 + typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'red');
539 + typeCheckPass(PropTypes.oneOf(['red', 'blue']), 'blue');
540 + });
541
552 -describe('Union Types', function() {
553 - it('should warn if none of the types are valid', function() {
554 - typeCheckFail(
555 - PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
556 - [],
557 - 'Invalid prop `testProp` supplied to `testComponent`.'
558 - );
542 + it("should be implicitly optional and not warn without values", function() {
543 + typeCheckPass(PropTypes.oneOf(['red', 'blue']), null);
544 + typeCheckPass(PropTypes.oneOf(['red', 'blue']), undefined);
545 + });
546
560 - var checker = PropTypes.oneOfType([
561 - PropTypes.shape({a: PropTypes.number.isRequired}),
562 - PropTypes.shape({b: PropTypes.number.isRequired})
563 - ]);
564 - typeCheckFail(
565 - checker,
566 - {c: 1},
567 - 'Invalid prop `testProp` supplied to `testComponent`.'
568 - );
547 + it("should warn for missing required values", function() {
548 + typeCheckFail(
549 + PropTypes.oneOf(['red', 'blue']).isRequired,
550 + null,
551 + requiredMessage
552 + );
553 + typeCheckFail(
554 + PropTypes.oneOf(['red', 'blue']).isRequired,
555 + undefined,
556 + requiredMessage
557 + );
558 + });
559 });
560
571 - it('should not warn if one of the types are valid', function() {
572 - var checker = PropTypes.oneOfType([
573 - PropTypes.string,
574 - PropTypes.number
575 - ]);
576 - typeCheckPass(checker, null);
577 - typeCheckPass(checker, 'foo');
578 - typeCheckPass(checker, 123);
579 -
580 - checker = PropTypes.oneOfType([
581 - PropTypes.shape({a: PropTypes.number.isRequired}),
582 - PropTypes.shape({b: PropTypes.number.isRequired})
583 - ]);
584 - typeCheckPass(checker, {a: 1});
585 - typeCheckPass(checker, {b: 1});
586 - });
561 + describe('Union Types', function() {
562 + it('should warn if none of the types are valid', function() {
563 + typeCheckFail(
564 + PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
565 + [],
566 + 'Invalid prop `testProp` supplied to `testComponent`.'
567 + );
568
588 - it("should be implicitly optional and not warn without values", function() {
589 - typeCheckPass(
590 - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null
591 - );
592 - typeCheckPass(
593 - PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined
594 - );
595 - });
569 + var checker = PropTypes.oneOfType([
570 + PropTypes.shape({a: PropTypes.number.isRequired}),
571 + PropTypes.shape({b: PropTypes.number.isRequired})
572 + ]);
573 + typeCheckFail(
574 + checker,
575 + {c: 1},
576 + 'Invalid prop `testProp` supplied to `testComponent`.'
577 + );
578 + });
579
597 - it("should warn for missing required values", function() {
598 - typeCheckFail(
599 - PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
600 - null,
601 - requiredMessage
602 - );
603 - typeCheckFail(
604 - PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
605 - undefined,
606 - requiredMessage
607 - );
608 - });
609 -});
580 + it('should not warn if one of the types are valid', function() {
581 + var checker = PropTypes.oneOfType([
582 + PropTypes.string,
583 + PropTypes.number
584 + ]);
585 + typeCheckPass(checker, null);
586 + typeCheckPass(checker, 'foo');
587 + typeCheckPass(checker, 123);
588 +
589 + checker = PropTypes.oneOfType([
590 + PropTypes.shape({a: PropTypes.number.isRequired}),
591 + PropTypes.shape({b: PropTypes.number.isRequired})
592 + ]);
593 + typeCheckPass(checker, {a: 1});
594 + typeCheckPass(checker, {b: 1});
595 + });
596
611 -describe('Shape Types', function() {
612 - it("should warn for non objects", function() {
613 - typeCheckFail(
614 - PropTypes.shape({}),
615 - 'some string',
616 - 'Invalid prop `testProp` of type `string` supplied to `testComponent`, ' +
617 - 'expected `object`.'
618 - );
619 - typeCheckFail(
620 - PropTypes.shape({}),
621 - ['array'],
622 - 'Invalid prop `testProp` of type `array` supplied to `testComponent`, ' +
623 - 'expected `object`.'
624 - );
625 - });
597 + it("should be implicitly optional and not warn without values", function() {
598 + typeCheckPass(
599 + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), null
600 + );
601 + typeCheckPass(
602 + PropTypes.oneOfType([PropTypes.string, PropTypes.number]), undefined
603 + );
604 + });
605
627 - it("should not warn for empty values", function() {
628 - typeCheckPass(PropTypes.shape({}), undefined);
629 - typeCheckPass(PropTypes.shape({}), null);
630 - typeCheckPass(PropTypes.shape({}), {});
606 + it("should warn for missing required values", function() {
607 + typeCheckFail(
608 + PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
609 + null,
610 + requiredMessage
611 + );
612 + typeCheckFail(
613 + PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
614 + undefined,
615 + requiredMessage
616 + );
617 + });
618 });
619
633 - it("should not warn for an empty object", function() {
634 - typeCheckPass(PropTypes.shape({}).isRequired, {});
635 - });
620 + describe('Shape Types', function() {
621 + it("should warn for non objects", function() {
622 + typeCheckFail(
623 + PropTypes.shape({}),
624 + 'some string',
625 + 'Invalid prop `testProp` of type `string` supplied to ' +
626 + '`testComponent`, expected `object`.'
627 + );
628 + typeCheckFail(
629 + PropTypes.shape({}),
630 + ['array'],
631 + 'Invalid prop `testProp` of type `array` supplied to ' +
632 + '`testComponent`, expected `object`.'
633 + );
634 + });
635
637 - it("should not warn for non specified types", function() {
638 - typeCheckPass(PropTypes.shape({}), {key: 1});
639 - });
636 + it("should not warn for empty values", function() {
637 + typeCheckPass(PropTypes.shape({}), undefined);
638 + typeCheckPass(PropTypes.shape({}), null);
639 + typeCheckPass(PropTypes.shape({}), {});
640 + });
641
641 - it("should not warn for valid types", function() {
642 - typeCheckPass(PropTypes.shape({key: PropTypes.number}), {key: 1});
643 - });
642 + it("should not warn for an empty object", function() {
643 + typeCheckPass(PropTypes.shape({}).isRequired, {});
644 + });
645
645 - it("should warn for required valid types", function() {
646 - typeCheckFail(
647 - PropTypes.shape({key: PropTypes.number.isRequired}),
648 - {},
649 - 'Required prop `key` was not specified in `testComponent`.'
650 - );
651 - });
646 + it("should not warn for non specified types", function() {
647 + typeCheckPass(PropTypes.shape({}), {key: 1});
648 + });
649
653 - it("should warn for the first required type", function() {
654 - typeCheckFail(
655 - PropTypes.shape({
656 - key: PropTypes.number.isRequired,
657 - secondKey: PropTypes.number.isRequired
658 - }),
659 - {},
660 - 'Required prop `key` was not specified in `testComponent`.'
661 - );
662 - });
650 + it("should not warn for valid types", function() {
651 + typeCheckPass(PropTypes.shape({key: PropTypes.number}), {key: 1});
652 + });
653
664 - it("should warn for invalid key types", function() {
665 - typeCheckFail(PropTypes.shape({key: PropTypes.number}),
666 - {key: 'abc'},
667 - 'Invalid prop `key` of type `string` supplied to `testComponent`, ' +
668 - 'expected `number`.'
669 - );
670 - });
654 + it("should warn for required valid types", function() {
655 + typeCheckFail(
656 + PropTypes.shape({key: PropTypes.number.isRequired}),
657 + {},
658 + 'Required prop `key` was not specified in `testComponent`.'
659 + );
660 + });
661
672 - it("should be implicitly optional and not warn without values", function() {
673 - typeCheckPass(
674 - PropTypes.shape(PropTypes.shape({key: PropTypes.number})), null
675 - );
676 - typeCheckPass(
677 - PropTypes.shape(PropTypes.shape({key: PropTypes.number})), undefined
678 - );
679 - });
662 + it("should warn for the first required type", function() {
663 + typeCheckFail(
664 + PropTypes.shape({
665 + key: PropTypes.number.isRequired,
666 + secondKey: PropTypes.number.isRequired
667 + }),
668 + {},
669 + 'Required prop `key` was not specified in `testComponent`.'
670 + );
671 + });
672
681 - it("should warn for missing required values", function() {
682 - typeCheckFail(
683 - PropTypes.shape({key: PropTypes.number}).isRequired,
684 - null,
685 - requiredMessage
686 - );
687 - typeCheckFail(
688 - PropTypes.shape({key: PropTypes.number}).isRequired,
689 - undefined,
690 - requiredMessage
691 - );
692 - });
693 -});
673 + it("should warn for invalid key types", function() {
674 + typeCheckFail(PropTypes.shape({key: PropTypes.number}),
675 + {key: 'abc'},
676 + 'Invalid prop `key` of type `string` supplied to `testComponent`, ' +
677 + 'expected `number`.'
678 + );
679 + });
680
695 -describe('Custom validator', function() {
696 - beforeEach(function() {
697 - require('mock-modules').dumpCache();
698 - ReactTestUtils = require('ReactTestUtils');
699 - spyOn(console, 'warn');
700 - });
681 + it("should be implicitly optional and not warn without values", function() {
682 + typeCheckPass(
683 + PropTypes.shape(PropTypes.shape({key: PropTypes.number})), null
684 + );
685 + typeCheckPass(
686 + PropTypes.shape(PropTypes.shape({key: PropTypes.number})), undefined
687 + );
688 + });
689
702 - it('should have been called with the right params', function() {
703 - var spy = jasmine.createSpy();
704 - var Component = React.createClass({
705 - propTypes: {num: spy},
690 + it("should warn for missing required values", function() {
691 + typeCheckFail(
692 + PropTypes.shape({key: PropTypes.number}).isRequired,
693 + null,
694 + requiredMessage
695 + );
696 + typeCheckFail(
697 + PropTypes.shape({key: PropTypes.number}).isRequired,
698 + undefined,
699 + requiredMessage
700 + );
701 + });
702 + });
703
707 - render: function() {
708 - return <div />;
709 - }
704 + describe('Custom validator', function() {
705 + beforeEach(function() {
706 + require('mock-modules').dumpCache();
707 + spyOn(console, 'warn');
708 });
709
712 - var instance = <Component num={5} />;
713 - instance = ReactTestUtils.renderIntoDocument(instance);
710 + it('should have been called with the right params', function() {
711 + var spy = jasmine.createSpy();
712 + var Component = React.createClass({
713 + propTypes: {num: spy},
714
715 - expect(spy.argsForCall.length).toBe(2); // temp double validation
716 - expect(spy.argsForCall[0][1]).toBe('num');
717 - expect(spy.argsForCall[0][2]).toBe('Component');
718 - });
715 + render: function() {
716 + return <div />;
717 + }
718 + });
719
720 - it('should have been called even if the prop is not present', function() {
721 - var spy = jasmine.createSpy();
722 - var Component = React.createClass({
723 - propTypes: {num: spy},
720 + var instance = <Component num={5} />;
721 + instance = ReactTestUtils.renderIntoDocument(instance);
722
725 - render: function() {
726 - return <div />;
727 - }
723 + expect(spy.argsForCall.length).toBe(2); // temp double validation
724 + expect(spy.argsForCall[0][1]).toBe('num');
725 + expect(spy.argsForCall[0][2]).toBe('Component');
726 });
727
730 - var instance = <Component bla={5} />;
731 - instance = ReactTestUtils.renderIntoDocument(instance);
732 -
733 - expect(spy.argsForCall.length).toBe(2); // temp double validation
734 - });
728 + it('should have been called even if the prop is not present', function() {
729 + var spy = jasmine.createSpy();
730 + var Component = React.createClass({
731 + propTypes: {num: spy},
732
736 - it('should have received the validator\'s return value', function() {
737 - var spy = jasmine.createSpy().andCallFake(
738 - function(props, propName, componentName) {
739 - if (props[propName] !== 5) {
740 - return new Error('num must be 5!');
733 + render: function() {
734 + return <div />;
735 }
742 - }
743 - );
744 - var Component = React.createClass({
745 - propTypes: {num: spy},
736 + });
737
747 - render: function() {
748 - return <div />;
749 - }
750 - });
738 + var instance = <Component bla={5} />;
739 + instance = ReactTestUtils.renderIntoDocument(instance);
740
752 - var instance = <Component num={6} />;
753 - instance = ReactTestUtils.renderIntoDocument(instance);
754 - expect(console.warn.argsForCall.length).toBe(1);
755 - expect(console.warn.argsForCall[0][0]).toBe('Warning: num must be 5!');
756 - });
741 + expect(spy.argsForCall.length).toBe(2); // temp double validation
742 + });
743
758 - it('should not warn if the validator returned anything else than an error',
759 - function() {
744 + it('should have received the validator\'s return value', function() {
745 var spy = jasmine.createSpy().andCallFake(
746 function(props, propName, componentName) {
762 - return 'This message will never reach anyone';
747 + if (props[propName] !== 5) {
748 + return new Error('num must be 5!');
749 + }
750 }
751 );
752 var Component = React.createClass({
@@ -770,9 +757,31 @@ describe('Custom validator', function() {
757 }
758 });
759
773 - var instance = <Component num={5} />;
760 + var instance = <Component num={6} />;
761 instance = ReactTestUtils.renderIntoDocument(instance);
775 - expect(console.warn.argsForCall.length).toBe(0);
776 - }
777 - );
762 + expect(console.warn.argsForCall.length).toBe(1);
763 + expect(console.warn.argsForCall[0][0]).toBe('Warning: num must be 5!');
764 + });
765 +
766 + it('should not warn if the validator returned anything else than an error',
767 + function() {
768 + var spy = jasmine.createSpy().andCallFake(
769 + function(props, propName, componentName) {
770 + return 'This message will never reach anyone';
771 + }
772 + );
773 + var Component = React.createClass({
774 + propTypes: {num: spy},
775 +
776 + render: function() {
777 + return <div />;
778 + }
779 + });
780 +
781 + var instance = <Component num={5} />;
782 + instance = ReactTestUtils.renderIntoDocument(instance);
783 + expect(console.warn.argsForCall.length).toBe(0);
784 + }
785 + );
786 + });
787 });