react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / utils / __tests__ / ReactChildren-test.js
81155 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @emails react-core9*/1011"use strict";1213describe('ReactChildren', function() {14var ReactChildren;15var React;1617beforeEach(function() {18ReactChildren = require('ReactChildren');19React = require('React');20});212223it('should support identity for simple', function() {24var callback = jasmine.createSpy().andCallFake(function(kid, index) {25return kid;26});2728var simpleKid = <span key="simple" />;2930// First pass children into a component to fully simulate what happens when31// using structures that arrive from transforms.3233var instance = <div>{simpleKid}</div>;34ReactChildren.forEach(instance.props.children, callback);35expect(callback).toHaveBeenCalledWith(simpleKid, 0);36callback.reset();37var mappedChildren = ReactChildren.map(instance.props.children, callback);38expect(callback).toHaveBeenCalledWith(simpleKid, 0);39expect(mappedChildren[Object.keys(mappedChildren)[0]]).toBe(simpleKid);40});4142it('should treat single arrayless child as being in array', function() {43var callback = jasmine.createSpy().andCallFake(function(kid, index) {44return kid;45});4647var simpleKid = <span />;48var instance = <div>{simpleKid}</div>;49ReactChildren.forEach(instance.props.children, callback);50expect(callback).toHaveBeenCalledWith(simpleKid, 0);51callback.reset();52var mappedChildren = ReactChildren.map(instance.props.children, callback);53expect(callback).toHaveBeenCalledWith(simpleKid, 0);54expect(mappedChildren[Object.keys(mappedChildren)[0]]).toBe(simpleKid);55});5657it('should treat single child in array as expected', function() {58var callback = jasmine.createSpy().andCallFake(function(kid, index) {59return kid;60});6162var simpleKid = <span />;63var instance = <div>{[simpleKid]}</div>;64ReactChildren.forEach(instance.props.children, callback);65expect(callback).toHaveBeenCalledWith(simpleKid, 0);66callback.reset();67var mappedChildren = ReactChildren.map(instance.props.children, callback);68expect(callback).toHaveBeenCalledWith(simpleKid, 0);69expect(mappedChildren[Object.keys(mappedChildren)[0]]).toBe(simpleKid);70});7172it('should pass key to returned component', function() {73var mapFn = function(kid, index) {74return <div>{kid}</div>;75};7677var simpleKid = <span key="simple" />;7879var instance = <div>{simpleKid}</div>;80var mappedChildren = ReactChildren.map(instance.props.children, mapFn);8182var mappedKeys = Object.keys(mappedChildren);83expect(mappedKeys.length).toBe(1);84expect(mappedChildren[mappedKeys[0]]).not.toBe(simpleKid);85expect(mappedChildren[mappedKeys[0]].props.children).toBe(simpleKid);86expect(mappedKeys[0]).toBe('.$simple');87});8889it('should invoke callback with the right context', function() {90var lastContext;91var callback = function(kid, index) {92lastContext = this;93return this;94};9596var scopeTester = {};9798var simpleKid = <span key="simple" />;99var instance = <div>{simpleKid}</div>;100ReactChildren.forEach(instance.props.children, callback, scopeTester);101expect(lastContext).toBe(scopeTester);102103var mappedChildren =104ReactChildren.map(instance.props.children, callback, scopeTester);105106var mappedKeys = Object.keys(mappedChildren);107expect(mappedKeys.length).toBe(1);108expect(mappedChildren[mappedKeys[0]]).toBe(scopeTester);109});110111it('should be called for each child', function() {112var zero = <div key="keyZero" />;113var one = null;114var two = <div key="keyTwo" />;115var three = null;116var four = <div key="keyFour" />;117118var zeroMapped = <div key="giraffe" />; // Key should be joined to obj key119var oneMapped = null; // Key should be added even if we don't supply it!120var twoMapped = <div />; // Key should be added even if not supplied!121var threeMapped = <span />; // Map from null to something.122var fourMapped = <div key="keyFour" />;123124var callback = jasmine.createSpy().andCallFake(function(kid, index) {125return index === 0 ? zeroMapped :126index === 1 ? oneMapped :127index === 2 ? twoMapped :128index === 3 ? threeMapped : fourMapped;129});130131var instance = (132<div>133{zero}134{one}135{two}136{three}137{four}138</div>139);140141ReactChildren.forEach(instance.props.children, callback);142expect(callback).toHaveBeenCalledWith(zero, 0);143expect(callback).toHaveBeenCalledWith(one, 1);144expect(callback).toHaveBeenCalledWith(two, 2);145expect(callback).toHaveBeenCalledWith(three, 3);146expect(callback).toHaveBeenCalledWith(four, 4);147callback.reset();148149var mappedChildren =150ReactChildren.map(instance.props.children, callback);151var mappedKeys = Object.keys(mappedChildren);152expect(callback.calls.length).toBe(5);153expect(mappedKeys.length).toBe(5);154// Keys default to indices.155expect(mappedKeys).toEqual(156['.$keyZero', '.1', '.$keyTwo', '.3', '.$keyFour']157);158159expect(callback).toHaveBeenCalledWith(zero, 0);160expect(mappedChildren[mappedKeys[0]]).toBe(zeroMapped);161162expect(callback).toHaveBeenCalledWith(one, 1);163expect(mappedChildren[mappedKeys[1]]).toBe(oneMapped);164165expect(callback).toHaveBeenCalledWith(two, 2);166expect(mappedChildren[mappedKeys[2]]).toBe(twoMapped);167168expect(callback).toHaveBeenCalledWith(three, 3);169expect(mappedChildren[mappedKeys[3]]).toBe(threeMapped);170171expect(callback).toHaveBeenCalledWith(four, 4);172expect(mappedChildren[mappedKeys[4]]).toBe(fourMapped);173});174175176it('should be called for each child in nested structure', function() {177var zero = <div key="keyZero" />;178var one = null;179var two = <div key="keyTwo" />;180var three = null;181var four = <div key="keyFour" />;182var five = <div key="keyFiveInner" />;183// five is placed into a JS object with a key that is joined to the184// component key attribute.185// Precedence is as follows:186// 1. If grouped in an Object, the object key combined with `key` prop187// 2. If grouped in an Array, the `key` prop, falling back to array index188189var zeroMapped = <div key="giraffe" />; // Key should be overridden190var oneMapped = null; // Key should be added even if we don't supply it!191var twoMapped = <div />; // Key should be added even if not supplied!192var threeMapped = <span />; // Map from null to something.193var fourMapped = <div key="keyFour" />;194var fiveMapped = <div />;195196var callback = jasmine.createSpy().andCallFake(function(kid, index) {197return index === 0 ? zeroMapped :198index === 1 ? oneMapped :199index === 2 ? twoMapped :200index === 3 ? threeMapped :201index === 4 ? fourMapped : fiveMapped;202});203204var instance = (205<div>{206[{207firstHalfKey: [zero, one, two],208secondHalfKey: [three, four],209keyFive: five210}]211}</div>212);213214ReactChildren.forEach(instance.props.children, callback);215expect(callback).toHaveBeenCalledWith(zero, 0);216expect(callback).toHaveBeenCalledWith(one, 1);217expect(callback).toHaveBeenCalledWith(two, 2);218expect(callback).toHaveBeenCalledWith(three, 3);219expect(callback).toHaveBeenCalledWith(four, 4);220expect(callback).toHaveBeenCalledWith(five, 5);221callback.reset();222223var mappedChildren = ReactChildren.map(instance.props.children, callback);224var mappedKeys = Object.keys(mappedChildren);225expect(callback.calls.length).toBe(6);226expect(mappedKeys.length).toBe(6);227// Keys default to indices.228expect(mappedKeys).toEqual([229'.0:$firstHalfKey:0:$keyZero',230'.0:$firstHalfKey:0:1',231'.0:$firstHalfKey:0:$keyTwo',232'.0:$secondHalfKey:0:0',233'.0:$secondHalfKey:0:$keyFour',234'.0:$keyFive:$keyFiveInner'235]);236237expect(callback).toHaveBeenCalledWith(zero, 0);238expect(mappedChildren[mappedKeys[0]]).toBe(zeroMapped);239240expect(callback).toHaveBeenCalledWith(one, 1);241expect(mappedChildren[mappedKeys[1]]).toBe(oneMapped);242243expect(callback).toHaveBeenCalledWith(two, 2);244expect(mappedChildren[mappedKeys[2]]).toBe(twoMapped);245246expect(callback).toHaveBeenCalledWith(three, 3);247expect(mappedChildren[mappedKeys[3]]).toBe(threeMapped);248249expect(callback).toHaveBeenCalledWith(four, 4);250expect(mappedChildren[mappedKeys[4]]).toBe(fourMapped);251252expect(callback).toHaveBeenCalledWith(five, 5);253expect(mappedChildren[mappedKeys[5]]).toBe(fiveMapped);254});255256it('should retain key across two mappings', function() {257var zeroForceKey = <div key="keyZero" />;258var oneForceKey = <div key="keyOne" />;259260// Key should be joined to object key261var zeroForceKeyMapped = <div key="giraffe" />;262// Key should be added even if we don't supply it!263var oneForceKeyMapped = <div />;264265var mapFn = function(kid, index) {266return index === 0 ? zeroForceKeyMapped : oneForceKeyMapped;267};268269var forcedKeys = (270<div>271{zeroForceKey}272{oneForceKey}273</div>274);275276var expectedForcedKeys = ['.$keyZero', '.$keyOne'];277var mappedChildrenForcedKeys =278ReactChildren.map(forcedKeys.props.children, mapFn);279var mappedForcedKeys = Object.keys(mappedChildrenForcedKeys);280expect(mappedForcedKeys).toEqual(expectedForcedKeys);281282var expectedRemappedForcedKeys = [283'.$=1$keyZero:$giraffe',284'.$=1$keyOne:0'285];286var remappedChildrenForcedKeys =287ReactChildren.map(mappedChildrenForcedKeys, mapFn);288expect(289Object.keys(remappedChildrenForcedKeys)290).toEqual(expectedRemappedForcedKeys);291292});293294it('should not throw if key provided is a dupe with array key', function() {295var zero = <div />;296var one = <div key="0" />;297298var mapFn = function() {299return null;300};301302var instance = (303<div>304{zero}305{one}306</div>307);308309expect(function() {310ReactChildren.map(instance.props.children, mapFn);311}).not.toThrow();312});313314it('should warn if key provided is a dupe with explicit key', function() {315var zero = <div key="something"/>;316var one = <span key="something" />;317318var mapFn = function(component) { return component; };319var instance = (320<div>{zero}{one}</div>321);322323spyOn(console, 'warn');324var mapped = ReactChildren.map(instance.props.children, mapFn);325326expect(console.warn.calls.length).toEqual(1);327expect(mapped).toEqual({'.$something': zero});328});329330it('should return 0 for null children', function() {331var numberOfChildren = ReactChildren.count(null);332expect(numberOfChildren).toBe(0);333});334335it('should return 0 for undefined children', function() {336var numberOfChildren = ReactChildren.count(undefined);337expect(numberOfChildren).toBe(0);338});339340it('should return 1 for single child', function() {341var simpleKid = <span key="simple" />;342var instance = <div>{simpleKid}</div>;343var numberOfChildren = ReactChildren.count(instance.props.children);344expect(numberOfChildren).toBe(1);345});346347it('should count the number of children in flat structure', function() {348var zero = <div key="keyZero" />;349var one = null;350var two = <div key="keyTwo" />;351var three = null;352var four = <div key="keyFour" />;353354var instance = (355<div>356{zero}357{one}358{two}359{three}360{four}361</div>362);363var numberOfChildren = ReactChildren.count(instance.props.children);364expect(numberOfChildren).toBe(5);365});366367it('should count the number of children in nested structure', function() {368var zero = <div key="keyZero" />;369var one = null;370var two = <div key="keyTwo" />;371var three = null;372var four = <div key="keyFour" />;373var five = <div key="keyFiveInner" />;374// five is placed into a JS object with a key that is joined to the375// component key attribute.376// Precedence is as follows:377// 1. If grouped in an Object, the object key combined with `key` prop378// 2. If grouped in an Array, the `key` prop, falling back to array index379380var instance = (381<div>{382[{383firstHalfKey: [zero, one, two],384secondHalfKey: [three, four],385keyFive: five386}]387}</div>388);389var numberOfChildren = ReactChildren.count(instance.props.children);390expect(numberOfChildren).toBe(6);391});392});393394395