Adjacent text nodes in SSR should have comments between them despite components (#11109)

* Add a failing test for text nodes within components

* Reset the text node flag only when emitting tags

This ensures we don't reset it when we exit components that return strings.

* Add a failing test for a more complex tree

* Also reset text flag when emitting a footer

This fixes the {'a'}</div>{'b'} case and prevents an unnecessary comment before 'b'.
This commit is contained in:
Dan Abramov
2017-10-05 20:05:00 +01:00
committed by GitHub
parent 7d3b44bf37
commit 32ec797274
2 changed files with 79 additions and 2 deletions
@@ -1117,6 +1117,79 @@ describe('ReactDOMServerIntegration', () => {
expectTextNode(e.childNodes[1], 'bar');
}
});
itRenders(
'a component returning text node between two text nodes',
async render => {
const B = () => 'b';
const e = await render(<div>{'a'}<B />{'c'}</div>);
if (
render === serverRender ||
render === clientRenderOnServerString ||
render === streamRender
) {
// In the server render output there's a comment between them.
expect(e.childNodes.length).toBe(5);
expectTextNode(e.childNodes[0], 'a');
expectTextNode(e.childNodes[2], 'b');
expectTextNode(e.childNodes[4], 'c');
} else {
expect(e.childNodes.length).toBe(3);
expectTextNode(e.childNodes[0], 'a');
expectTextNode(e.childNodes[1], 'b');
expectTextNode(e.childNodes[2], 'c');
}
},
);
itRenders('a tree with sibling host and text nodes', async render => {
class X extends React.Component {
render() {
return [null, [<Y key="1" />], false];
}
}
function Y() {
return [<Z key="1" />, ['c']];
}
function Z() {
return null;
}
const e = await render(
<div>
{[['a'], 'b']}
<div>
<X key="1" />
d
</div>
e
</div>,
);
if (
render === serverRender ||
render === clientRenderOnServerString ||
render === streamRender
) {
// In the server render output there's comments between text nodes.
expect(e.childNodes.length).toBe(5);
expectTextNode(e.childNodes[0], 'a');
expectTextNode(e.childNodes[2], 'b');
expect(e.childNodes[3].childNodes.length).toBe(3);
expectTextNode(e.childNodes[3].childNodes[0], 'c');
expectTextNode(e.childNodes[3].childNodes[2], 'd');
expectTextNode(e.childNodes[4], 'e');
} else {
expect(e.childNodes.length).toBe(4);
expectTextNode(e.childNodes[0], 'a');
expectTextNode(e.childNodes[1], 'b');
expect(e.childNodes[2].childNodes.length).toBe(2);
expectTextNode(e.childNodes[2].childNodes[0], 'c');
expectTextNode(e.childNodes[2].childNodes[1], 'd');
expectTextNode(e.childNodes[3], 'e');
}
});
});
describe('number children', function() {
@@ -475,8 +475,11 @@ class ReactDOMServerRenderer {
}
var frame = this.stack[this.stack.length - 1];
if (frame.childIndex >= frame.children.length) {
out += frame.footer;
this.previousWasTextNode = false;
var footer = frame.footer;
out += footer;
if (footer !== '') {
this.previousWasTextNode = false;
}
this.stack.pop();
if (frame.tag === 'select') {
this.currentSelectValue = null;
@@ -827,6 +830,7 @@ class ReactDOMServerRenderer {
frame.debugElementStack = [];
}
this.stack.push(frame);
this.previousWasTextNode = false;
return out;
}
}