diff --git a/src/core/__tests__/ReactMultiChildText-test.js b/src/core/__tests__/ReactMultiChildText-test.js index 3ecef8ed7820f..51a0cffc7a938 100644 --- a/src/core/__tests__/ReactMultiChildText-test.js +++ b/src/core/__tests__/ReactMultiChildText-test.js @@ -28,65 +28,74 @@ var ReactTestUtils = require('ReactTestUtils'); var reactComponentExpect = require('reactComponentExpect'); -var assertNodeText = function(instance, text) { - expect(instance.getDOMNode().childNodes.length).toBe(1); - expect(instance.getDOMNode().innerHTML).toBe('' + text); -}; +// Helpers +var testAllPermutations = function(testCases) { + for (var i = 0; i < testCases.length; i += 2) { + var renderWithChildren = testCases[i]; + var expectedResultAfterRender = testCases[i + 1]; -var assertEmptyNode = function(instance) { - expect(instance.getDOMNode().childNodes.length).toBe(0); -}; + for (var j = 0; j < testCases.length; j += 2) { + var updateWithChildren = testCases[j]; + var expectedResultAfterUpdate = testCases[j + 1]; -var assertMultiChild = function(instance, textOne, textTwo) { - expect(instance.getDOMNode().childNodes.length).toBe(2); - var firstTextDOMNode = - reactComponentExpect(instance) - .expectRenderedChildAt(0) - .toBeTextComponent() - .instance() - .getDOMNode(); - expect(firstTextDOMNode.childNodes.length).toBe(textOne === '' ? 0 : 1); - expect(firstTextDOMNode.innerHTML).toBe('' + textOne); - - var secondTextDOMNode = - reactComponentExpect(instance) - .expectRenderedChildAt(1) - .toBeTextComponent() - .instance() - .getDOMNode(); - expect(secondTextDOMNode.childNodes.length).toBe(textTwo === '' ? 0 : 1); - expect(secondTextDOMNode.innerHTML).toBe('' + textTwo); -}; + var d = renderChildren(renderWithChildren); + expectChildren(d, expectedResultAfterRender); -var assertSingleChild = function(instance, text) { - expect(instance.getDOMNode().childNodes.length).toBe(1); - var textDOMNode = - reactComponentExpect(instance) - .expectRenderedChildAt(0) - .toBeTextComponent() - .instance() - .getDOMNode(); - expect(textDOMNode.childNodes.length).toBe(1); - expect(textDOMNode.innerHTML).toBe('' + text); + updateChildren(d, updateWithChildren); + expectChildren(d, expectedResultAfterUpdate); + } + } }; -// Helpers -var renderSingleTextChild = function(text) { - var d = ReactTestUtils.renderIntoDocument(
{text}
); - return d; +var renderChildren = function(children) { + return ReactTestUtils.renderIntoDocument( + React.DOM.div({children: children}) + ); }; -var renderMultipleTextChildren = function(textOne, textTwo) { - var d = ReactTestUtils.renderIntoDocument(
{textOne}{textTwo}
); - return d; + +var updateChildren = function(d, children) { + d.replaceProps({children: children}); }; -var TestCompositeComponent = React.createClass({ - render: function() { - return ( -
- ); +var expectChildren = function(d, children) { + if (typeof children === 'string') { + var textNode = d.getDOMNode().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 { + expect(d.getDOMNode().childNodes.length).toBe(children.length); + + for (var i = 0; i < children.length; i++) { + var child = children[i]; + + if (typeof child === 'string') { + var textWrapperNode = + reactComponentExpect(d) + .expectRenderedChildAt(i) + .toBeTextComponent() + .instance(); + + expectChildren(textWrapperNode, child); + } else { + var elementDOMNode = + reactComponentExpect(d) + .expectRenderedChildAt(i) + .toBeComponentOfType(React.DOM.div) + .instance() + .getDOMNode(); + + expect(elementDOMNode.tagName).toBe('DIV'); + } + } } -}); +}; + /** * ReactMultiChild DOM integration test. In ReactDOM components, we make sure @@ -94,190 +103,107 @@ var TestCompositeComponent = React.createClass({ * faster to render and update. */ describe('ReactMultiChildText', function() { - it('should render null as empty', function() { - var d = renderSingleTextChild(null); - // false should act exactly as a null child - assertEmptyNode(d); - }); - - it('should render undefined as empty', function() { - var d = renderSingleTextChild(undefined); - // false should act exactly as a null child - assertEmptyNode(d); - }); - - it('should render null as empty then switch to text node', function() { - var d = renderSingleTextChild(null); - // false should act exactly as a null child - assertEmptyNode(d); - d.replaceProps({children: 'hello'}); - assertNodeText(d, 'hello'); - }); - - it('should render undefined as empty then switch to text node', function() { - var d = renderSingleTextChild(undefined); - // false should act exactly as a null child - assertEmptyNode(d); - d.replaceProps({children: 'hello'}); - assertNodeText(d, 'hello'); - }); - - it('should render null as empty then switch to span children', function() { - var d = renderSingleTextChild(null); - // false should act exactly as a null child - assertEmptyNode(d); - d.replaceProps({children: ['hello', 'goodbye']}); - assertMultiChild(d, 'hello', 'goodbye'); - }); - - it('should render null as empty then switch to span children', function() { - var d = renderSingleTextChild(undefined); - // false should act exactly as a null child - assertEmptyNode(d); - d.replaceProps({children: ['hello', 'goodbye']}); - assertMultiChild(d, 'hello', 'goodbye'); - }); - - it('should render zero string as text node then switch to spans', function() { - var d = renderSingleTextChild('0'); - // false should act exactly as a null child - assertNodeText(d, '0'); - d.replaceProps({children: ['hello', 'goodbye']}); - assertMultiChild(d, 'hello', 'goodbye'); - }); - - it('should render zero number as text node then switch to spans', function() { - var d = renderSingleTextChild(0); - // false should act exactly as a null child - assertNodeText(d, '0'); - d.replaceProps({children: ['hello', 'goodbye']}); - assertMultiChild(d, 'hello', 'goodbye'); - }); - - it('should render a single text child to a single text node', function() { - var d = renderSingleTextChild('hello'); - assertNodeText(d, 'hello'); - }); - - it('should render two string children to two spans', function() { - var d = renderMultipleTextChildren('hello', 'goodbye'); - assertMultiChild(d, 'hello', 'goodbye'); - }); - - it('should render false as a null child', function() { - var d = renderMultipleTextChildren(false, 234.2); - // false should act exactly as a null child - assertSingleChild(d, '234.2'); - }); - - it('should render true as a null child', function() { - var d = renderMultipleTextChildren(true, 234.2); - // false should act exactly as a null child - assertSingleChild(d, '234.2'); - }); - - it('should render true as a null child', function() { - var d = renderMultipleTextChildren(true, 234.2); - // false should act exactly as a null child - assertSingleChild(d, '234.2'); - }); - - it('should render one true as no children', function() { - var d = renderSingleTextChild(true); - assertEmptyNode(d); - }); - - it('should render one false as no children', function() { - var d = renderSingleTextChild(false); - assertEmptyNode(d); - }); - - it('should render empty string as no children', function() { - var d = renderSingleTextChild(''); - assertEmptyNode(d); - }); - - it('should render two empty strings as two empty spans', function() { - var d = renderMultipleTextChildren('', ''); - assertMultiChild(d, '', ''); - }); - - it('should render empty string and string as two spans', function() { - var d = renderMultipleTextChildren('', 'yo'); - assertMultiChild(d, '', 'yo'); - }); - - it('should render child string zero as text node', function() { - var d = renderSingleTextChild('0'); - // false should act exactly as a null child - assertNodeText(d, '0'); - }); - - it('should render child number zero as text node', function() { - var d = renderSingleTextChild(0); - // false should act exactly as a null child - assertNodeText(d, '0'); - }); - - it('should render content string zero as text node', function() { - var d = renderSingleTextChild('0'); - // false should act exactly as a null child - assertNodeText(d, '0'); - }); - - it('should render zero string as string child', function() { - var d = renderMultipleTextChildren('0', 234.2); - // false should act exactly as a null child - assertMultiChild(d, '0', '234.2'); - }); - - it('should render zero string as string child then text node', function() { - var d = renderMultipleTextChildren('0', 234.2); - // false should act exactly as a null child - assertMultiChild(d, '0', '234.2'); - d.replaceProps({children: '0'}); - assertNodeText(d, '0'); - }); - - it('should render zero number as string child then text node', function() { - var d = renderMultipleTextChildren(0, 234.2); - // false should act exactly as a null child - assertMultiChild(d, '0', '234.2'); - d.replaceProps({children: 0}); - // BELOW REVEALS A BUG IN JSDOM - // assertNodeText(d, '0'); // This works in the browser. - }); - - it('should render multiple children then switch to inline', function() { - var d = renderMultipleTextChildren('hello', 'goodbye'); - assertMultiChild(d, 'hello', 'goodbye'); - d.replaceProps({children: 'hello'}); - assertNodeText(d, 'hello'); - }); - - it('should render multiple children then switch to inline child', function() { - var d = renderMultipleTextChildren('hello', 'goodbye'); - assertMultiChild(d, 'hello', 'goodbye'); - // Even when switching from content to a single child, it should render - // that single child as inline content. - d.replaceProps({children: 'hello'}); - assertNodeText(d, 'hello'); - }); - - it('should render inline child, then switch to text components ', function() { - var d = renderSingleTextChild('hello'); - assertNodeText(d, 'hello'); - d.replaceProps({children: ['hello', 'goodbye']}); - assertMultiChild(d, 'hello', 'goodbye'); - }); - - it('should render inline child, then switch to composite', function() { - var d = renderSingleTextChild('hello'); - assertNodeText(d, 'hello'); - d.replaceProps({children: }); - reactComponentExpect(d) - .expectRenderedChildAt(0) - .toBeCompositeComponentWithType(TestCompositeComponent); + it('should correctly handle all possible children for render and update', function() { + 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 objects + [{a: true}, {a: true}], [], + [{a: 1.2}, {a: 1.2}], ['1.2', '1.2'], + [{a: ''}, {a: ''}], ['', ''], + [{a: 'foo'}, {a: 'foo'}], ['foo', 'foo'], + [{a:
}, {a:
}], [
,
], + + [{a: true, b: 1.2, c:
}, '', 'foo'], ['1.2',
, '', 'foo'], + [1.2, '', {a:
, b: 'foo', c: true}], ['1.2', '',
, 'foo'], + ['', {a: 'foo', b:
, c: true}, 1.2], ['', 'foo',
, '1.2'], + + [true, {a: 1.2, b: '', c:
, d: 'foo'}, true, 1.2], ['1.2', '',
, 'foo', '1.2'], + ['', 'foo', {a: true, b:
, c: 1.2, d: ''}, 'foo'], ['', 'foo',
, '1.2', '', 'foo'], + + // values inside elements + [
{true}{1.2}{
}
, '', 'foo'], [
, '', 'foo'], + [1.2, '',
{
}{'foo'}{true}
], ['1.2', '',
], + ['',
{'foo'}{
}{true}
, 1.2], ['',
, '1.2'], + + [true,
{1.2}{''}{
}{'foo'}
, true, 1.2], [
, '1.2'], + ['', 'foo',
{true}{
}{1.2}{''}
, 'foo'], ['', 'foo',
, 'foo'] + ]); }); it('should throw if rendering both HTML and children', function() {