diff --git a/src/core/__tests__/ReactComponentFlattenChildren-test.js b/src/core/__tests__/ReactComponentFlattenChildren-test.js new file mode 100644 index 0000000000..972172c541 --- /dev/null +++ b/src/core/__tests__/ReactComponentFlattenChildren-test.js @@ -0,0 +1,159 @@ +/** + * Copyright 2013 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @jsx React.DOM + * @emails react-core + */ + +"use strict"; + +var React; + +var Fake; + +var singleChild = function(children) { + return ({children}).props.children; +}; + +var multiChild = function(child1, child2, child3, child4) { + return ({child1} {child2} {child3}{child4}).props.children; +}; + + +describe('ReactComponentFlatten', function() { + beforeEach(function() { + require('mock-modules').dumpCache(); + React = require('React'); + var ReactComponent = require('ReactComponent'); + var copyProperties = require('copyProperties'); + var Constructor = function() {}; + copyProperties(Constructor.prototype, ReactComponent.Mixin); + Fake = function() { + var instance = new Constructor(); + instance.construct.apply(instance, arguments); + return instance; + }; + }); + + it("should reuse a flat array", function() { + var children = [ +
, +
+ ]; + + var flat = singleChild(children); + + expect(flat).toBe(children); + expect(flat[0]._key).toEqual('0:foo'); + expect(flat[1]._key).toEqual('0:bar'); + }); + + it("should collapse a sparse array", function() { + var children = [ + null, +
, +
+ ]; + + var flat = singleChild(children); + + expect(flat).not.toBe(children); + expect(flat.length).toEqual(2); + expect(flat[0]._key).toEqual('0:foo'); + expect(flat[1]._key).toEqual('0:bar'); + }); + + it("should collapse a nested array into a flat array", function() { + var flat = multiChild( + null, +
, + [
, null] + ); + + expect(flat.length).toEqual(2); + expect(flat[0]._key).toEqual('foo'); + expect(flat[1]._key).toEqual('2:bar'); + }); + + it("should use retain key index despite static empty values", function() { + // TODO: Wrap in another single child (currently breaks) + + var before = multiChild( +
, +
, + [
], + [
] + ); + + var after = multiChild( + null, +
, + null, + [
] + ); + + expect(before.length).toEqual(4); + expect(after.length).toEqual(2); + expect(before[1]._key).toEqual(after[0]._key); + expect(before[3]._key).toEqual(after[1]._key); + }); + + it("should assign idempotent keys for extra flattening layers", function() { + var flat = multiChild( + null, + [null,
], + false + ); + + var preFlat = multiChild( + null, + singleChild([null,
]), + false + ); + + expect(flat.length).toBe(1); + expect(preFlat.length).toBe(1); + expect(preFlat[0]._key).toBe(flat[0]._key); + }); + + it("should assign idempotent strings through flattening", function() { + var children = [ + 'FOO', + 'BAR' + ]; + var flat = singleChild(children); + var wrappedFlat = multiChild(null, flat); + expect(flat).toBe(children); + expect(wrappedFlat.length).toBe(2); + expect(wrappedFlat[0]).toBe(flat[0]); + expect(wrappedFlat[1]).toBe(flat[1]); + }); + + it("cannot keep keys unique when children are unboxed", function() { + // This is a case that difficult to solve and should not actually be solved. + var children1 = [
]; + var children2 = [
]; + var flat1 = singleChild(children1); + var flat2 = singleChild(children2); + // There's no way to tell flat1[0] and flat2[0] apart. + var mergedChildren = [flat1[0], flat2[0]]; + var newChildren = multiChild(mergedChildren); + expect(newChildren.length).toBe(2); + expect(newChildren[0]._key).toBe(newChildren[1]._key); + }); + +}); + + diff --git a/src/core/__tests__/ReactIdentity-test.js b/src/core/__tests__/ReactIdentity-test.js index 36dffd8391..ee3f88487f 100644 --- a/src/core/__tests__/ReactIdentity-test.js +++ b/src/core/__tests__/ReactIdentity-test.js @@ -67,8 +67,8 @@ describe('ReactIdentity', function() { React.renderComponent(instance, document.createElement('div')); var node = instance.getDOMNode(); reactComponentExpect(instance).toBeDOMComponentWithChildCount(2); - checkId(node.childNodes[0], '.reactRoot[0].[0:apple]'); - checkId(node.childNodes[1], '.reactRoot[0].[0:banana]'); + checkId(node.childNodes[0], '.reactRoot[0].[apple]'); + checkId(node.childNodes[1], '.reactRoot[0].[banana]'); }); it('should use instance identity', function() { @@ -89,15 +89,15 @@ describe('ReactIdentity', function() { React.renderComponent(instance, document.createElement('div')); var node = instance.getDOMNode(); reactComponentExpect(instance).toBeDOMComponentWithChildCount(3); - checkId(node.childNodes[0], '.reactRoot[0].[0:wrap1]'); + checkId(node.childNodes[0], '.reactRoot[0].[wrap1]'); checkId( node.childNodes[0].firstChild, - '.reactRoot[0].[0:wrap1].[0:squirrel]' + '.reactRoot[0].[wrap1].[0:squirrel]' ); - checkId(node.childNodes[1], '.reactRoot[0].[0:wrap2]'); - checkId(node.childNodes[1].firstChild, '.reactRoot[0].[0:wrap2].[0:bunny]'); - checkId(node.childNodes[2], '.reactRoot[0].[0:2]'); - checkId(node.childNodes[2].firstChild, '.reactRoot[0].[0:2].[0:chipmunk]'); + checkId(node.childNodes[1], '.reactRoot[0].[wrap2]'); + checkId(node.childNodes[1].firstChild, '.reactRoot[0].[wrap2].[0:bunny]'); + checkId(node.childNodes[2], '.reactRoot[0].[2]'); + checkId(node.childNodes[2].firstChild, '.reactRoot[0].[2].[0:chipmunk]'); }); it('should let restructured components retain their uniqueness', function() { diff --git a/src/utils/__tests__/mapChildren-test.js b/src/utils/__tests__/mapChildren-test.js index 21abf64110..39f557f38e 100644 --- a/src/utils/__tests__/mapChildren-test.js +++ b/src/utils/__tests__/mapChildren-test.js @@ -122,12 +122,12 @@ describe('mapChildren', function() { .instance(); expect(mapFn.calls.length).toBe(3); - expect(mapFn).toHaveBeenCalledWith(kidOne, '0:one', 0); - expect(mapFn).toHaveBeenCalledWith(kidTwo, '0:two', 1); - expect(mapFn).toHaveBeenCalledWith(kidThree, '0:three', 2); + expect(mapFn).toHaveBeenCalledWith(kidOne, 'one', 0); + expect(mapFn).toHaveBeenCalledWith(kidTwo, 'two', 1); + expect(mapFn).toHaveBeenCalledWith(kidThree, 'three', 2); expect(rendered.props.children).not.toEqual(instance.props.children); expect(rendered.props.children).toHaveKeys([ - '0:0:one', '0:0:two', '0:0:three' + '0:one', '0:two', '0:three' ]); }); });