diff options
| author | Igor Minar | 2012-11-23 16:08:47 +0100 |
|---|---|---|
| committer | Igor Minar | 2012-11-26 20:39:10 +0100 |
| commit | 6e2c38f54dc012dc919cdd7f7ab9b73dc1e99c66 (patch) | |
| tree | 96c03d2b961feb5d3b9978538a1ac7e437a0184c /test/ng/directive | |
| parent | 00e7e3141819e14ced3279fa5dfb8eba4ff89e5f (diff) | |
| download | angular.js-6e2c38f54dc012dc919cdd7f7ab9b73dc1e99c66.tar.bz2 | |
test(ngRepeat): clean up and improve tests
Diffstat (limited to 'test/ng/directive')
| -rw-r--r-- | test/ng/directive/ngRepeatSpec.js | 'use strict'; // NOTE: The usage of window and document instead of $window and $document here is // deliberate. This service depends on the specific behavior of anchor nodes created by the // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and // cause us to break tests. In addition, when the browser resolves a URL for XHR, it // doesn't know about mocked locations and resolves URLs to the real document - which is // exactly the behavior needed here. There is little value is mocking these out for this // service. var urlParsingNode = document.createElement("a"); var originUrl = urlResolve(window.location.href, true); /** * * Implementation Notes for non-IE browsers * ---------------------------------------- * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM, * results both in the normalizing and parsing of the URL. Normalizing means that a relative * URL will be resolved into an absolute URL in the context of the application document. * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related * properties are all populated to reflect the normalized URL. This approach has wide * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc. See * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html * * Implementation Notes for IE * --------------------------- * IE >= 8 and <= 10 normalizes the URL when assigned to the anchor node similar to the other * browsers. However, the parsed components will not be set if the URL assigned did not specify * them. (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.) We * work around that by performing the parsing in a 2nd step by taking a previously normalized * URL (e.g. by assining to a.href) and assigning it a.href again. This correctly populates the * properties such as protocol, hostname, port, etc. * * IE7 does not normalize the URL when assigned to an anchor node. (Apparently, it does, if one * uses the inner HTML approach to assign the URL as part of an HTML snippet - * http://stackoverflow.com/a/472729) However, setting img[src] does normalize the URL. * Unfortunately, setting img[src] to something like "javascript:foo" on IE throws an exception. * Since the primary usage for normalizing URLs is to sanitize such URLs, we can't use that * method and IE < 8 is unsupported. * * References: * http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html * http://url.spec.whatwg.org/#urlutils * https://github.com/angular/angular.js/pull/2902 * http://james.padolsey.com/javascript/parsing-urls-with-the-dom/ * * @function * @param {string} url The URL to be parsed. * @description Normalizes and parses a URL. * @returns {object} Returns the normalized URL as a dictionary. * * | member name | Description | * |---------------|----------------| * | href | A normalized version of the provided URL if it was not an absolute URL | * | protocol | The protocol including the trailing colon | * | host | The host and port (if the port is non-default) of the normalizedUrl | * | search | The search params, minus the question mark | * | hash | The hash string, minus the hash symbol * | hostname | The hostname * | port | The port, without ":" * | pathname | The pathname, beginning with "/" * */ function urlResolve(url) { var href = url; if (msie) { // Normalize before parse. Refer Implementation Notes on why this is // done in two steps on IE. urlParsingNode.setAttribute("href", href); href = urlParsingNode.href; } urlParsingNode.setAttribute('href', href); // $$urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils return { href: urlParsingNode.href, protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', host: urlParsingNode.host, search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', hostname: urlParsingNode.hostname, port: urlParsingNode.port, pathname: urlParsingNode.pathname && urlParsingNode.pathname.charAt(0) === '/' ? urlParsingNode.pathname : '/' + urlParsingNode.pathname }; } /** * Parse a request URL and determine whether this is a same-origin request as the application document. * * @param {string|object} requestUrl The url of the request as a string that will be resolved * or a parsed URL object. * @returns {boolean} Whether the request is for the same origin as the application document. */ function urlIsSameOrigin(requestUrl) { var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl; return (parsed.protocol === originUrl.protocol && parsed.host === originUrl.host); }v> - $rootScope.items = {misko: true, shyam: true, zhenbo:true}; - $rootScope.$digest(); + scope.items = {misko: true, shyam: true, zhenbo:true}; + scope.$digest(); expect(element.find('li').length).toEqual(3); expect(element.text()).toEqual('misko:true;shyam:true;zhenbo:true;'); @@ -166,216 +173,214 @@ describe('ngRepeat', function() { expect(element.find('input')[1].checked).toBe(false); expect(element.find('input')[2].checked).toBe(true); - $rootScope.items = {misko: false, shyam: true, zhenbo: true}; - $rootScope.$digest(); + scope.items = {misko: false, shyam: true, zhenbo: true}; + scope.$digest(); expect(element.text()).toEqual('misko:false;shyam:true;zhenbo:true;'); expect(element.find('input')[0].checked).toBe(false); expect(element.find('input')[1].checked).toBe(true); expect(element.find('input')[2].checked).toBe(true); - })); + }); - it('should not ngRepeat over parent properties', inject(function($rootScope, $compile) { + it('should not ngRepeat over parent properties', function() { var Class = function() {}; Class.prototype.abc = function() {}; Class.prototype.value = 'abc'; element = $compile( '<ul>' + - '<li ng-repeat="(key, value) in items" ng-bind="key + \':\' + value + \';\' "></li>' + - '</ul>')($rootScope); - $rootScope.items = new Class(); - $rootScope.items.name = 'value'; - $rootScope.$digest(); + '<li ng-repeat="(key, value) in items">{{key}}:{{value}};</li>' + + '</ul>')(scope); + scope.items = new Class(); + scope.items.name = 'value'; + scope.$digest(); expect(element.text()).toEqual('name:value;'); - })); + }); - it('should error on wrong parsing of ngRepeat', inject(function($rootScope, $compile) { + it('should error on wrong parsing of ngRepeat', function() { expect(function() { - element = $compile('<ul><li ng-repeat="i dont parse"></li></ul>')($rootScope); + element = jqLite('<ul><li ng-repeat="i dont parse"></li></ul>'); + $compile(element)(scope); }).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) { + it("should throw error when left-hand-side of ngRepeat can't be parsed", function() { expect(function() { - element = $compile('<ul><li ng-repeat="i dont parse in foo"></li></ul>')($rootScope); + element = jqLite('<ul><li ng-repeat="i dont parse in foo"></li></ul>'); + $compile(element)(scope); }).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) { + function() { element = $compile( '<ul>' + - '<li ng-repeat="item in items" ng-bind="item + $index + \'|\'"></li>' + - '</ul>')($rootScope); - $rootScope.items = ['misko', 'shyam', 'frodo']; - $rootScope.$digest(); - expect(element.text()).toEqual('misko0|shyam1|frodo2|'); - })); + '<li ng-repeat="item in items">{{item}}:{{$index}}|</li>' + + '</ul>')(scope); + scope.items = ['misko', 'shyam', 'frodo']; + scope.$digest(); + expect(element.text()).toEqual('misko:0|shyam:1|frodo:2|'); + }); - it('should expose iterator offset as $index when iterating over objects', - inject(function($rootScope, $compile) { + it('should expose iterator offset as $index when iterating over objects', function() { element = $compile( '<ul>' + - '<li ng-repeat="(key, val) in items" ng-bind="key + \':\' + val + $index + \'|\'"></li>' + - '</ul>')($rootScope); - $rootScope.items = {'misko':'m', 'shyam':'s', 'frodo':'f'}; - $rootScope.$digest(); - expect(element.text()).toEqual('frodo:f0|misko:m1|shyam:s2|'); - })); + '<li ng-repeat="(key, val) in items">{{key}}:{{val}}:{{$index}}|</li>' + + '</ul>')(scope); + scope.items = {'misko':'m', 'shyam':'s', 'frodo':'f'}; + scope.$digest(); + expect(element.text()).toEqual('frodo:f:0|misko:m:1|shyam:s:2|'); + }); it('should expose iterator position as $first, $middle and $last when iterating over arrays', - inject(function($rootScope, $compile) { + function() { element = $compile( '<ul>' + '<li ng-repeat="item in items">{{item}}:{{$first}}-{{$middle}}-{{$last}}|</li>' + - '</ul>')($rootScope); - $rootScope.items = ['misko', 'shyam', 'doug']; - $rootScope.$digest(); + '</ul>')(scope); + scope.items = ['misko', 'shyam', 'doug']; + scope.$digest(); expect(element.text()). toEqual('misko:true-false-false|shyam:false-true-false|doug:false-false-true|'); - $rootScope.items.push('frodo'); - $rootScope.$digest(); + scope.items.push('frodo'); + scope.$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(); + scope.items.pop(); + scope.items.pop(); + scope.$digest(); expect(element.text()).toEqual('misko:true-false-false|shyam:false-false-true|'); - $rootScope.items.pop(); - $rootScope.$digest(); + scope.items.pop(); + scope.$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) { + function() { element = $compile( '<ul>' + '<li ng-repeat="(key, val) in items">{{key}}:{{val}}:{{$first}}-{{$middle}}-{{$last}}|</li>' + - '</ul>')($rootScope); - $rootScope.items = {'misko':'m', 'shyam':'s', 'doug':'d', 'frodo':'f'}; - $rootScope.$digest(); + '</ul>')(scope); + scope.items = {'misko':'m', 'shyam':'s', 'doug':'d', 'frodo':'f'}; + scope.$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(); + delete scope.items.doug; + delete scope.items.frodo; + scope.$digest(); expect(element.text()).toEqual('misko:m:true-false-false|shyam:s:false-false-true|'); - delete $rootScope.items.shyam; - $rootScope.$digest(); + delete scope.items.shyam; + scope.$digest(); expect(element.text()).toEqual('misko:m:true-false-true|'); - })); + }); - it('should ignore $ and $$ properties', inject(function($rootScope, $compile) { - element = $compile('<ul><li ng-repeat="i in items">{{i}}|</li></ul>')($rootScope); - $rootScope.items = ['a', 'b', 'c']; - $rootScope.items.$$hashkey = 'xxx'; - $rootScope.items.$root = 'yyy'; - $rootScope.$digest(); + it('should ignore $ and $$ properties', function() { + element = $compile('<ul><li ng-repeat="i in items">{{i}}|</li></ul>')(scope); + scope.items = ['a', 'b', 'c']; + scope.items.$$hashkey = 'xxx'; + scope.items.$root = 'yyy'; + scope.$digest(); expect(element.text()).toEqual('a|b|c|'); - })); + }); - it('should repeat over nested arrays', inject(function($rootScope, $compile) { + it('should repeat over nested arrays', function() { element = $compile( '<ul>' + '<li ng-repeat="subgroup in groups">' + '<div ng-repeat="group in subgroup">{{group}}|</div>X' + '</li>' + - '</ul>')($rootScope); - $rootScope.groups = [['a', 'b'], ['c','d']]; - $rootScope.$digest(); + '</ul>')(scope); + scope.groups = [['a', 'b'], ['c','d']]; + scope.$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('<ul><li ng-repeat="item in array">{{item}}|</li></ul>')($rootScope); - $rootScope.array = ['a', 'b', 'c']; - $rootScope.array.foo = '23'; - $rootScope.array.bar = function() {}; - $rootScope.$digest(); + it('should ignore non-array element properties when iterating over an array', function() { + element = $compile('<ul><li ng-repeat="item in array">{{item}}|</li></ul>')(scope); + scope.array = ['a', 'b', 'c']; + scope.array.foo = '23'; + scope.array.bar = function() {}; + scope.$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('<ul><li ng-repeat="item in array">{{item}}|</li></ul>')($rootScope); - $rootScope.array = ['a', 'b']; - $rootScope.array[4] = 'c'; - $rootScope.array[6] = 'd'; - $rootScope.$digest(); + it('should iterate over non-existent elements of a sparse array', function() { + element = $compile('<ul><li ng-repeat="item in array">{{item}}|</li></ul>')(scope); + scope.array = ['a', 'b']; + scope.array[4] = 'c'; + scope.array[6] = 'd'; + scope.$digest(); expect(element.text()).toBe('a|b|||c||d|'); - })); + }); - it('should iterate over all kinds of types', inject(function($rootScope, $compile) { - element = $compile('<ul><li ng-repeat="item in array">{{item}}|</li></ul>')($rootScope); - $rootScope.array = ['a', 1, null, undefined, {}]; - $rootScope.$digest(); + it('should iterate over all kinds of types', function() { + element = $compile('<ul><li ng-repeat="item in array">{{item}}|</li></ul>')(scope); + scope.array = ['a', 1, null, undefined, {}]; + scope.$digest(); expect(element.text()).toMatch(/a\|1\|\|\|\{\s*\}\|/); - })); + }); describe('stability', function() { var a, b, c, d, lis; - beforeEach(inject(function($rootScope, $compile) { + beforeEach(function() { element = $compile( '<ul>' + '<li ng-repeat="item in items">{{key}}:{{val}}|></li>' + - '</ul>')($rootScope); + '</ul>')(scope); a = {}; b = {}; c = {}; d = {}; - $rootScope.items = [a, b, c]; - $rootScope.$digest(); + scope.items = [a, b, c]; + scope.$digest(); lis = element.find('li'); - })); + }); - it('should preserve the order of elements', inject(function($rootScope) { - $rootScope.items = [a, c, d]; - $rootScope.$digest(); + it('should preserve the order of elements', function() { + scope.items = [a, c, d]; + scope.$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(); + it('should support duplicates', function() { + scope.items = [a, a, b, c]; + scope.$digest(); var newElements = element.find('li'); expect(newElements[0]).toEqual(lis[0]); expect(newElements[1]).not.toEqual(lis[0]); @@ -383,50 +388,48 @@ describe('ngRepeat', function() { expect(newElements[3]).toEqual(lis[2]); lis = newElements; - $rootScope.$digest(); + scope.$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(); + scope.$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(); + it('should remove last item when one duplicate instance is removed', function() { + scope.items = [a, a, a]; + scope.$digest(); lis = element.find('li'); - $rootScope.items = [a, a]; - $rootScope.$digest(); + scope.items = [a, a]; + scope.$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(); + it('should reverse items when the collection is reversed', function() { + scope.items = [a, b, c]; + scope.$digest(); lis = element.find('li'); - $rootScope.items = [c, b, a]; - $rootScope.$digest(); + scope.items = [c, b, a]; + scope.$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]); - })); + }); }); }); |
