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() {