@samitouri / QOS-React-2 / commits / 642323e5a8

Improve error message when mounting non-string/function elements

Ben Alpert committed Jun 17, 2015 at 00:16 UTC 642323e5a8ad814e372b67bd76ded2d6d5bd383d
3 files changed +52 -12
src/isomorphic/classic/element/__tests__/ReactElementValidator-test.js
+6 -5
@@ -327,17 +327,18 @@ describe('ReactElementValidator', function() {
327 });
328 expect(function() {
329 ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
330 - }).toThrow();
331 - expect(console.error.calls.length).toBe(2);
330 + }).toThrow(
331 + 'Invariant Violation: Element type is invalid: expected a string (for ' +
332 + 'built-in components) or a class/function (for composite components) ' +
333 + 'but got: null. Check the render method of `ParentComp`.'
334 + );
335 + expect(console.error.calls.length).toBe(1);
336 expect(console.error.calls[0].args[0]).toBe(
337 'Warning: React.createElement: type should not be null, undefined, ' +
338 'boolean, or number. It should be a string (for DOM elements) or a ' +
339 'ReactClass (for composite components). Check the render method of ' +
340 '`ParentComp`.'
341 );
338 - expect(console.error.calls[1].args[0]).toBe(
339 - 'Warning: Only functions or strings can be mounted as React components.'
340 - );
342 });
343
344 it('should check default prop values', function() {
src/renderers/shared/reconciler/__tests__/ReactComponent-test.js
+28
@@ -279,4 +279,32 @@ describe('ReactComponent', function() {
279 );
280 });
281
282 + it('throws usefully when rendering badly-typed elements', function() {
283 + spyOn(console, 'error');
284 +
285 + var X = undefined;
286 + expect(() => ReactTestUtils.renderIntoDocument(<X />)).toThrow(
287 + 'Invariant Violation: Element type is invalid: expected a string (for ' +
288 + 'built-in components) or a class/function (for composite components) ' +
289 + 'but got: undefined.'
290 + );
291 +
292 + var Y = null;
293 + expect(() => ReactTestUtils.renderIntoDocument(<Y />)).toThrow(
294 + 'Invariant Violation: Element type is invalid: expected a string (for ' +
295 + 'built-in components) or a class/function (for composite components) ' +
296 + 'but got: null.'
297 + );
298 +
299 + var Z = {};
300 + expect(() => ReactTestUtils.renderIntoDocument(<Z />)).toThrow(
301 + 'Invariant Violation: Element type is invalid: expected a string (for ' +
302 + 'built-in components) or a class/function (for composite components) ' +
303 + 'but got: object.'
304 + );
305 +
306 + // One warning for each element creation
307 + expect(console.error.calls.length).toBe(3);
308 + });
309 +
310 });
src/renderers/shared/reconciler/instantiateReactComponent.js
+18 -7
@@ -30,6 +30,16 @@ assign(
30 }
31 );
32
33 +function getDeclarationErrorAddendum(owner) {
34 + if (owner) {
35 + var name = owner.getName();
36 + if (name) {
37 + return ' Check the render method of `' + name + '`.';
38 + }
39 + }
40 + return '';
41 +}
42 +
43 /**
44 * Check if the type reference is a known internal type. I.e. not a user
45 * provided composite type.
@@ -63,13 +73,14 @@ function instantiateReactComponent(node, parentCompositeType) {
73
74 if (typeof node === 'object') {
75 var element = node;
66 - if (__DEV__) {
67 - warning(
68 - element && (typeof element.type === 'function' ||
69 - typeof element.type === 'string'),
70 - 'Only functions or strings can be mounted as React components.'
71 - );
72 - }
76 + invariant(
77 + element && (typeof element.type === 'function' ||
78 + typeof element.type === 'string'),
79 + 'Element type is invalid: expected a string (for built-in components) ' +
80 + 'or a class/function (for composite components) but got: %s.%s',
81 + element.type == null ? element.type : typeof element.type,
82 + getDeclarationErrorAddendum(element._owner)
83 + );
84
85 // Special case string values
86 if (parentCompositeType === element.type &&