'use strict'; describe('ngRepeat', function() { var element; afterEach(function(){ dealoc(element); }); it('should ngRepeat over array', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); Array.prototype.extraProperty = "should be ignored"; // INIT $rootScope.items = ['misko', 'shyam']; $rootScope.$digest(); expect(element.find('li').length).toEqual(2); expect(element.text()).toEqual('misko;shyam;'); delete Array.prototype.extraProperty; // GROW $rootScope.items = ['adam', 'kai', 'brad']; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('adam;kai;brad;'); // SHRINK $rootScope.items = ['brad']; $rootScope.$digest(); expect(element.find('li').length).toEqual(1); expect(element.text()).toEqual('brad;'); })); it('should ngRepeat over array of primitive correctly', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); Array.prototype.extraProperty = "should be ignored"; // INIT $rootScope.items = [true, true, true]; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('true;true;true;'); delete Array.prototype.extraProperty; $rootScope.items = [false, true, true]; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('false;true;true;'); $rootScope.items = [false, true, false]; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('false;true;false;'); $rootScope.items = [true]; $rootScope.$digest(); expect(element.find('li').length).toEqual(1); expect(element.text()).toEqual('true;'); $rootScope.items = [true, true, false]; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('true;true;false;'); $rootScope.items = [true, false, false]; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('true;false;false;'); // string $rootScope.items = ['a', 'a', 'a']; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('a;a;a;'); $rootScope.items = ['ab', 'a', 'a']; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('ab;a;a;'); $rootScope.items = ['test']; $rootScope.$digest(); expect(element.find('li').length).toEqual(1); expect(element.text()).toEqual('test;'); $rootScope.items = ['same', 'value']; $rootScope.$digest(); expect(element.find('li').length).toEqual(2); expect(element.text()).toEqual('same;value;'); // number $rootScope.items = [12, 12, 12]; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('12;12;12;'); $rootScope.items = [53, 12, 27]; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('53;12;27;'); $rootScope.items = [89]; $rootScope.$digest(); expect(element.find('li').length).toEqual(1); expect(element.text()).toEqual('89;'); $rootScope.items = [89, 23]; $rootScope.$digest(); expect(element.find('li').length).toEqual(2); expect(element.text()).toEqual('89;23;'); })); it('should ngRepeat over object', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); $rootScope.items = {misko:'swe', shyam:'set'}; $rootScope.$digest(); expect(element.text()).toEqual('misko:swe;shyam:set;'); })); it('should ngRepeat over object with primitive value correctly', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); $rootScope.items = {misko:'true', shyam:'true', zhenbo: 'true'}; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('misko:true;shyam:true;zhenbo:true;'); $rootScope.items = {misko:'false', shyam:'true', zhenbo: 'true'}; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('misko:false;shyam:true;zhenbo:true;'); $rootScope.items = {misko:'false', shyam:'false', zhenbo: 'false'}; $rootScope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('misko:false;shyam:false;zhenbo:false;'); $rootScope.items = {misko:'true'}; $rootScope.$digest(); expect(element.find('li').length).toEqual(1); expect(element.text()).toEqual('misko:true;'); $rootScope.items = {shyam:'true', zhenbo: 'false'}; $rootScope.$digest(); expect(element.find('li').length).toEqual(2); expect(element.text()).toEqual('shyam:true;zhenbo:false;'); })); it('should not ngRepeat over parent properties', inject(function($rootScope, $compile) { var Class = function() {}; Class.prototype.abc = function() {}; Class.prototype.value = 'abc'; element = $compile( '')($rootScope); $rootScope.items = new Class(); $rootScope.items.name = 'value'; $rootScope.$digest(); expect(element.text()).toEqual('name:value;'); })); it('should error on wrong parsing of ngRepeat', inject(function($rootScope, $compile) { expect(function() { element = $compile('')($rootScope); }).toThrow("Expected ngRepeat in form of '_item_ in _collection_' but got 'i dont parse'."); })); it("should throw error when left-hand-side of ngRepeat can't be parsed", inject( function($rootScope, $compile) { expect(function() { element = $compile('')($rootScope); }).toThrow("'item' in 'item in collection' should be identifier or (key, value) but got " + "'i dont parse'."); })); it('should expose iterator offset as $index when iterating over arrays', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); $rootScope.items = ['misko', 'shyam', 'frodo']; $rootScope.$digest(); expect(element.text()).toEqual('misko0|shyam1|frodo2|'); })); it('should expose iterator offset as $index when iterating over objects', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); $rootScope.items = {'misko':'m', 'shyam':'s', 'frodo':'f'}; $rootScope.$digest(); expect(element.text()).toEqual('frodo:f0|misko:m1|shyam:s2|'); })); it('should expose iterator position as $first, $middle and $last when iterating over arrays', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); $rootScope.items = ['misko', 'shyam', 'doug']; $rootScope.$digest(); expect(element.text()). toEqual('misko:true-false-false|shyam:false-true-false|doug:false-false-true|'); $rootScope.items.push('frodo'); $rootScope.$digest(); expect(element.text()). toEqual('misko:true-false-false|' + 'shyam:false-true-false|' + 'doug:false-true-false|' + 'frodo:false-false-true|'); $rootScope.items.pop(); $rootScope.items.pop(); $rootScope.$digest(); expect(element.text()).toEqual('misko:true-false-false|shyam:false-false-true|'); $rootScope.items.pop(); $rootScope.$digest(); expect(element.text()).toEqual('misko:true-false-true|'); })); it('should expose iterator position as $first, $middle and $last when iterating over objects', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); $rootScope.items = {'misko':'m', 'shyam':'s', 'doug':'d', 'frodo':'f'}; $rootScope.$digest(); expect(element.text()). toEqual('doug:d:true-false-false|' + 'frodo:f:false-true-false|' + 'misko:m:false-true-false|' + 'shyam:s:false-false-true|'); delete $rootScope.items.doug; delete $rootScope.items.frodo; $rootScope.$digest(); expect(element.text()).toEqual('misko:m:true-false-false|shyam:s:false-false-true|'); delete $rootScope.items.shyam; $rootScope.$digest(); expect(element.text()).toEqual('misko:m:true-false-true|'); })); it('should ignore $ and $$ properties', inject(function($rootScope, $compile) { element = $compile('')($rootScope); $rootScope.items = ['a', 'b', 'c']; $rootScope.items.$$hashkey = 'xxx'; $rootScope.items.$root = 'yyy'; $rootScope.$digest(); expect(element.text()).toEqual('a|b|c|'); })); it('should repeat over nested arrays', inject(function($rootScope, $compile) { element = $compile( '')($rootScope); $rootScope.groups = [['a', 'b'], ['c','d']]; $rootScope.$digest(); expect(element.text()).toEqual('a|b|Xc|d|X'); })); it('should ignore non-array element properties when iterating over an array', inject(function($rootScope, $compile) { element = $compile('')($rootScope); $rootScope.array = ['a', 'b', 'c']; $rootScope.array.foo = '23'; $rootScope.array.bar = function() {}; $rootScope.$digest(); expect(element.text()).toBe('a|b|c|'); })); it('should iterate over non-existent elements of a sparse array', inject(function($rootScope, $compile) { element = $compile('')($rootScope); $rootScope.array = ['a', 'b']; $rootScope.array[4] = 'c'; $rootScope.array[6] = 'd'; $rootScope.$digest(); expect(element.text()).toBe('a|b|||c||d|'); })); it('should iterate over all kinds of types', inject(function($rootScope, $compile) { element = $compile('')($rootScope); $rootScope.array = ['a', 1, null, undefined, {}]; $rootScope.$digest(); expect(element.text()).toMatch(/a\|1\|\|\|\{\s*\}\|/); })); describe('stability', function() { var a, b, c, d, lis; beforeEach(inject(function($rootScope, $compile) { element = $compile( '')($rootScope); a = {}; b = {}; c = {}; d = {}; $rootScope.items = [a, b, c]; $rootScope.$digest(); lis = element.find('li'); })); it('should preserve the order of elements', inject(function($rootScope) { $rootScope.items = [a, c, d]; $rootScope.$digest(); var newElements = element.find('li'); expect(newElements[0]).toEqual(lis[0]); expect(newElements[1]).toEqual(lis[2]); expect(newElements[2]).not.toEqual(lis[1]); })); it('should support duplicates', inject(function($rootScope) { $rootScope.items = [a, a, b, c]; $rootScope.$digest(); var newElements = element.find('li'); expect(newElements[0]).toEqual(lis[0]); expect(newElements[1]).not.toEqual(lis[0]); expect(newElements[2]).toEqual(lis[1]); expect(newElements[3]).toEqual(lis[2]); lis = newElements; $rootScope.$digest(); newElements = element.find('li'); expect(newElements[0]).toEqual(lis[0]); expect(newElements[1]).toEqual(lis[1]); expect(newElements[2]).toEqual(lis[2]); expect(newElements[3]).toEqual(lis[3]); $rootScope.$digest(); newElements = element.find('li'); expect(newElements[0]).toEqual(lis[0]); expect(newElements[1]).toEqual(lis[1]); expect(newElements[2]).toEqual(lis[2]); expect(newElements[3]).toEqual(lis[3]); })); it('should remove last item when one duplicate instance is removed', inject(function($rootScope) { $rootScope.items = [a, a, a]; $rootScope.$digest(); lis = element.find('li'); $rootScope.items = [a, a]; $rootScope.$digest(); var newElements = element.find('li'); expect(newElements.length).toEqual(2); expect(newElements[0]).toEqual(lis[0]); expect(newElements[1]).toEqual(lis[1]); })); it('should reverse items when the collection is reversed', inject(function($rootScope) { $rootScope.items = [a, b, c]; $rootScope.$digest(); lis = element.find('li'); $rootScope.items = [c, b, a]; $rootScope.$digest(); var newElements = element.find('li'); expect(newElements.length).toEqual(3); expect(newElements[0]).toEqual(lis[2]); expect(newElements[1]).toEqual(lis[1]); expect(newElements[2]).toEqual(lis[0]); })); }); });