/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
*/
'use strict';
const React = require('react');
const ReactDOM = require('react-dom');
const ReactTestUtils = require('react-dom/test-utils');
// Helpers
const testAllPermutations = function(testCases) {
for (let i = 0; i < testCases.length; i += 2) {
const renderWithChildren = testCases[i];
const expectedResultAfterRender = testCases[i + 1];
for (let j = 0; j < testCases.length; j += 2) {
const updateWithChildren = testCases[j];
const expectedResultAfterUpdate = testCases[j + 1];
const container = document.createElement('div');
ReactDOM.render(
{renderWithChildren}
, container);
expectChildren(container, expectedResultAfterRender);
ReactDOM.render({updateWithChildren}
, container);
expectChildren(container, expectedResultAfterUpdate);
}
}
};
const expectChildren = function(container, children) {
const outerNode = container.firstChild;
let textNode;
if (typeof children === 'string') {
textNode = outerNode.firstChild;
if (children === '') {
expect(textNode != null).toBe(false);
} else {
expect(textNode != null).toBe(true);
expect(textNode.nodeType).toBe(3);
expect(textNode.data).toBe('' + children);
}
} else {
let mountIndex = 0;
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (typeof child === 'string') {
textNode = outerNode.childNodes[mountIndex];
expect(textNode.nodeType).toBe(3);
expect(textNode.data).toBe('' + child);
mountIndex++;
} else {
const elementDOMNode = outerNode.childNodes[mountIndex];
expect(elementDOMNode.tagName).toBe('DIV');
mountIndex++;
}
}
}
};
/**
* ReactMultiChild DOM integration test. In ReactDOM components, we make sure
* that single children that are strings are treated as "content" which is much
* faster to render and update.
*/
describe('ReactMultiChildText', () => {
it('should correctly handle all possible children for render and update', () => {
expect(() => {
// prettier-ignore
testAllPermutations([
// basic values
undefined, [],
null, [],
false, [],
true, [],
0, '0',
1.2, '1.2',
'', '',
'foo', 'foo',
[], [],
[undefined], [],
[null], [],
[false], [],
[true], [],
[0], ['0'],
[1.2], ['1.2'],
[''], [''],
['foo'], ['foo'],
[], [],
// two adjacent values
[true, 0], ['0'],
[0, 0], ['0', '0'],
[1.2, 0], ['1.2', '0'],
[0, ''], ['0', ''],
['foo', 0], ['foo', '0'],
[0, ], ['0', ],
[true, 1.2], ['1.2'],
[1.2, 0], ['1.2', '0'],
[1.2, 1.2], ['1.2', '1.2'],
[1.2, ''], ['1.2', ''],
['foo', 1.2], ['foo', '1.2'],
[1.2, ], ['1.2', ],
[true, ''], [''],
['', 0], ['', '0'],
[1.2, ''], ['1.2', ''],
['', ''], ['', ''],
['foo', ''], ['foo', ''],
['', ], ['', ],
[true, 'foo'], ['foo'],
['foo', 0], ['foo', '0'],
[1.2, 'foo'], ['1.2', 'foo'],
['foo', ''], ['foo', ''],
['foo', 'foo'], ['foo', 'foo'],
['foo', ], ['foo', ],
// values separated by an element
[true, , true], [],
[1.2, , 1.2], ['1.2', , '1.2'],
['', , ''], ['', , ''],
['foo', , 'foo'], ['foo', , 'foo'],
[true, 1.2, , '', 'foo'], ['1.2', , '', 'foo'],
[1.2, '', , 'foo', true], ['1.2', '', , 'foo'],
['', 'foo', , true, 1.2], ['', 'foo', , '1.2'],
[true, 1.2, '', , 'foo', true, 1.2], ['1.2', '', , 'foo', '1.2'],
['', 'foo', true, , 1.2, '', 'foo'], ['', 'foo', , '1.2', '', 'foo'],
// values inside arrays
[[true], [true]], [],
[[1.2], [1.2]], ['1.2', '1.2'],
[[''], ['']], ['', ''],
[['foo'], ['foo']], ['foo', 'foo'],
[[], []], [, ],
[[true, 1.2, ], '', 'foo'], ['1.2', , '', 'foo'],
[1.2, '', [, 'foo', true]], ['1.2', '', , 'foo'],
['', ['foo', , true], 1.2], ['', 'foo', , '1.2'],
[true, [1.2, '', , 'foo'], true, 1.2], ['1.2', '', , 'foo', '1.2'],
['', 'foo', [true, , 1.2, ''], 'foo'], ['', 'foo', , '1.2', '', 'foo'],
// values inside elements
[, '', 'foo'], [, '', 'foo'],
[1.2, '', ], ['1.2', '', ],
['', , 1.2], ['', , '1.2'],
[true, , true, 1.2], [, '1.2'],
['', 'foo', , 'foo'], ['', 'foo', , 'foo'],
]);
}).toErrorDev([
'Warning: Each child in a list should have a unique "key" prop.',
'Warning: Each child in a list should have a unique "key" prop.',
]);
});
it('should throw if rendering both HTML and children', () => {
expect(function() {
ReactTestUtils.renderIntoDocument(
ghjkl
,
);
}).toThrow();
});
it('should render between nested components and inline children', () => {
ReactTestUtils.renderIntoDocument(
,
);
expect(function() {
ReactTestUtils.renderIntoDocument(
A
,
);
}).not.toThrow();
expect(function() {
ReactTestUtils.renderIntoDocument(
{['A']}
,
);
}).not.toThrow();
expect(function() {
ReactTestUtils.renderIntoDocument(
{['A', 'B']}
,
);
}).not.toThrow();
});
});