Skip to content

Commit

Permalink
Merge pull request facebook#4154 from spicyj/facebookgh-3478
Browse files Browse the repository at this point in the history
Improve error message when mounting non-string/function elements
  • Loading branch information
sophiebits committed Jun 17, 2015
2 parents a841b4f + 642323e commit 0160212
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -327,17 +327,18 @@ describe('ReactElementValidator', function() {
});
expect(function() {
ReactTestUtils.renderIntoDocument(React.createElement(ParentComp));
}).toThrow();
expect(console.error.calls.length).toBe(2);
}).toThrow(
'Invariant Violation: Element type is invalid: expected a string (for ' +
'built-in components) or a class/function (for composite components) ' +
'but got: null. Check the render method of `ParentComp`.'
);
expect(console.error.calls.length).toBe(1);
expect(console.error.calls[0].args[0]).toBe(
'Warning: React.createElement: type should not be null, undefined, ' +
'boolean, or number. It should be a string (for DOM elements) or a ' +
'ReactClass (for composite components). Check the render method of ' +
'`ParentComp`.'
);
expect(console.error.calls[1].args[0]).toBe(
'Warning: Only functions or strings can be mounted as React components.'
);
});

it('should check default prop values', function() {
Expand Down
28 changes: 28 additions & 0 deletions src/renderers/shared/reconciler/__tests__/ReactComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,32 @@ describe('ReactComponent', function() {
);
});

it('throws usefully when rendering badly-typed elements', function() {
spyOn(console, 'error');

var X = undefined;
expect(() => ReactTestUtils.renderIntoDocument(<X />)).toThrow(
'Invariant Violation: Element type is invalid: expected a string (for ' +
'built-in components) or a class/function (for composite components) ' +
'but got: undefined.'
);

var Y = null;
expect(() => ReactTestUtils.renderIntoDocument(<Y />)).toThrow(
'Invariant Violation: Element type is invalid: expected a string (for ' +
'built-in components) or a class/function (for composite components) ' +
'but got: null.'
);

var Z = {};
expect(() => ReactTestUtils.renderIntoDocument(<Z />)).toThrow(
'Invariant Violation: Element type is invalid: expected a string (for ' +
'built-in components) or a class/function (for composite components) ' +
'but got: object.'
);

// One warning for each element creation
expect(console.error.calls.length).toBe(3);
});

});
25 changes: 18 additions & 7 deletions src/renderers/shared/reconciler/instantiateReactComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ assign(
}
);

function getDeclarationErrorAddendum(owner) {
if (owner) {
var name = owner.getName();
if (name) {
return ' Check the render method of `' + name + '`.';
}
}
return '';
}

/**
* Check if the type reference is a known internal type. I.e. not a user
* provided composite type.
Expand Down Expand Up @@ -63,13 +73,14 @@ function instantiateReactComponent(node, parentCompositeType) {

if (typeof node === 'object') {
var element = node;
if (__DEV__) {
warning(
element && (typeof element.type === 'function' ||
typeof element.type === 'string'),
'Only functions or strings can be mounted as React components.'
);
}
invariant(
element && (typeof element.type === 'function' ||
typeof element.type === 'string'),
'Element type is invalid: expected a string (for built-in components) ' +
'or a class/function (for composite components) but got: %s.%s',
element.type == null ? element.type : typeof element.type,
getDeclarationErrorAddendum(element._owner)
);

// Special case string values
if (parentCompositeType === element.type &&
Expand Down

0 comments on commit 0160212

Please sign in to comment.