Improve error message when mounting non-string/function elements

This commit is contained in:
Ben Alpert
2015-06-17 00:16:22 -07:00
parent c265504fe2
commit 642323e5a8
3 changed files with 52 additions and 12 deletions
@@ -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() {
@@ -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);
});
});
@@ -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.
@@ -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 &&