text: /**
   * Copyright 2013-2015, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   *
   * @emails react-core
   */
  
  'use strict';
  
  describe('traverseAllChildren', function() {
    var traverseAllChildren;
    var React;
    var ReactFragment;
    beforeEach(function() {
      require('mock-modules').dumpCache();
      traverseAllChildren = require('traverseAllChildren');
      React = require('React');
      ReactFragment = require('ReactFragment');
    });
  
    function frag(obj) {
      return ReactFragment.create(obj);
    }
  
    it('should support identity for simple', function() {
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(true);
        });
  
      var simpleKid = <span key="simple" />;
  
      // Jasmine doesn't provide a way to test that the fn was invoked with scope.
      var instance = <div>{simpleKid}</div>;
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        simpleKid,
        '.$simple'
      );
      expect(traverseContext.length).toEqual(1);
    });
  
    it('should treat single arrayless child as being in array', function() {
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(true);
        });
  
      var simpleKid = <span />;
      var instance = <div>{simpleKid}</div>;
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        simpleKid,
        '.0'
      );
      expect(traverseContext.length).toEqual(1);
    });
  
    it('should treat single child in array as expected', function() {
      spyOn(console, 'error');
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(true);
        });
  
      var simpleKid = <span />;
      var instance = <div>{[simpleKid]}</div>;
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        simpleKid,
        '.0'
      );
      expect(traverseContext.length).toEqual(1);
      expect(console.error.calls.length).toBe(1);
      expect(console.error.calls[0].args[0]).toContain('Warning: Each child in an array or iterator should have a unique "key" prop.');
    });
  
    it('should be called for each child', function() {
      var zero = <div key="keyZero" />;
      var one = null;
      var two = <div key="keyTwo" />;
      var three = null;
      var four = <div key="keyFour" />;
  
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(true);
        });
  
      var instance = (
        <div>
          {zero}
          {one}
          {two}
          {three}
          {four}
        </div>
      );
  
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        zero,
        '.$keyZero'
      );
      expect(traverseFn).toHaveBeenCalledWith(traverseContext, one, '.1');
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        two,
        '.$keyTwo'
      );
      expect(traverseFn).toHaveBeenCalledWith(traverseContext, three, '.3');
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        four,
        '.$keyFour'
      );
    });
  
    it('should traverse children of different kinds', function() {
      var div = <div key="divNode" />;
      var span = <span key="spanNode" />;
      var a = <a key="aNode" />;
  
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(true);
        });
  
      var instance = (
        <div>
          {div}
          {[frag({span})]}
          {frag({a: a})}
          {'string'}
          {1234}
          {true}
          {false}
          {null}
          {undefined}
        </div>
      );
  
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
  
      expect(traverseFn.calls.length).toBe(9);
      expect(traverseContext.length).toEqual(9);
  
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, div, '.$divNode'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, <span key="span/.$spanNode" />, '.1:0:$span/=1$spanNode'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, <a key="a/.$aNode" />, '.2:$a/=1$aNode'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, 'string', '.3'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, 1234, '.4'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, null, '.5'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, null, '.6'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, null, '.7'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext, null, '.8'
      );
    });
  
    it('should be called for each child in nested structure', function() {
      var zero = <div key="keyZero" />;
      var one = null;
      var two = <div key="keyTwo" />;
      var three = null;
      var four = <div key="keyFour" />;
      var five = <div key="keyFiveInner" />;
      // five is placed into a JS object with a key that is joined to the
      // component key attribute.
      // Precedence is as follows:
      // 1. If grouped in an Object, the object key combined with `key` prop
      // 2. If grouped in an Array, the `key` prop, falling back to array index
  
  
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(true);
        });
  
      var instance = (
        <div>{
          [
            frag({
              firstHalfKey: [zero, one, two],
              secondHalfKey: [three, four],
              keyFive: five,
            }),
          ]
        }</div>
      );
  
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn.calls.length).toBe(4);
      expect(traverseContext.length).toEqual(4);
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        <div key="firstHalfKey/.$keyZero" />,
        '.0:$firstHalfKey/=1$keyZero'
      );
  
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        <div key="firstHalfKey/.$keyTwo" />,
        '.0:$firstHalfKey/=1$keyTwo'
      );
  
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        <div key="secondHalfKey/.$keyFour" />,
        '.0:$secondHalfKey/=1$keyFour'
      );
  
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        <div key="keyFive/.$keyFiveInner" />,
        '.0:$keyFive/=1$keyFiveInner'
      );
    });
  
    it('should retain key across two mappings', function() {
      var zeroForceKey = <div key="keyZero" />;
      var oneForceKey = <div key="keyOne" />;
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(true);
        });
  
      var forcedKeys = (
        <div>
          {zeroForceKey}
          {oneForceKey}
        </div>
      );
  
      traverseAllChildren(forcedKeys.props.children, traverseFn, traverseContext);
      expect(traverseContext.length).toEqual(2);
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        zeroForceKey,
        '.$keyZero'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        oneForceKey,
        '.$keyOne'
      );
    });
  
    it('should be called for each child in an iterable without keys', function() {
      spyOn(console, 'error');
      var threeDivIterable = {
        '@@iterator': function() {
          var i = 0;
          return {
            next: function() {
              if (i++ < 3) {
                return {value: <div />, done: false};
              } else {
                return {value: undefined, done: true};
              }
            },
          };
        },
      };
  
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(kid);
        });
  
      var instance = (
        <div>
          {threeDivIterable}
        </div>
      );
  
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn.calls.length).toBe(3);
  
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[0],
        '.0'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[1],
        '.1'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[2],
        '.2'
      );
  
      expect(console.error.calls.length).toBe(1);
      expect(console.error.calls[0].args[0]).toContain('Warning: Each child in an array or iterator should have a unique "key" prop.');
    });
  
    it('should be called for each child in an iterable with keys', function() {
      var threeDivIterable = {
        '@@iterator': function() {
          var i = 0;
          return {
            next: function() {
              if (i++ < 3) {
                return {value: <div key={'#' + i} />, done: false};
              } else {
                return {value: undefined, done: true};
              }
            },
          };
        },
      };
  
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(kid);
        });
  
      var instance = (
        <div>
          {threeDivIterable}
        </div>
      );
  
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn.calls.length).toBe(3);
  
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[0],
        '.$#1'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[1],
        '.$#2'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[2],
        '.$#3'
      );
    });
  
    it('should use keys from entry iterables', function() {
      spyOn(console, 'error');
  
      var threeDivEntryIterable = {
        '@@iterator': function() {
          var i = 0;
          return {
            next: function() {
              if (i++ < 3) {
                return {value: ['#' + i, <div />], done: false};
              } else {
                return {value: undefined, done: true};
              }
            },
          };
        },
      };
      threeDivEntryIterable.entries = threeDivEntryIterable['@@iterator'];
  
      var traverseContext = [];
      var traverseFn =
        jasmine.createSpy().andCallFake(function(context, kid, key, index) {
          context.push(kid);
        });
  
      var instance = (
        <div>
          {threeDivEntryIterable}
        </div>
      );
  
      traverseAllChildren(instance.props.children, traverseFn, traverseContext);
      expect(traverseFn.calls.length).toBe(3);
  
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[0],
        '.$#1:0'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[1],
        '.$#2:0'
      );
      expect(traverseFn).toHaveBeenCalledWith(
        traverseContext,
        traverseContext[2],
        '.$#3:0'
      );
  
      expect(console.error.argsForCall.length).toBe(1);
      expect(console.error.argsForCall[0][0]).toContain(
        'Warning: Using Maps as children is not yet fully supported. It is an ' +
        'experimental feature that might be removed. Convert it to a sequence ' +
        '/ iterable of keyed ReactElements instead.'
      );
    });
  
    it('should not enumerate enumerable numbers (#4776)', function() {
      /*eslint-disable no-extend-native */
      Number.prototype['@@iterator'] = function() {
        throw new Error('number iterator called');
      };
      /*eslint-enable no-extend-native */
  
      try {
        var instance = (
          <div>
            {5}
            {12}
            {13}
          </div>
        );
  
        var traverseFn = jasmine.createSpy();
  
        traverseAllChildren(instance.props.children, traverseFn, null);
        expect(traverseFn.calls.length).toBe(3);
  
        expect(traverseFn).toHaveBeenCalledWith(
          null,
          5,
          '.0'
        );
        expect(traverseFn).toHaveBeenCalledWith(
          null,
          12,
          '.1'
        );
        expect(traverseFn).toHaveBeenCalledWith(
          null,
          13,
          '.2'
        );
      } finally {
        delete Number.prototype['@@iterator'];
      }
    });
  
    it('should throw on object', function() {
      expect(function() {
        traverseAllChildren({a: 1, b: 2}, function() {}, null);
      }).toThrow(
        'Objects are not valid as a React child (found: object with keys ' +
        '{a, b}). If you meant to render a collection of children, use an ' +
        'array instead or wrap the object using createFragment(object) from ' +
        'the React add-ons.'
      );
    });
  
    it('should throw on regex', function() {
      // Really, we care about dates (#4840) but those have nondeterministic
      // serialization (timezones) so let's test a regex instead:
      expect(function() {
        traverseAllChildren(/abc/, function() {}, null);
      }).toThrow(
        'Objects are not valid as a React child (found: /abc/). If you meant ' +
        'to render a collection of children, use an array instead or wrap the ' +
        'object using createFragment(object) from the React add-ons.'
      );
    });
  
  });
  