Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81155 views
1
/**
2
* Copyright 2013-2014, Facebook, Inc.
3
* All rights reserved.
4
*
5
* This source code is licensed under the BSD-style license found in the
6
* LICENSE file in the root directory of this source tree. An additional grant
7
* of patent rights can be found in the PATENTS file in the same directory.
8
*
9
* @emails react-core
10
*/
11
12
"use strict";
13
14
describe('ReactChildren', function() {
15
var ReactChildren;
16
var React;
17
18
beforeEach(function() {
19
ReactChildren = require('ReactChildren');
20
React = require('React');
21
});
22
23
24
it('should support identity for simple', function() {
25
var callback = jasmine.createSpy().andCallFake(function(kid, index) {
26
return kid;
27
});
28
29
var simpleKid = <span key="simple" />;
30
31
// First pass children into a component to fully simulate what happens when
32
// using structures that arrive from transforms.
33
34
var instance = <div>{simpleKid}</div>;
35
ReactChildren.forEach(instance.props.children, callback);
36
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
37
callback.reset();
38
var mappedChildren = ReactChildren.map(instance.props.children, callback);
39
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
40
expect(mappedChildren[Object.keys(mappedChildren)[0]]).toBe(simpleKid);
41
});
42
43
it('should treat single arrayless child as being in array', function() {
44
var callback = jasmine.createSpy().andCallFake(function(kid, index) {
45
return kid;
46
});
47
48
var simpleKid = <span />;
49
var instance = <div>{simpleKid}</div>;
50
ReactChildren.forEach(instance.props.children, callback);
51
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
52
callback.reset();
53
var mappedChildren = ReactChildren.map(instance.props.children, callback);
54
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
55
expect(mappedChildren[Object.keys(mappedChildren)[0]]).toBe(simpleKid);
56
});
57
58
it('should treat single child in array as expected', function() {
59
var callback = jasmine.createSpy().andCallFake(function(kid, index) {
60
return kid;
61
});
62
63
var simpleKid = <span />;
64
var instance = <div>{[simpleKid]}</div>;
65
ReactChildren.forEach(instance.props.children, callback);
66
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
67
callback.reset();
68
var mappedChildren = ReactChildren.map(instance.props.children, callback);
69
expect(callback).toHaveBeenCalledWith(simpleKid, 0);
70
expect(mappedChildren[Object.keys(mappedChildren)[0]]).toBe(simpleKid);
71
});
72
73
it('should pass key to returned component', function() {
74
var mapFn = function(kid, index) {
75
return <div>{kid}</div>;
76
};
77
78
var simpleKid = <span key="simple" />;
79
80
var instance = <div>{simpleKid}</div>;
81
var mappedChildren = ReactChildren.map(instance.props.children, mapFn);
82
83
var mappedKeys = Object.keys(mappedChildren);
84
expect(mappedKeys.length).toBe(1);
85
expect(mappedChildren[mappedKeys[0]]).not.toBe(simpleKid);
86
expect(mappedChildren[mappedKeys[0]].props.children).toBe(simpleKid);
87
expect(mappedKeys[0]).toBe('.$simple');
88
});
89
90
it('should invoke callback with the right context', function() {
91
var lastContext;
92
var callback = function(kid, index) {
93
lastContext = this;
94
return this;
95
};
96
97
var scopeTester = {};
98
99
var simpleKid = <span key="simple" />;
100
var instance = <div>{simpleKid}</div>;
101
ReactChildren.forEach(instance.props.children, callback, scopeTester);
102
expect(lastContext).toBe(scopeTester);
103
104
var mappedChildren =
105
ReactChildren.map(instance.props.children, callback, scopeTester);
106
107
var mappedKeys = Object.keys(mappedChildren);
108
expect(mappedKeys.length).toBe(1);
109
expect(mappedChildren[mappedKeys[0]]).toBe(scopeTester);
110
});
111
112
it('should be called for each child', function() {
113
var zero = <div key="keyZero" />;
114
var one = null;
115
var two = <div key="keyTwo" />;
116
var three = null;
117
var four = <div key="keyFour" />;
118
119
var zeroMapped = <div key="giraffe" />; // Key should be joined to obj key
120
var oneMapped = null; // Key should be added even if we don't supply it!
121
var twoMapped = <div />; // Key should be added even if not supplied!
122
var threeMapped = <span />; // Map from null to something.
123
var fourMapped = <div key="keyFour" />;
124
125
var callback = jasmine.createSpy().andCallFake(function(kid, index) {
126
return index === 0 ? zeroMapped :
127
index === 1 ? oneMapped :
128
index === 2 ? twoMapped :
129
index === 3 ? threeMapped : fourMapped;
130
});
131
132
var instance = (
133
<div>
134
{zero}
135
{one}
136
{two}
137
{three}
138
{four}
139
</div>
140
);
141
142
ReactChildren.forEach(instance.props.children, callback);
143
expect(callback).toHaveBeenCalledWith(zero, 0);
144
expect(callback).toHaveBeenCalledWith(one, 1);
145
expect(callback).toHaveBeenCalledWith(two, 2);
146
expect(callback).toHaveBeenCalledWith(three, 3);
147
expect(callback).toHaveBeenCalledWith(four, 4);
148
callback.reset();
149
150
var mappedChildren =
151
ReactChildren.map(instance.props.children, callback);
152
var mappedKeys = Object.keys(mappedChildren);
153
expect(callback.calls.length).toBe(5);
154
expect(mappedKeys.length).toBe(5);
155
// Keys default to indices.
156
expect(mappedKeys).toEqual(
157
['.$keyZero', '.1', '.$keyTwo', '.3', '.$keyFour']
158
);
159
160
expect(callback).toHaveBeenCalledWith(zero, 0);
161
expect(mappedChildren[mappedKeys[0]]).toBe(zeroMapped);
162
163
expect(callback).toHaveBeenCalledWith(one, 1);
164
expect(mappedChildren[mappedKeys[1]]).toBe(oneMapped);
165
166
expect(callback).toHaveBeenCalledWith(two, 2);
167
expect(mappedChildren[mappedKeys[2]]).toBe(twoMapped);
168
169
expect(callback).toHaveBeenCalledWith(three, 3);
170
expect(mappedChildren[mappedKeys[3]]).toBe(threeMapped);
171
172
expect(callback).toHaveBeenCalledWith(four, 4);
173
expect(mappedChildren[mappedKeys[4]]).toBe(fourMapped);
174
});
175
176
177
it('should be called for each child in nested structure', function() {
178
var zero = <div key="keyZero" />;
179
var one = null;
180
var two = <div key="keyTwo" />;
181
var three = null;
182
var four = <div key="keyFour" />;
183
var five = <div key="keyFiveInner" />;
184
// five is placed into a JS object with a key that is joined to the
185
// component key attribute.
186
// Precedence is as follows:
187
// 1. If grouped in an Object, the object key combined with `key` prop
188
// 2. If grouped in an Array, the `key` prop, falling back to array index
189
190
var zeroMapped = <div key="giraffe" />; // Key should be overridden
191
var oneMapped = null; // Key should be added even if we don't supply it!
192
var twoMapped = <div />; // Key should be added even if not supplied!
193
var threeMapped = <span />; // Map from null to something.
194
var fourMapped = <div key="keyFour" />;
195
var fiveMapped = <div />;
196
197
var callback = jasmine.createSpy().andCallFake(function(kid, index) {
198
return index === 0 ? zeroMapped :
199
index === 1 ? oneMapped :
200
index === 2 ? twoMapped :
201
index === 3 ? threeMapped :
202
index === 4 ? fourMapped : fiveMapped;
203
});
204
205
var instance = (
206
<div>{
207
[{
208
firstHalfKey: [zero, one, two],
209
secondHalfKey: [three, four],
210
keyFive: five
211
}]
212
}</div>
213
);
214
215
ReactChildren.forEach(instance.props.children, callback);
216
expect(callback).toHaveBeenCalledWith(zero, 0);
217
expect(callback).toHaveBeenCalledWith(one, 1);
218
expect(callback).toHaveBeenCalledWith(two, 2);
219
expect(callback).toHaveBeenCalledWith(three, 3);
220
expect(callback).toHaveBeenCalledWith(four, 4);
221
expect(callback).toHaveBeenCalledWith(five, 5);
222
callback.reset();
223
224
var mappedChildren = ReactChildren.map(instance.props.children, callback);
225
var mappedKeys = Object.keys(mappedChildren);
226
expect(callback.calls.length).toBe(6);
227
expect(mappedKeys.length).toBe(6);
228
// Keys default to indices.
229
expect(mappedKeys).toEqual([
230
'.0:$firstHalfKey:0:$keyZero',
231
'.0:$firstHalfKey:0:1',
232
'.0:$firstHalfKey:0:$keyTwo',
233
'.0:$secondHalfKey:0:0',
234
'.0:$secondHalfKey:0:$keyFour',
235
'.0:$keyFive:$keyFiveInner'
236
]);
237
238
expect(callback).toHaveBeenCalledWith(zero, 0);
239
expect(mappedChildren[mappedKeys[0]]).toBe(zeroMapped);
240
241
expect(callback).toHaveBeenCalledWith(one, 1);
242
expect(mappedChildren[mappedKeys[1]]).toBe(oneMapped);
243
244
expect(callback).toHaveBeenCalledWith(two, 2);
245
expect(mappedChildren[mappedKeys[2]]).toBe(twoMapped);
246
247
expect(callback).toHaveBeenCalledWith(three, 3);
248
expect(mappedChildren[mappedKeys[3]]).toBe(threeMapped);
249
250
expect(callback).toHaveBeenCalledWith(four, 4);
251
expect(mappedChildren[mappedKeys[4]]).toBe(fourMapped);
252
253
expect(callback).toHaveBeenCalledWith(five, 5);
254
expect(mappedChildren[mappedKeys[5]]).toBe(fiveMapped);
255
});
256
257
it('should retain key across two mappings', function() {
258
var zeroForceKey = <div key="keyZero" />;
259
var oneForceKey = <div key="keyOne" />;
260
261
// Key should be joined to object key
262
var zeroForceKeyMapped = <div key="giraffe" />;
263
// Key should be added even if we don't supply it!
264
var oneForceKeyMapped = <div />;
265
266
var mapFn = function(kid, index) {
267
return index === 0 ? zeroForceKeyMapped : oneForceKeyMapped;
268
};
269
270
var forcedKeys = (
271
<div>
272
{zeroForceKey}
273
{oneForceKey}
274
</div>
275
);
276
277
var expectedForcedKeys = ['.$keyZero', '.$keyOne'];
278
var mappedChildrenForcedKeys =
279
ReactChildren.map(forcedKeys.props.children, mapFn);
280
var mappedForcedKeys = Object.keys(mappedChildrenForcedKeys);
281
expect(mappedForcedKeys).toEqual(expectedForcedKeys);
282
283
var expectedRemappedForcedKeys = [
284
'.$=1$keyZero:$giraffe',
285
'.$=1$keyOne:0'
286
];
287
var remappedChildrenForcedKeys =
288
ReactChildren.map(mappedChildrenForcedKeys, mapFn);
289
expect(
290
Object.keys(remappedChildrenForcedKeys)
291
).toEqual(expectedRemappedForcedKeys);
292
293
});
294
295
it('should not throw if key provided is a dupe with array key', function() {
296
var zero = <div />;
297
var one = <div key="0" />;
298
299
var mapFn = function() {
300
return null;
301
};
302
303
var instance = (
304
<div>
305
{zero}
306
{one}
307
</div>
308
);
309
310
expect(function() {
311
ReactChildren.map(instance.props.children, mapFn);
312
}).not.toThrow();
313
});
314
315
it('should warn if key provided is a dupe with explicit key', function() {
316
var zero = <div key="something"/>;
317
var one = <span key="something" />;
318
319
var mapFn = function(component) { return component; };
320
var instance = (
321
<div>{zero}{one}</div>
322
);
323
324
spyOn(console, 'warn');
325
var mapped = ReactChildren.map(instance.props.children, mapFn);
326
327
expect(console.warn.calls.length).toEqual(1);
328
expect(mapped).toEqual({'.$something': zero});
329
});
330
331
it('should return 0 for null children', function() {
332
var numberOfChildren = ReactChildren.count(null);
333
expect(numberOfChildren).toBe(0);
334
});
335
336
it('should return 0 for undefined children', function() {
337
var numberOfChildren = ReactChildren.count(undefined);
338
expect(numberOfChildren).toBe(0);
339
});
340
341
it('should return 1 for single child', function() {
342
var simpleKid = <span key="simple" />;
343
var instance = <div>{simpleKid}</div>;
344
var numberOfChildren = ReactChildren.count(instance.props.children);
345
expect(numberOfChildren).toBe(1);
346
});
347
348
it('should count the number of children in flat structure', function() {
349
var zero = <div key="keyZero" />;
350
var one = null;
351
var two = <div key="keyTwo" />;
352
var three = null;
353
var four = <div key="keyFour" />;
354
355
var instance = (
356
<div>
357
{zero}
358
{one}
359
{two}
360
{three}
361
{four}
362
</div>
363
);
364
var numberOfChildren = ReactChildren.count(instance.props.children);
365
expect(numberOfChildren).toBe(5);
366
});
367
368
it('should count the number of children in nested structure', function() {
369
var zero = <div key="keyZero" />;
370
var one = null;
371
var two = <div key="keyTwo" />;
372
var three = null;
373
var four = <div key="keyFour" />;
374
var five = <div key="keyFiveInner" />;
375
// five is placed into a JS object with a key that is joined to the
376
// component key attribute.
377
// Precedence is as follows:
378
// 1. If grouped in an Object, the object key combined with `key` prop
379
// 2. If grouped in an Array, the `key` prop, falling back to array index
380
381
var instance = (
382
<div>{
383
[{
384
firstHalfKey: [zero, one, two],
385
secondHalfKey: [three, four],
386
keyFive: five
387
}]
388
}</div>
389
);
390
var numberOfChildren = ReactChildren.count(instance.props.children);
391
expect(numberOfChildren).toBe(6);
392
});
393
});
394
395