@samitouri / QOS-React-2 / commits / 41d5cee44e

Simplified and improved test-cases for ReactMultiChildText-test

Andreas Svensson committed Aug 4, 2014 at 11:03 UTC 41d5cee44e65787a8121c70bab5f11ea71238d2b
1 file changed +160 -234
src/core/__tests__/ReactMultiChildText-test.js
+160 -234
@@ -28,65 +28,74 @@ var ReactTestUtils = require('ReactTestUtils');
28
29 var reactComponentExpect = require('reactComponentExpect');
30
31 -var assertNodeText = function(instance, text) {
32 - expect(instance.getDOMNode().childNodes.length).toBe(1);
33 - expect(instance.getDOMNode().innerHTML).toBe('' + text);
34 -};
31 +// Helpers
32 +var testAllPermutations = function(testCases) {
33 + for (var i = 0; i < testCases.length; i += 2) {
34 + var renderWithChildren = testCases[i];
35 + var expectedResultAfterRender = testCases[i + 1];
36
36 -var assertEmptyNode = function(instance) {
37 - expect(instance.getDOMNode().childNodes.length).toBe(0);
38 -};
37 + for (var j = 0; j < testCases.length; j += 2) {
38 + var updateWithChildren = testCases[j];
39 + var expectedResultAfterUpdate = testCases[j + 1];
40
40 -var assertMultiChild = function(instance, textOne, textTwo) {
41 - expect(instance.getDOMNode().childNodes.length).toBe(2);
42 - var firstTextDOMNode =
43 - reactComponentExpect(instance)
44 - .expectRenderedChildAt(0)
45 - .toBeTextComponent()
46 - .instance()
47 - .getDOMNode();
48 - expect(firstTextDOMNode.childNodes.length).toBe(textOne === '' ? 0 : 1);
49 - expect(firstTextDOMNode.innerHTML).toBe('' + textOne);
50 -
51 - var secondTextDOMNode =
52 - reactComponentExpect(instance)
53 - .expectRenderedChildAt(1)
54 - .toBeTextComponent()
55 - .instance()
56 - .getDOMNode();
57 - expect(secondTextDOMNode.childNodes.length).toBe(textTwo === '' ? 0 : 1);
58 - expect(secondTextDOMNode.innerHTML).toBe('' + textTwo);
59 -};
41 + var d = renderChildren(renderWithChildren);
42 + expectChildren(d, expectedResultAfterRender);
43
61 -var assertSingleChild = function(instance, text) {
62 - expect(instance.getDOMNode().childNodes.length).toBe(1);
63 - var textDOMNode =
64 - reactComponentExpect(instance)
65 - .expectRenderedChildAt(0)
66 - .toBeTextComponent()
67 - .instance()
68 - .getDOMNode();
69 - expect(textDOMNode.childNodes.length).toBe(1);
70 - expect(textDOMNode.innerHTML).toBe('' + text);
44 + updateChildren(d, updateWithChildren);
45 + expectChildren(d, expectedResultAfterUpdate);
46 + }
47 + }
48 };
49
73 -// Helpers
74 -var renderSingleTextChild = function(text) {
75 - var d = ReactTestUtils.renderIntoDocument(<div>{text}</div>);
76 - return d;
50 +var renderChildren = function(children) {
51 + return ReactTestUtils.renderIntoDocument(
52 + React.DOM.div({children: children})
53 + );
54 };
78 -var renderMultipleTextChildren = function(textOne, textTwo) {
79 - var d = ReactTestUtils.renderIntoDocument(<div>{textOne}{textTwo}</div>);
80 - return d;
55 +
56 +var updateChildren = function(d, children) {
57 + d.replaceProps({children: children});
58 };
59
83 -var TestCompositeComponent = React.createClass({
84 - render: function() {
85 - return (
86 - <div></div>
87 - );
60 +var expectChildren = function(d, children) {
61 + if (typeof children === 'string') {
62 + var textNode = d.getDOMNode().firstChild;
63 +
64 + if (children === '') {
65 + expect(textNode != null).toBe(false);
66 + } else {
67 + expect(textNode != null).toBe(true);
68 + expect(textNode.nodeType).toBe(3);
69 + expect(textNode.data).toBe('' + children);
70 + }
71 + } else {
72 + expect(d.getDOMNode().childNodes.length).toBe(children.length);
73 +
74 + for (var i = 0; i < children.length; i++) {
75 + var child = children[i];
76 +
77 + if (typeof child === 'string') {
78 + var textWrapperNode =
79 + reactComponentExpect(d)
80 + .expectRenderedChildAt(i)
81 + .toBeTextComponent()
82 + .instance();
83 +
84 + expectChildren(textWrapperNode, child);
85 + } else {
86 + var elementDOMNode =
87 + reactComponentExpect(d)
88 + .expectRenderedChildAt(i)
89 + .toBeComponentOfType(React.DOM.div)
90 + .instance()
91 + .getDOMNode();
92 +
93 + expect(elementDOMNode.tagName).toBe('DIV');
94 + }
95 + }
96 }
89 -});
97 +};
98 +
99
100 /**
101 * ReactMultiChild DOM integration test. In ReactDOM components, we make sure
@@ -94,190 +103,107 @@ var TestCompositeComponent = React.createClass({
103 * faster to render and update.
104 */
105 describe('ReactMultiChildText', function() {
97 - it('should render null as empty', function() {
98 - var d = renderSingleTextChild(null);
99 - // false should act exactly as a null child
100 - assertEmptyNode(d);
101 - });
102 -
103 - it('should render undefined as empty', function() {
104 - var d = renderSingleTextChild(undefined);
105 - // false should act exactly as a null child
106 - assertEmptyNode(d);
107 - });
108 -
109 - it('should render null as empty then switch to text node', function() {
110 - var d = renderSingleTextChild(null);
111 - // false should act exactly as a null child
112 - assertEmptyNode(d);
113 - d.replaceProps({children: 'hello'});
114 - assertNodeText(d, 'hello');
115 - });
116 -
117 - it('should render undefined as empty then switch to text node', function() {
118 - var d = renderSingleTextChild(undefined);
119 - // false should act exactly as a null child
120 - assertEmptyNode(d);
121 - d.replaceProps({children: 'hello'});
122 - assertNodeText(d, 'hello');
123 - });
124 -
125 - it('should render null as empty then switch to span children', function() {
126 - var d = renderSingleTextChild(null);
127 - // false should act exactly as a null child
128 - assertEmptyNode(d);
129 - d.replaceProps({children: ['hello', 'goodbye']});
130 - assertMultiChild(d, 'hello', 'goodbye');
131 - });
132 -
133 - it('should render null as empty then switch to span children', function() {
134 - var d = renderSingleTextChild(undefined);
135 - // false should act exactly as a null child
136 - assertEmptyNode(d);
137 - d.replaceProps({children: ['hello', 'goodbye']});
138 - assertMultiChild(d, 'hello', 'goodbye');
139 - });
140 -
141 - it('should render zero string as text node then switch to spans', function() {
142 - var d = renderSingleTextChild('0');
143 - // false should act exactly as a null child
144 - assertNodeText(d, '0');
145 - d.replaceProps({children: ['hello', 'goodbye']});
146 - assertMultiChild(d, 'hello', 'goodbye');
147 - });
148 -
149 - it('should render zero number as text node then switch to spans', function() {
150 - var d = renderSingleTextChild(0);
151 - // false should act exactly as a null child
152 - assertNodeText(d, '0');
153 - d.replaceProps({children: ['hello', 'goodbye']});
154 - assertMultiChild(d, 'hello', 'goodbye');
155 - });
156 -
157 - it('should render a single text child to a single text node', function() {
158 - var d = renderSingleTextChild('hello');
159 - assertNodeText(d, 'hello');
160 - });
161 -
162 - it('should render two string children to two spans', function() {
163 - var d = renderMultipleTextChildren('hello', 'goodbye');
164 - assertMultiChild(d, 'hello', 'goodbye');
165 - });
166 -
167 - it('should render false as a null child', function() {
168 - var d = renderMultipleTextChildren(false, 234.2);
169 - // false should act exactly as a null child
170 - assertSingleChild(d, '234.2');
171 - });
172 -
173 - it('should render true as a null child', function() {
174 - var d = renderMultipleTextChildren(true, 234.2);
175 - // false should act exactly as a null child
176 - assertSingleChild(d, '234.2');
177 - });
178 -
179 - it('should render true as a null child', function() {
180 - var d = renderMultipleTextChildren(true, 234.2);
181 - // false should act exactly as a null child
182 - assertSingleChild(d, '234.2');
183 - });
184 -
185 - it('should render one true as no children', function() {
186 - var d = renderSingleTextChild(true);
187 - assertEmptyNode(d);
188 - });
189 -
190 - it('should render one false as no children', function() {
191 - var d = renderSingleTextChild(false);
192 - assertEmptyNode(d);
193 - });
194 -
195 - it('should render empty string as no children', function() {
196 - var d = renderSingleTextChild('');
197 - assertEmptyNode(d);
198 - });
199 -
200 - it('should render two empty strings as two empty spans', function() {
201 - var d = renderMultipleTextChildren('', '');
202 - assertMultiChild(d, '', '');
203 - });
204 -
205 - it('should render empty string and string as two spans', function() {
206 - var d = renderMultipleTextChildren('', 'yo');
207 - assertMultiChild(d, '', 'yo');
208 - });
209 -
210 - it('should render child string zero as text node', function() {
211 - var d = renderSingleTextChild('0');
212 - // false should act exactly as a null child
213 - assertNodeText(d, '0');
214 - });
215 -
216 - it('should render child number zero as text node', function() {
217 - var d = renderSingleTextChild(0);
218 - // false should act exactly as a null child
219 - assertNodeText(d, '0');
220 - });
221 -
222 - it('should render content string zero as text node', function() {
223 - var d = renderSingleTextChild('0');
224 - // false should act exactly as a null child
225 - assertNodeText(d, '0');
226 - });
227 -
228 - it('should render zero string as string child', function() {
229 - var d = renderMultipleTextChildren('0', 234.2);
230 - // false should act exactly as a null child
231 - assertMultiChild(d, '0', '234.2');
232 - });
233 -
234 - it('should render zero string as string child then text node', function() {
235 - var d = renderMultipleTextChildren('0', 234.2);
236 - // false should act exactly as a null child
237 - assertMultiChild(d, '0', '234.2');
238 - d.replaceProps({children: '0'});
239 - assertNodeText(d, '0');
240 - });
241 -
242 - it('should render zero number as string child then text node', function() {
243 - var d = renderMultipleTextChildren(0, 234.2);
244 - // false should act exactly as a null child
245 - assertMultiChild(d, '0', '234.2');
246 - d.replaceProps({children: 0});
247 - // BELOW REVEALS A BUG IN JSDOM
248 - // assertNodeText(d, '0'); // This works in the browser.
249 - });
250 -
251 - it('should render multiple children then switch to inline', function() {
252 - var d = renderMultipleTextChildren('hello', 'goodbye');
253 - assertMultiChild(d, 'hello', 'goodbye');
254 - d.replaceProps({children: 'hello'});
255 - assertNodeText(d, 'hello');
256 - });
257 -
258 - it('should render multiple children then switch to inline child', function() {
259 - var d = renderMultipleTextChildren('hello', 'goodbye');
260 - assertMultiChild(d, 'hello', 'goodbye');
261 - // Even when switching from content to a single child, it should render
262 - // that single child as inline content.
263 - d.replaceProps({children: 'hello'});
264 - assertNodeText(d, 'hello');
265 - });
266 -
267 - it('should render inline child, then switch to text components ', function() {
268 - var d = renderSingleTextChild('hello');
269 - assertNodeText(d, 'hello');
270 - d.replaceProps({children: ['hello', 'goodbye']});
271 - assertMultiChild(d, 'hello', 'goodbye');
272 - });
273 -
274 - it('should render inline child, then switch to composite', function() {
275 - var d = renderSingleTextChild('hello');
276 - assertNodeText(d, 'hello');
277 - d.replaceProps({children: <TestCompositeComponent />});
278 - reactComponentExpect(d)
279 - .expectRenderedChildAt(0)
280 - .toBeCompositeComponentWithType(TestCompositeComponent);
106 + it('should correctly handle all possible children for render and update', function() {
107 + testAllPermutations([
108 + // basic values
109 + undefined, [],
110 + null, [],
111 + false, [],
112 + true, [],
113 + 0, '0',
114 + 1.2, '1.2',
115 + '', '',
116 + 'foo', 'foo',
117 +
118 + [], [],
119 + [undefined], [],
120 + [null], [],
121 + [false], [],
122 + [true], [],
123 + [0], ['0'],
124 + [1.2], ['1.2'],
125 + [''], [''],
126 + ['foo'], ['foo'],
127 + [<div />], [<div />],
128 +
129 + // two adjacent values
130 + [true, 0], ['0'],
131 + [0, 0], ['0', '0'],
132 + [1.2, 0], ['1.2', '0'],
133 + [0, ''], ['0', ''],
134 + ['foo', 0], ['foo', '0'],
135 + [0, <div />], ['0', <div />],
136 +
137 + [true, 1.2], ['1.2'],
138 + [1.2, 0], ['1.2', '0'],
139 + [1.2, 1.2], ['1.2', '1.2'],
140 + [1.2, ''], ['1.2', ''],
141 + ['foo', 1.2], ['foo', '1.2'],
142 + [1.2, <div />], ['1.2', <div />],
143 +
144 + [true, ''], [''],
145 + ['', 0], ['', '0'],
146 + [1.2, ''], ['1.2', ''],
147 + ['', ''], ['', ''],
148 + ['foo', ''], ['foo', ''],
149 + ['', <div />], ['', <div />],
150 +
151 + [true, 'foo'], ['foo'],
152 + ['foo', 0], ['foo', '0'],
153 + [1.2, 'foo'], ['1.2', 'foo'],
154 + ['foo', ''], ['foo', ''],
155 + ['foo', 'foo'], ['foo', 'foo'],
156 + ['foo', <div />], ['foo', <div />],
157 +
158 + // values separated by an element
159 + [true, <div />, true], [<div />],
160 + [1.2, <div />, 1.2], ['1.2', <div />, '1.2'],
161 + ['', <div />, ''], ['', <div />, ''],
162 + ['foo', <div />, 'foo'], ['foo', <div />, 'foo'],
163 +
164 + [true, 1.2, <div />, '', 'foo'], ['1.2', <div />, '', 'foo'],
165 + [1.2, '', <div />, 'foo', true], ['1.2', '', <div />, 'foo'],
166 + ['', 'foo', <div />, true, 1.2], ['', 'foo', <div />, '1.2'],
167 +
168 + [true, 1.2, '', <div />, 'foo', true, 1.2], ['1.2', '', <div />, 'foo', '1.2'],
169 + ['', 'foo', true, <div />, 1.2, '', 'foo'], ['', 'foo', <div />, '1.2', '', 'foo'],
170 +
171 + // values inside arrays
172 + [[true], [true]], [],
173 + [[1.2], [1.2]], ['1.2', '1.2'],
174 + [[''], ['']], ['', ''],
175 + [['foo'], ['foo']], ['foo', 'foo'],
176 + [[<div />], [<div />]], [<div />, <div />],
177 +
178 + [[true, 1.2, <div />], '', 'foo'], ['1.2', <div />, '', 'foo'],
179 + [1.2, '', [<div />, 'foo', true]], ['1.2', '', <div />, 'foo'],
180 + ['', ['foo', <div />, true], 1.2], ['', 'foo', <div />, '1.2'],
181 +
182 + [true, [1.2, '', <div />, 'foo'], true, 1.2], ['1.2', '', <div />, 'foo', '1.2'],
183 + ['', 'foo', [true, <div />, 1.2, ''], 'foo'], ['', 'foo', <div />, '1.2', '', 'foo'],
184 +
185 + // values inside objects
186 + [{a: true}, {a: true}], [],
187 + [{a: 1.2}, {a: 1.2}], ['1.2', '1.2'],
188 + [{a: ''}, {a: ''}], ['', ''],
189 + [{a: 'foo'}, {a: 'foo'}], ['foo', 'foo'],
190 + [{a: <div />}, {a: <div />}], [<div />, <div />],
191 +
192 + [{a: true, b: 1.2, c: <div />}, '', 'foo'], ['1.2', <div />, '', 'foo'],
193 + [1.2, '', {a: <div />, b: 'foo', c: true}], ['1.2', '', <div />, 'foo'],
194 + ['', {a: 'foo', b: <div />, c: true}, 1.2], ['', 'foo', <div />, '1.2'],
195 +
196 + [true, {a: 1.2, b: '', c: <div />, d: 'foo'}, true, 1.2], ['1.2', '', <div />, 'foo', '1.2'],
197 + ['', 'foo', {a: true, b: <div />, c: 1.2, d: ''}, 'foo'], ['', 'foo', <div />, '1.2', '', 'foo'],
198 +
199 + // values inside elements
200 + [<div>{true}{1.2}{<div />}</div>, '', 'foo'], [<div />, '', 'foo'],
201 + [1.2, '', <div>{<div />}{'foo'}{true}</div>], ['1.2', '', <div />],
202 + ['', <div>{'foo'}{<div />}{true}</div>, 1.2], ['', <div />, '1.2'],
203 +
204 + [true, <div>{1.2}{''}{<div />}{'foo'}</div>, true, 1.2], [<div />, '1.2'],
205 + ['', 'foo', <div>{true}{<div />}{1.2}{''}</div>, 'foo'], ['', 'foo', <div />, 'foo']
206 + ]);
207 });
208
209 it('should throw if rendering both HTML and children', function() {