Skip to content

Commit

Permalink
Fix bug with toTree on rendered array facebook#10616
Browse files Browse the repository at this point in the history
  • Loading branch information
Clement Hoang committed Sep 8, 2017
1 parent 8b7082e commit 442c409
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 53 deletions.
15 changes: 10 additions & 5 deletions src/renderers/testing/ReactTestRendererFiberEntry.js
Expand Up @@ -285,14 +285,19 @@ function toJSON(inst: Instance | TextInstance): ReactTestRendererNode {
}
}

function nodeAndSiblingsArray(nodeWithSibling: ?Fiber) {
function nodeAndSiblingsTrees(nodeWithSibling: ?Fiber) {
var array = [];
var node = nodeWithSibling;
while (node != null) {
array.push(node);
node = node.sibling;
}
return array;
const trees = array.map(toTree);
return trees.length ? trees : null;
}

function isChildrenArray(node: Fiber) {
return node.child && node.child.sibling;
}

function toTree(node: ?Fiber) {
Expand All @@ -308,23 +313,23 @@ function toTree(node: ?Fiber) {
type: node.type,
props: {...node.memoizedProps},
instance: node.stateNode,
rendered: toTree(node.child),
rendered: nodeAndSiblingsTrees(node.child),
};
case FunctionalComponent: // 1
return {
nodeType: 'component',
type: node.type,
props: {...node.memoizedProps},
instance: null,
rendered: toTree(node.child),
rendered: nodeAndSiblingsTrees(node.child),
};
case HostComponent: // 5
return {
nodeType: 'host',
type: node.type,
props: {...node.memoizedProps},
instance: null, // TODO: use createNodeMock here somehow?
rendered: nodeAndSiblingsArray(node.child).map(toTree),
rendered: nodeAndSiblingsTrees(node.child),
};
case HostText: // 6
return node.stateNode.text;
Expand Down
230 changes: 182 additions & 48 deletions src/renderers/testing/__tests__/ReactTestRenderer-test.js
Expand Up @@ -19,10 +19,14 @@ var prettyFormat = require('pretty-format');
// with jasmine's deep equality function, and test the instances separate. We
// also delete children props because testing them is more annoying and not
// really important to verify.
function cleanNode(node) {
function cleanNodeOrArray(node) {
if (!node) {
return;
}
if (Array.isArray(node)) {
node.forEach(cleanNodeOrArray);
return;
}
if (node && node.instance) {
node.instance = null;
}
Expand All @@ -32,9 +36,9 @@ function cleanNode(node) {
node.props = props;
}
if (Array.isArray(node.rendered)) {
node.rendered.forEach(cleanNode);
node.rendered.forEach(cleanNodeOrArray);
} else if (typeof node.rendered === 'object') {
cleanNode(node.rendered);
cleanNodeOrArray(node.rendered);
}
}

Expand Down Expand Up @@ -507,21 +511,23 @@ describe('ReactTestRenderer', () => {
var renderer = ReactTestRenderer.create(<Qoo />);
var tree = renderer.toTree();

cleanNode(tree);
cleanNodeOrArray(tree);

expect(prettyFormat(tree)).toEqual(
prettyFormat({
nodeType: 'component',
type: Qoo,
props: {},
instance: null,
rendered: {
nodeType: 'host',
type: 'span',
props: {className: 'Qoo'},
instance: null,
rendered: ['Hello World!'],
},
rendered: [
{
nodeType: 'host',
type: 'span',
props: {className: 'Qoo'},
instance: null,
rendered: ['Hello World!'],
},
],
}),
);
});
Expand All @@ -538,7 +544,7 @@ describe('ReactTestRenderer', () => {

expect(tree.instance).toBeInstanceOf(Foo);

cleanNode(tree);
cleanNodeOrArray(tree);

expect(tree).toEqual({
type: Foo,
Expand All @@ -549,6 +555,126 @@ describe('ReactTestRenderer', () => {
});
});

it('toTree() handles simple components that return arrays', () => {
const Foo = ({children}) => children;

const renderer = ReactTestRenderer.create(
<Foo>
<div>One</div>
<div>Two</div>
</Foo>,
);

var tree = renderer.toTree();

cleanNodeOrArray(tree);

expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: Foo,
nodeType: 'component',
props: {},
instance: null,
rendered: [
{
instance: null,
nodeType: 'host',
props: {},
rendered: ['One'],
type: 'div',
},
{
instance: null,
nodeType: 'host',
props: {},
rendered: ['Two'],
type: 'div',
},
],
}),
);
});

it('toTree() handles complicated tree of fragments', () => {
class Foo extends React.Component {
render() {
return this.props.children;
}
}

const renderer = ReactTestRenderer.create(
<div>
<Foo>
<div>One</div>
<div>Two</div>
<Foo>
<div>Three</div>
</Foo>
</Foo>
<div>Four</div>
</div>,
);

var tree = renderer.toTree();

cleanNodeOrArray(tree);

expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: 'div',
instance: null,
nodeType: 'host',
props: {},
rendered: [
{
type: Foo,
nodeType: 'component',
props: {},
instance: null,
rendered: [
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['One'],
},
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Two'],
},
{
type: Foo,
nodeType: 'component',
props: {},
instance: null,
rendered: [
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Three'],
},
],
},
],
},
{
type: 'div',
nodeType: 'host',
props: {},
instance: null,
rendered: ['Four'],
},
],
}),
);
});

it('root instance and createNodeMock ref return the same value', () => {
var createNodeMock = ref => ({node: ref});
var refInst = null;
Expand Down Expand Up @@ -600,56 +726,64 @@ describe('ReactTestRenderer', () => {

// we test for the presence of instances before nulling them out
expect(tree.instance).toBeInstanceOf(Bam);
expect(tree.rendered.instance).toBeInstanceOf(Bar);
expect(tree.rendered[0].instance).toBeInstanceOf(Bar);

cleanNode(tree);
cleanNodeOrArray(tree);

expect(prettyFormat(tree)).toEqual(
prettyFormat({
type: Bam,
nodeType: 'component',
props: {},
instance: null,
rendered: {
type: Bar,
nodeType: 'component',
props: {special: true},
instance: null,
rendered: {
type: Foo,
rendered: [
{
type: Bar,
nodeType: 'component',
props: {className: 'special'},
props: {special: true},
instance: null,
rendered: {
type: 'div',
nodeType: 'host',
props: {className: 'Foo special'},
instance: null,
rendered: [
{
type: 'span',
nodeType: 'host',
props: {className: 'Foo2'},
instance: null,
rendered: ['Literal'],
},
{
type: Qoo,
nodeType: 'component',
props: {},
instance: null,
rendered: {
type: 'span',
rendered: [
{
type: Foo,
nodeType: 'component',
props: {className: 'special'},
instance: null,
rendered: [
{
type: 'div',
nodeType: 'host',
props: {className: 'Qoo'},
props: {className: 'Foo special'},
instance: null,
rendered: ['Hello World!'],
rendered: [
{
type: 'span',
nodeType: 'host',
props: {className: 'Foo2'},
instance: null,
rendered: ['Literal'],
},
{
type: Qoo,
nodeType: 'component',
props: {},
instance: null,
rendered: [
{
type: 'span',
nodeType: 'host',
props: {className: 'Qoo'},
instance: null,
rendered: ['Hello World!'],
},
],
},
],
},
},
],
},
],
},
],
},
},
],
}),
);
});
Expand Down

0 comments on commit 442c409

Please sign in to comment.