Skip to content

Commit

Permalink
Improve validateDOMNesting message for whitespace
Browse files Browse the repository at this point in the history
For #5071.
  • Loading branch information
sophiebits committed Aug 17, 2016
1 parent 921d8c1 commit d60089c
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 10 deletions.
30 changes: 27 additions & 3 deletions src/renderers/dom/client/validateDOMNesting.js
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,24 @@ if (__DEV__) {

var didWarn = {};

validateDOMNesting = function(childTag, childInstance, ancestorInfo) {
validateDOMNesting = function(
childTag,
childText,
childInstance,
ancestorInfo
) {
ancestorInfo = ancestorInfo || emptyAncestorInfo;
var parentInfo = ancestorInfo.current;
var parentTag = parentInfo && parentInfo.tag;

if (childText != null) {
warning(
childTag == null,
'validateDOMNesting: when childText is passed, childTag should be null'
);
childTag = '#text';
}

var invalidParent =
isTagValidWithParent(childTag, parentTag) ? null : parentInfo;
var invalidAncestor =
Expand Down Expand Up @@ -385,7 +398,17 @@ if (__DEV__) {
didWarn[warnKey] = true;

var tagDisplayName = childTag;
if (childTag !== '#text') {
var whitespaceInfo = '';
if (childTag === '#text') {
if (/\S/.test(childText)) {
tagDisplayName = 'Text nodes';
} else {
tagDisplayName = 'Whitespace text nodes';
whitespaceInfo =
' Make sure you don\'t have any extra whitespace between tags on ' +
'each line of your source code.';
}
} else {
tagDisplayName = '<' + childTag + '>';
}

Expand All @@ -398,10 +421,11 @@ if (__DEV__) {
}
warning(
false,
'validateDOMNesting(...): %s cannot appear as a child of <%s>. ' +
'validateDOMNesting(...): %s cannot appear as a child of <%s>.%s ' +
'See %s.%s',
tagDisplayName,
ancestorTag,
whitespaceInfo,
ownerInfo,
info
);
Expand Down
3 changes: 2 additions & 1 deletion src/renderers/dom/shared/ReactDOMComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ if (__DEV__) {
return;
}

validateDOMNesting(null, String(content), this, this._ancestorInfo);
this._contentDebugID = contentDebugID;
if (hasExistingContent) {
ReactInstrumentation.debugTool.onBeforeUpdateComponent(contentDebugID, content);
Expand Down Expand Up @@ -605,7 +606,7 @@ ReactDOMComponent.Mixin = {
if (parentInfo) {
// parentInfo should always be present except for the top-level
// component when server rendering
validateDOMNesting(this._tag, this, parentInfo);
validateDOMNesting(this._tag, null, this, parentInfo);
}
this._ancestorInfo =
validateDOMNesting.updatedAncestorInfo(parentInfo, this._tag, this);
Expand Down
2 changes: 1 addition & 1 deletion src/renderers/dom/shared/ReactDOMTextComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ Object.assign(ReactDOMTextComponent.prototype, {
if (parentInfo) {
// parentInfo should always be present except for the top-level
// component when server rendering
validateDOMNesting('#text', this, parentInfo);
validateDOMNesting(null, this._stringText, this, parentInfo);
}
}

Expand Down
16 changes: 11 additions & 5 deletions src/renderers/dom/shared/__tests__/ReactDOMComponent-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,7 @@ describe('ReactDOMComponent', function() {
});

it('should work error event on <source> element', function() {
spyOn(console, 'error');
spyOn(console, 'error');
var container = document.createElement('div');
ReactDOM.render(
<video>
Expand Down Expand Up @@ -1225,7 +1225,7 @@ describe('ReactDOMComponent', function() {

class Row extends React.Component {
render() {
return <tr />;
return <tr>x</tr>;
}
}

Expand All @@ -1237,15 +1237,21 @@ describe('ReactDOMComponent', function() {

ReactTestUtils.renderIntoDocument(<Foo />);

expect(console.error.calls.count()).toBe(2);
expect(console.error.calls.count()).toBe(3);
expect(console.error.calls.argsFor(0)[0]).toBe(
'Warning: validateDOMNesting(...): <tr> cannot appear as a child of ' +
'<table>. See Foo > table > Row > tr. Add a <tbody> to your code to ' +
'match the DOM tree generated by the browser.'
);
expect(console.error.calls.argsFor(1)[0]).toBe(
'Warning: validateDOMNesting(...): #text cannot appear as a child ' +
'of <table>. See Foo > table > #text.'
'Warning: validateDOMNesting(...): Text nodes cannot appear as a ' +
'child of <tr>. See Row > tr > #text.'
);
expect(console.error.calls.argsFor(2)[0]).toBe(
'Warning: validateDOMNesting(...): Whitespace text nodes cannot ' +
'appear as a child of <table>. Make sure you don\'t have any extra ' +
'whitespace between tags on each line of your source code. See Foo > ' +
'table > #text.'
);
});

Expand Down

0 comments on commit d60089c

Please sign in to comment.