diff options
| author | Misko Hevery | 2012-03-23 14:03:24 -0700 |
|---|---|---|
| committer | Misko Hevery | 2012-03-28 11:16:35 -0700 |
| commit | 2430f52bb97fa9d682e5f028c977c5bf94c5ec38 (patch) | |
| tree | e7529b741d70199f36d52090b430510bad07f233 /test/service | |
| parent | 944098a4e0f753f06b40c73ca3e79991cec6c2e2 (diff) | |
| download | angular.js-2430f52bb97fa9d682e5f028c977c5bf94c5ec38.tar.bz2 | |
chore(module): move files around in preparation for more modules
Diffstat (limited to 'test/service')
28 files changed, 0 insertions, 9180 deletions
diff --git a/test/service/anchorScrollSpec.js b/test/service/anchorScrollSpec.js deleted file mode 100644 index 7e4b3aa3..00000000 --- a/test/service/anchorScrollSpec.js +++ /dev/null @@ -1,186 +0,0 @@ -describe('$anchorScroll', function() { - - var elmSpy; - - function addElements() { - var elements = sliceArgs(arguments); - - return function() { - forEach(elements, function(identifier) { - var match = identifier.match(/(\w* )?(\w*)=(\w*)/), - jqElm = jqLite('<' + (match[1] || 'a ') + match[2] + '="' + match[3] + '"/>'), - elm = jqElm[0]; - - elmSpy[identifier] = spyOn(elm, 'scrollIntoView'); - jqLite(document.body).append(jqElm); - }); - }; - } - - function changeHashAndScroll(hash) { - return function($location, $anchorScroll) { - $location.hash(hash); - $anchorScroll(); - }; - } - - function expectScrollingToTop($window) { - forEach(elmSpy, function(spy, id) { - expect(spy).not.toHaveBeenCalled(); - }); - - expect($window.scrollTo).toHaveBeenCalledWith(0, 0); - } - - function expectScrollingTo(identifier) { - return function($window) { - forEach(elmSpy, function(spy, id) { - if (identifier === id) expect(spy).toHaveBeenCalledOnce(); - else expect(spy).not.toHaveBeenCalled(); - }); - expect($window.scrollTo).not.toHaveBeenCalled(); - }; - } - - function expectNoScrolling() { - return expectScrollingTo(NaN); - } - - - beforeEach(module(function($provide) { - elmSpy = {}; - $provide.value('$window', { - scrollTo: jasmine.createSpy('$window.scrollTo'), - document: document - }); - })); - - - it('should scroll to top of the window if empty hash', inject( - changeHashAndScroll(''), - expectScrollingToTop)); - - - it('should not scroll if hash does not match any element', inject( - addElements('id=one', 'id=two'), - changeHashAndScroll('non-existing'), - expectNoScrolling())); - - - it('should scroll to anchor element with name', inject( - addElements('a name=abc'), - changeHashAndScroll('abc'), - expectScrollingTo('a name=abc'))); - - - it('should not scroll to other than anchor element with name', inject( - addElements('input name=xxl', 'select name=xxl', 'form name=xxl'), - changeHashAndScroll('xxl'), - expectNoScrolling())); - - - it('should scroll to anchor even if other element with given name exist', inject( - addElements('input name=some', 'a name=some'), - changeHashAndScroll('some'), - expectScrollingTo('a name=some'))); - - - it('should scroll to element with id with precedence over name', inject( - addElements('name=abc', 'id=abc'), - changeHashAndScroll('abc'), - expectScrollingTo('id=abc'))); - - - it('should scroll to top if hash == "top" and no matching element', inject( - changeHashAndScroll('top'), - expectScrollingToTop)); - - - it('should scroll to element with id "top" if present', inject( - addElements('id=top'), - changeHashAndScroll('top'), - expectScrollingTo('id=top'))); - - - describe('watcher', function() { - - function initLocation(config) { - return function($provide, $locationProvider) { - $provide.value('$sniffer', {history: config.historyApi}); - $locationProvider.html5Mode(config.html5Mode); - }; - } - - function changeHashTo(hash) { - return function ($location, $rootScope, $anchorScroll) { - $rootScope.$apply(function() { - $location.hash(hash); - }); - }; - } - - function disableAutoScrolling() { - return function($anchorScrollProvider) { - $anchorScrollProvider.disableAutoScrolling(); - }; - } - - afterEach(inject(function($document) { - dealoc($document); - })); - - - it('should scroll to element when hash change in hashbang mode', function() { - module(initLocation({html5Mode: false, historyApi: true})); - inject( - addElements('id=some'), - changeHashTo('some'), - expectScrollingTo('id=some') - ); - }); - - - it('should scroll to element when hash change in html5 mode with no history api', function() { - module(initLocation({html5Mode: true, historyApi: false})); - inject( - addElements('id=some'), - changeHashTo('some'), - expectScrollingTo('id=some') - ); - }); - - - it('should not scroll when element does not exist', function() { - module(initLocation({html5Mode: false, historyApi: false})); - inject( - addElements('id=some'), - changeHashTo('other'), - expectNoScrolling() - ); - }); - - - it('should scroll when html5 mode with history api', function() { - module(initLocation({html5Mode: true, historyApi: true})); - inject( - addElements('id=some'), - changeHashTo('some'), - expectScrollingTo('id=some') - ); - }); - - - it('should not scroll when disabled', function() { - module( - disableAutoScrolling(), - initLocation({html5Mode: false, historyApi: false}) - ); - inject( - addElements('id=fake'), - changeHashTo('fake'), - expectNoScrolling() - ); - }); - }); -}); - diff --git a/test/service/browserSpecs.js b/test/service/browserSpecs.js deleted file mode 100644 index 4563d14b..00000000 --- a/test/service/browserSpecs.js +++ /dev/null @@ -1,578 +0,0 @@ -'use strict'; - -function MockWindow() { - var events = {}; - var timeouts = this.timeouts = []; - - this.setTimeout = function(fn) { - return timeouts.push(fn) - 1; - }; - - this.clearTimeout = function(id) { - timeouts[id] = noop; - }; - - this.setTimeout.flush = function() { - var length = timeouts.length; - while (length-- > 0) timeouts.shift()(); - }; - - this.addEventListener = function(name, listener) { - if (isUndefined(events[name])) events[name] = []; - events[name].push(listener); - }; - - this.attachEvent = function(name, listener) { - this.addEventListener(name.substr(2), listener); - }; - - this.removeEventListener = noop; - this.detachEvent = noop; - - this.fire = function(name) { - forEach(events[name], function(fn) { - fn({type: name}); // type to make jQuery happy - }); - }; - - this.location = { - href: 'http://server', - replace: noop - }; - - this.history = { - replaceState: noop, - pushState: noop - }; -} - -describe('browser', function() { - - var browser, fakeWindow, logs, scripts, removedScripts, sniffer; - - beforeEach(function() { - scripts = []; - removedScripts = []; - sniffer = {history: true, hashchange: true}; - fakeWindow = new MockWindow(); - - var fakeBody = [{appendChild: function(node){scripts.push(node);}, - removeChild: function(node){removedScripts.push(node);}}]; - - logs = {log:[], warn:[], info:[], error:[]}; - - var fakeLog = {log: function() { logs.log.push(slice.call(arguments)); }, - warn: function() { logs.warn.push(slice.call(arguments)); }, - info: function() { logs.info.push(slice.call(arguments)); }, - error: function() { logs.error.push(slice.call(arguments)); }}; - - browser = new Browser(fakeWindow, jqLite(window.document), fakeBody, fakeLog, sniffer); - }); - - it('should contain cookie cruncher', function() { - expect(browser.cookies).toBeDefined(); - }); - - describe('outstading requests', function() { - it('should process callbacks immedietly with no outstanding requests', function() { - var callback = jasmine.createSpy('callback'); - browser.notifyWhenNoOutstandingRequests(callback); - expect(callback).toHaveBeenCalled(); - }); - }); - - - describe('defer', function() { - it('should execute fn asynchroniously via setTimeout', function() { - var callback = jasmine.createSpy('deferred'); - - browser.defer(callback); - expect(callback).not.toHaveBeenCalled(); - - fakeWindow.setTimeout.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should update outstandingRequests counter', function() { - var callback = jasmine.createSpy('deferred'); - - browser.defer(callback); - expect(callback).not.toHaveBeenCalled(); - - fakeWindow.setTimeout.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should return unique deferId', function() { - var deferId1 = browser.defer(noop), - deferId2 = browser.defer(noop); - - expect(deferId1).toBeDefined(); - expect(deferId2).toBeDefined(); - expect(deferId1).not.toEqual(deferId2); - }); - - - describe('cancel', function() { - it('should allow tasks to be canceled with returned deferId', function() { - var log = [], - deferId1 = browser.defer(function() { log.push('cancel me'); }), - deferId2 = browser.defer(function() { log.push('ok'); }), - deferId3 = browser.defer(function() { log.push('cancel me, now!'); }); - - expect(log).toEqual([]); - expect(browser.defer.cancel(deferId1)).toBe(true); - expect(browser.defer.cancel(deferId3)).toBe(true); - fakeWindow.setTimeout.flush(); - expect(log).toEqual(['ok']); - expect(browser.defer.cancel(deferId2)).toBe(false); - }); - }); - }); - - - describe('cookies', function() { - - function deleteAllCookies() { - var cookies = document.cookie.split(";"); - - for (var i = 0; i < cookies.length; i++) { - var cookie = cookies[i]; - var eqPos = cookie.indexOf("="); - var name = eqPos > -1 ? cookie.substr(0, eqPos) : cookie; - document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT"; - } - } - - beforeEach(function() { - deleteAllCookies(); - expect(document.cookie).toEqual(''); - }); - - - afterEach(function() { - deleteAllCookies(); - expect(document.cookie).toEqual(''); - }); - - - describe('remove all via (null)', function() { - - it('should do nothing when no cookies are set', function() { - browser.cookies(null); - expect(document.cookie).toEqual(''); - expect(browser.cookies()).toEqual({}); - }); - - }); - - describe('remove via cookies(cookieName, undefined)', function() { - - it('should remove a cookie when it is present', function() { - document.cookie = 'foo=bar'; - - browser.cookies('foo', undefined); - - expect(document.cookie).toEqual(''); - expect(browser.cookies()).toEqual({}); - }); - - - it('should do nothing when an nonexisting cookie is being removed', function() { - browser.cookies('doesntexist', undefined); - expect(document.cookie).toEqual(''); - expect(browser.cookies()).toEqual({}); - }); - }); - - - describe('put via cookies(cookieName, string)', function() { - - it('should create and store a cookie', function() { - browser.cookies('cookieName', 'cookie=Value'); - expect(document.cookie).toMatch(/cookieName=cookie%3DValue;? ?/); - expect(browser.cookies()).toEqual({'cookieName':'cookie=Value'}); - }); - - - it('should overwrite an existing unsynced cookie', function() { - document.cookie = "cookie=new"; - - var oldVal = browser.cookies('cookie', 'newer'); - - expect(document.cookie).toEqual('cookie=newer'); - expect(browser.cookies()).toEqual({'cookie':'newer'}); - expect(oldVal).not.toBeDefined(); - }); - - it('should escape both name and value', function() { - browser.cookies('cookie1=', 'val;ue'); - browser.cookies('cookie2=bar;baz', 'val=ue'); - - var rawCookies = document.cookie.split("; "); //order is not guaranteed, so we need to parse - expect(rawCookies.length).toEqual(2); - expect(rawCookies).toContain('cookie1%3D=val%3Bue'); - expect(rawCookies).toContain('cookie2%3Dbar%3Bbaz=val%3Due'); - }); - - it('should log warnings when 4kb per cookie storage limit is reached', function() { - var i, longVal = '', cookieStr; - - for(i=0; i<4091; i++) { - longVal += '+'; - } - - cookieStr = document.cookie; - browser.cookies('x', longVal); //total size 4093-4096, so it should go through - expect(document.cookie).not.toEqual(cookieStr); - expect(browser.cookies()['x']).toEqual(longVal); - expect(logs.warn).toEqual([]); - - browser.cookies('x', longVal + 'xxxx'); //total size 4097-4099, a warning should be logged - expect(logs.warn).toEqual( - [[ "Cookie 'x' possibly not set or overflowed because it was too large (4097 > 4096 " + - "bytes)!" ]]); - - //force browser to dropped a cookie and make sure that the cache is not out of sync - browser.cookies('x', 'shortVal'); - expect(browser.cookies().x).toEqual('shortVal'); //needed to prime the cache - cookieStr = document.cookie; - browser.cookies('x', longVal + longVal + longVal); //should be too long for all browsers - - if (document.cookie !== cookieStr) { - fail("browser didn't drop long cookie when it was expected. make the cookie in this " + - "test longer"); - } - - expect(browser.cookies().x).toEqual('shortVal'); - }); - - it('should log warnings when 20 cookies per domain storage limit is reached', function() { - var i, str, cookieStr; - - for (i=0; i<20; i++) { - str = '' + i; - browser.cookies(str, str); - } - - i=0; - for (str in browser.cookies()) { - i++; - } - expect(i).toEqual(20); - expect(logs.warn).toEqual([]); - cookieStr = document.cookie; - - browser.cookies('one', 'more'); - expect(logs.warn).toEqual([]); - - //if browser dropped a cookie (very likely), make sure that the cache is not out of sync - if (document.cookie === cookieStr) { - expect(size(browser.cookies())).toEqual(20); - } else { - expect(size(browser.cookies())).toEqual(21); - } - }); - }); - - - describe('get via cookies()[cookieName]', function() { - - it('should return undefined for nonexistent cookie', function() { - expect(browser.cookies().nonexistent).not.toBeDefined(); - }); - - - it ('should return a value for an existing cookie', function() { - document.cookie = "foo=bar=baz"; - expect(browser.cookies().foo).toEqual('bar=baz'); - }); - - - it ('should unescape cookie values that were escaped by puts', function() { - document.cookie = "cookie2%3Dbar%3Bbaz=val%3Due"; - expect(browser.cookies()['cookie2=bar;baz']).toEqual('val=ue'); - }); - - - it('should preserve leading & trailing spaces in names and values', function() { - browser.cookies(' cookie name ', ' cookie value '); - expect(browser.cookies()[' cookie name ']).toEqual(' cookie value '); - expect(browser.cookies()['cookie name']).not.toBeDefined(); - }); - }); - - - describe('getAll via cookies()', function() { - - it('should return cookies as hash', function() { - document.cookie = "foo1=bar1"; - document.cookie = "foo2=bar2"; - expect(browser.cookies()).toEqual({'foo1':'bar1', 'foo2':'bar2'}); - }); - - - it('should return empty hash if no cookies exist', function() { - expect(browser.cookies()).toEqual({}); - }); - }); - - - it('should pick up external changes made to browser cookies', function() { - browser.cookies('oatmealCookie', 'drool'); - expect(browser.cookies()).toEqual({'oatmealCookie':'drool'}); - - document.cookie = 'oatmealCookie=changed'; - expect(browser.cookies().oatmealCookie).toEqual('changed'); - }); - - - it('should initialize cookie cache with existing cookies', function() { - document.cookie = "existingCookie=existingValue"; - expect(browser.cookies()).toEqual({'existingCookie':'existingValue'}); - }); - - }); - - describe('poller', function() { - - it('should call functions in pollFns in regular intervals', function() { - var log = ''; - browser.addPollFn(function() {log+='a';}); - browser.addPollFn(function() {log+='b';}); - expect(log).toEqual(''); - fakeWindow.setTimeout.flush(); - expect(log).toEqual('ab'); - fakeWindow.setTimeout.flush(); - expect(log).toEqual('abab'); - }); - - it('should startPoller', function() { - expect(fakeWindow.timeouts.length).toEqual(0); - - browser.addPollFn(function() {}); - expect(fakeWindow.timeouts.length).toEqual(1); - - //should remain 1 as it is the check fn - browser.addPollFn(function() {}); - expect(fakeWindow.timeouts.length).toEqual(1); - }); - - it('should return fn that was passed into addPollFn', function() { - var fn = function() { return 1; }; - var returnedFn = browser.addPollFn(fn); - expect(returnedFn).toBe(fn); - }); - }); - - describe('url', function() { - var pushState, replaceState, locationReplace; - - beforeEach(function() { - pushState = spyOn(fakeWindow.history, 'pushState'); - replaceState = spyOn(fakeWindow.history, 'replaceState'); - locationReplace = spyOn(fakeWindow.location, 'replace'); - }); - - it('should return current location.href', function() { - fakeWindow.location.href = 'http://test.com'; - expect(browser.url()).toEqual('http://test.com'); - - fakeWindow.location.href = 'https://another.com'; - expect(browser.url()).toEqual('https://another.com'); - }); - - it('should use history.pushState when available', function() { - sniffer.history = true; - browser.url('http://new.org'); - - expect(pushState).toHaveBeenCalledOnce(); - expect(pushState.argsForCall[0][2]).toEqual('http://new.org'); - - expect(replaceState).not.toHaveBeenCalled(); - expect(locationReplace).not.toHaveBeenCalled(); - expect(fakeWindow.location.href).toEqual('http://server'); - }); - - it('should use history.replaceState when available', function() { - sniffer.history = true; - browser.url('http://new.org', true); - - expect(replaceState).toHaveBeenCalledOnce(); - expect(replaceState.argsForCall[0][2]).toEqual('http://new.org'); - - expect(pushState).not.toHaveBeenCalled(); - expect(locationReplace).not.toHaveBeenCalled(); - expect(fakeWindow.location.href).toEqual('http://server'); - }); - - it('should set location.href when pushState not available', function() { - sniffer.history = false; - browser.url('http://new.org'); - - expect(fakeWindow.location.href).toEqual('http://new.org'); - - expect(pushState).not.toHaveBeenCalled(); - expect(replaceState).not.toHaveBeenCalled(); - expect(locationReplace).not.toHaveBeenCalled(); - }); - - it('should use location.replace when history.replaceState not available', function() { - sniffer.history = false; - browser.url('http://new.org', true); - - expect(locationReplace).toHaveBeenCalledWith('http://new.org'); - - expect(pushState).not.toHaveBeenCalled(); - expect(replaceState).not.toHaveBeenCalled(); - expect(fakeWindow.location.href).toEqual('http://server'); - }); - - it('should return $browser to allow chaining', function() { - expect(browser.url('http://any.com')).toBe(browser); - }); - }); - - describe('urlChange', function() { - var callback; - - beforeEach(function() { - callback = jasmine.createSpy('onUrlChange'); - }); - - afterEach(function() { - if (!jQuery) jqLite(fakeWindow).dealoc(); - }); - - it('should return registered callback', function() { - expect(browser.onUrlChange(callback)).toBe(callback); - }); - - it('should forward popstate event with new url when history supported', function() { - sniffer.history = true; - browser.onUrlChange(callback); - fakeWindow.location.href = 'http://server/new'; - - fakeWindow.fire('popstate'); - expect(callback).toHaveBeenCalledWith('http://server/new'); - - fakeWindow.fire('hashchange'); - fakeWindow.setTimeout.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - it('should forward only popstate event when both history and hashchange supported', function() { - sniffer.history = true; - sniffer.hashchange = true; - browser.onUrlChange(callback); - fakeWindow.location.href = 'http://server/new'; - - fakeWindow.fire('popstate'); - expect(callback).toHaveBeenCalledWith('http://server/new'); - - fakeWindow.fire('hashchange'); - fakeWindow.setTimeout.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - it('should forward hashchange event with new url when only hashchange supported', function() { - sniffer.history = false; - sniffer.hashchange = true; - browser.onUrlChange(callback); - fakeWindow.location.href = 'http://server/new'; - - fakeWindow.fire('hashchange'); - expect(callback).toHaveBeenCalledWith('http://server/new'); - - fakeWindow.fire('popstate'); - fakeWindow.setTimeout.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - it('should use polling when neither history nor hashchange supported', function() { - sniffer.history = false; - sniffer.hashchange = false; - browser.onUrlChange(callback); - - fakeWindow.location.href = 'http://server.new'; - fakeWindow.setTimeout.flush(); - expect(callback).toHaveBeenCalledWith('http://server.new'); - - fakeWindow.fire('popstate'); - fakeWindow.fire('hashchange'); - expect(callback).toHaveBeenCalledOnce(); - }); - - it('should not fire urlChange if changed by browser.url method (polling)', function() { - sniffer.history = false; - sniffer.hashchange = false; - browser.onUrlChange(callback); - browser.url('http://new.com'); - - fakeWindow.setTimeout.flush(); - expect(callback).not.toHaveBeenCalled(); - }); - - it('should not fire urlChange if changed by browser.url method (hashchange)', function() { - sniffer.history = false; - sniffer.hashchange = true; - browser.onUrlChange(callback); - browser.url('http://new.com'); - - fakeWindow.fire('hashchange'); - expect(callback).not.toHaveBeenCalled(); - }); - }); - - describe('addJs', function() { - it('should append a script tag to body', function() { - browser.addJs('http://localhost/bar.js'); - expect(scripts.length).toBe(1); - expect(scripts[0].src).toBe('http://localhost/bar.js'); - expect(scripts[0].id).toBe(''); - }); - - it('should return the appended script element', function() { - var script = browser.addJs('http://localhost/bar.js'); - expect(script).toBe(scripts[0]); - }); - }); - - describe('baseHref', function() { - var jqDocHead; - - function setDocumentBaseHrefTo(href) { - clearDocumentBaseHref(); - jqDocHead.append('<base href="' + href +'" />'); - } - - function clearDocumentBaseHref() { - jqDocHead.find('base').remove(); - } - - beforeEach(function() { - jqDocHead = jqLite(document).find('head'); - }); - - afterEach(clearDocumentBaseHref); - - it('should return value from <base href>', function() { - setDocumentBaseHrefTo('/base/path/'); - expect(browser.baseHref()).toEqual('/base/path/'); - }); - - it('should return undefined if no <base href>', function() { - expect(browser.baseHref()).toBeUndefined(); - }); - - it('should remove domain from <base href>', function() { - setDocumentBaseHrefTo('http://host.com/base/path/'); - expect(browser.baseHref()).toEqual('/base/path/'); - - setDocumentBaseHrefTo('http://host.com/base/path/index.html'); - expect(browser.baseHref()).toEqual('/base/path/index.html'); - }); - }); -}); diff --git a/test/service/cacheFactorySpec.js b/test/service/cacheFactorySpec.js deleted file mode 100644 index dc68b63d..00000000 --- a/test/service/cacheFactorySpec.js +++ /dev/null @@ -1,317 +0,0 @@ -describe('$cacheFactory', function() { - - it('should be injected', inject(function($cacheFactory) { - expect($cacheFactory).toBeDefined(); - })); - - - it('should return a new cache whenever called', inject(function($cacheFactory) { - var cache1 = $cacheFactory('cache1'); - var cache2 = $cacheFactory('cache2'); - expect(cache1).not.toEqual(cache2); - })); - - - it('should complain if the cache id is being reused', inject(function($cacheFactory) { - $cacheFactory('cache1'); - expect(function() { $cacheFactory('cache1'); }). - toThrow('cacheId cache1 taken'); - })); - - - describe('info', function() { - - it('should provide info about all created caches', inject(function($cacheFactory) { - expect($cacheFactory.info()).toEqual({}); - - var cache1 = $cacheFactory('cache1'); - expect($cacheFactory.info()).toEqual({cache1: {id: 'cache1', size: 0}}); - - cache1.put('foo', 'bar'); - expect($cacheFactory.info()).toEqual({cache1: {id: 'cache1', size: 1}}); - })); - }); - - - describe('get', function() { - - it('should return a cache if looked up by id', inject(function($cacheFactory) { - var cache1 = $cacheFactory('cache1'), - cache2 = $cacheFactory('cache2'); - - expect(cache1).not.toBe(cache2); - expect(cache1).toBe($cacheFactory.get('cache1')); - expect(cache2).toBe($cacheFactory.get('cache2')); - })); - }); - - describe('cache', function() { - var cache; - - beforeEach(inject(function($cacheFactory) { - cache = $cacheFactory('test'); - })); - - - describe('put, get & remove', function() { - - it('should add cache entries via add and retrieve them via get', inject(function($cacheFactory) { - cache.put('key1', 'bar'); - cache.put('key2', {bar:'baz'}); - - expect(cache.get('key2')).toEqual({bar:'baz'}); - expect(cache.get('key1')).toBe('bar'); - })); - - - it('should ignore put if the value is undefined', inject(function($cacheFactory) { - cache.put(); - cache.put('key1'); - cache.put('key2', undefined); - - expect(cache.info().size).toBe(0); - })); - - - it('should remove entries via remove', inject(function($cacheFactory) { - cache.put('k1', 'foo'); - cache.put('k2', 'bar'); - - cache.remove('k2'); - - expect(cache.get('k1')).toBe('foo'); - expect(cache.get('k2')).toBeUndefined(); - - cache.remove('k1'); - - expect(cache.get('k1')).toBeUndefined(); - expect(cache.get('k2')).toBeUndefined(); - })); - - - it('should stringify keys', inject(function($cacheFactory) { - cache.put('123', 'foo'); - cache.put(123, 'bar'); - - expect(cache.get('123')).toBe('bar'); - expect(cache.info().size).toBe(1); - - cache.remove(123); - expect(cache.info().size).toBe(0); - })); - }); - - - describe('info', function() { - - it('should size increment with put and decrement with remove', inject(function($cacheFactory) { - expect(cache.info().size).toBe(0); - - cache.put('foo', 'bar'); - expect(cache.info().size).toBe(1); - - cache.put('baz', 'boo'); - expect(cache.info().size).toBe(2); - - cache.remove('baz'); - expect(cache.info().size).toBe(1); - - cache.remove('foo'); - expect(cache.info().size).toBe(0); - })); - - - it('should return cache id', inject(function($cacheFactory) { - expect(cache.info().id).toBe('test'); - })); - }); - - - describe('removeAll', function() { - - it('should blow away all data', inject(function($cacheFactory) { - cache.put('id1', 1); - cache.put('id2', 2); - cache.put('id3', 3); - expect(cache.info().size).toBe(3); - - cache.removeAll(); - - expect(cache.info().size).toBe(0); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBeUndefined(); - expect(cache.get('id3')).toBeUndefined(); - })); - }); - - - describe('destroy', function() { - - it('should make the cache unusable and remove references to it from $cacheFactory', inject(function($cacheFactory) { - cache.put('foo', 'bar'); - cache.destroy(); - - expect(function() { cache.get('foo'); } ).toThrow(); - expect(function() { cache.get('neverexisted'); }).toThrow(); - expect(function() { cache.put('foo', 'bar'); }).toThrow(); - - expect($cacheFactory.get('test')).toBeUndefined(); - expect($cacheFactory.info()).toEqual({}); - })); - }); - }); - - - describe('LRU cache', function() { - - it('should create cache with defined capacity', inject(function($cacheFactory) { - cache = $cacheFactory('cache1', {capacity: 5}); - expect(cache.info().size).toBe(0); - - for (var i=0; i<5; i++) { - cache.put('id' + i, i); - } - - expect(cache.info().size).toBe(5); - - cache.put('id5', 5); - expect(cache.info().size).toBe(5); - cache.put('id6', 6); - expect(cache.info().size).toBe(5); - })); - - - describe('eviction', function() { - - beforeEach(inject(function($cacheFactory) { - cache = $cacheFactory('cache1', {capacity: 2}); - - cache.put('id0', 0); - cache.put('id1', 1); - })); - - - it('should kick out the first entry on put', inject(function($cacheFactory) { - cache.put('id2', 2); - expect(cache.get('id0')).toBeUndefined(); - expect(cache.get('id1')).toBe(1); - expect(cache.get('id2')).toBe(2); - })); - - - it('should refresh an entry via get', inject(function($cacheFactory) { - cache.get('id0'); - cache.put('id2', 2); - expect(cache.get('id0')).toBe(0); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBe(2); - })); - - - it('should refresh an entry via put', inject(function($cacheFactory) { - cache.put('id0', '00'); - cache.put('id2', 2); - expect(cache.get('id0')).toBe('00'); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBe(2); - })); - - - it('should not purge an entry if another one was removed', inject(function($cacheFactory) { - cache.remove('id1'); - cache.put('id2', 2); - expect(cache.get('id0')).toBe(0); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBe(2); - })); - - - it('should purge the next entry if the stalest one was removed', inject(function($cacheFactory) { - cache.remove('id0'); - cache.put('id2', 2); - cache.put('id3', 3); - expect(cache.get('id0')).toBeUndefined(); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBe(2); - expect(cache.get('id3')).toBe(3); - })); - - - it('should correctly recreate the linked list if all cache entries were removed', inject(function($cacheFactory) { - cache.remove('id0'); - cache.remove('id1'); - cache.put('id2', 2); - cache.put('id3', 3); - cache.put('id4', 4); - expect(cache.get('id0')).toBeUndefined(); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBeUndefined(); - expect(cache.get('id3')).toBe(3); - expect(cache.get('id4')).toBe(4); - })); - - - it('should blow away the entire cache via removeAll and start evicting when full', inject(function($cacheFactory) { - cache.put('id0', 0); - cache.put('id1', 1); - cache.removeAll(); - - cache.put('id2', 2); - cache.put('id3', 3); - cache.put('id4', 4); - - expect(cache.info().size).toBe(2); - expect(cache.get('id0')).toBeUndefined(); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBeUndefined(); - expect(cache.get('id3')).toBe(3); - expect(cache.get('id4')).toBe(4); - })); - - - it('should correctly refresh and evict items if operations are chained', inject(function($cacheFactory) { - cache = $cacheFactory('cache2', {capacity: 3}); - - cache.put('id0', 0); //0 - cache.put('id1', 1); //1,0 - cache.put('id2', 2); //2,1,0 - cache.get('id0'); //0,2,1 - cache.put('id3', 3); //3,0,2 - cache.put('id0', 9); //0,3,2 - cache.put('id4', 4); //4,0,3 - - expect(cache.get('id3')).toBe(3); - expect(cache.get('id0')).toBe(9); - expect(cache.get('id4')).toBe(4); - - cache.remove('id0'); //4,3 - cache.remove('id3'); //4 - cache.put('id5', 5); //5,4 - cache.put('id6', 6); //6,5,4 - cache.get('id4'); //4,6,5 - cache.put('id7', 7); //7,4,6 - - expect(cache.get('id0')).toBeUndefined(); - expect(cache.get('id1')).toBeUndefined(); - expect(cache.get('id2')).toBeUndefined(); - expect(cache.get('id3')).toBeUndefined(); - expect(cache.get('id4')).toBe(4); - expect(cache.get('id5')).toBeUndefined(); - expect(cache.get('id6')).toBe(6); - expect(cache.get('id7')).toBe(7); - - cache.removeAll(); - cache.put('id0', 0); //0 - cache.put('id1', 1); //1,0 - cache.put('id2', 2); //2,1,0 - cache.put('id3', 3); //3,2,1 - - expect(cache.info().size).toBe(3); - expect(cache.get('id0')).toBeUndefined(); - expect(cache.get('id1')).toBe(1); - expect(cache.get('id2')).toBe(2); - expect(cache.get('id3')).toBe(3); - })); - }); - }); -}); diff --git a/test/service/compilerSpec.js b/test/service/compilerSpec.js deleted file mode 100644 index dc2e20cf..00000000 --- a/test/service/compilerSpec.js +++ /dev/null @@ -1,1811 +0,0 @@ -'use strict'; - -describe('$compile', function() { - var element; - - beforeEach(module(provideLog, function($provide, $compileProvider){ - element = null; - - $compileProvider.directive('log', function(log) { - return { - restrict: 'CAM', - priority:0, - compile: valueFn(function(scope, element, attrs) { - log(attrs.log || 'LOG'); - }) - }; - }); - - $compileProvider.directive('highLog', function(log) { - return { restrict: 'CAM', priority:3, compile: valueFn(function(scope, element, attrs) { - log(attrs.highLog || 'HIGH'); - })}; - }); - - $compileProvider.directive('mediumLog', function(log) { - return { restrict: 'CAM', priority:2, compile: valueFn(function(scope, element, attrs) { - log(attrs.mediumLog || 'MEDIUM'); - })}; - }); - - $compileProvider.directive('greet', function() { - return { restrict: 'CAM', priority:10, compile: valueFn(function(scope, element, attrs) { - element.text("Hello " + attrs.greet); - })}; - }); - - $compileProvider.directive('set', function() { - return function(scope, element, attrs) { - element.text(attrs.set); - }; - }); - - $compileProvider.directive('mediumStop', valueFn({ - priority: 2, - terminal: true - })); - - $compileProvider.directive('stop', valueFn({ - terminal: true - })); - - $compileProvider.directive('negativeStop', valueFn({ - priority: -100, // even with negative priority we still should be able to stop descend - terminal: true - })); - })); - - - afterEach(function(){ - dealoc(element); - }); - - - describe('configuration', function() { - it('should register a directive', function() { - module(function($compileProvider) { - $compileProvider.directive('div', function(log) { - return { - restrict: 'ECA', - link: function(scope, element) { - log('OK'); - element.text('SUCCESS'); - } - }; - }) - }); - inject(function($compile, $rootScope, log) { - element = $compile('<div></div>')($rootScope); - expect(element.text()).toEqual('SUCCESS'); - expect(log).toEqual('OK'); - }) - }); - - it('should allow registration of multiple directives with same name', function() { - module(function($compileProvider) { - $compileProvider.directive('div', function(log) { - return { - restrict: 'ECA', - link: log.fn('1') - }; - }); - $compileProvider.directive('div', function(log) { - return { - restrict: 'ECA', - link: log.fn('2') - }; - }); - }); - inject(function($compile, $rootScope, log) { - element = $compile('<div></div>')($rootScope); - expect(log).toEqual('1; 2'); - }); - }); - }); - - - describe('compile phase', function() { - - it('should wrap root text nodes in spans', inject(function($compile, $rootScope) { - element = jqLite('<div>A<a>B</a>C</div>'); - var text = element.contents(); - expect(text[0].nodeName).toEqual('#text'); - text = $compile(text)($rootScope); - expect(lowercase(text[0].nodeName)).toEqual('span'); - expect(element.find('span').text()).toEqual('A<a>B</a>C'); - })); - - describe('multiple directives per element', function() { - it('should allow multiple directives per element', inject(function($compile, $rootScope, log){ - element = $compile( - '<span greet="angular" log="L" x-high-log="H" data-medium-log="M"></span>') - ($rootScope); - expect(element.text()).toEqual('Hello angular'); - expect(log).toEqual('H; M; L'); - })); - - - it('should recurse to children', inject(function($compile, $rootScope){ - element = $compile('<div>0<a set="hello">1</a>2<b set="angular">3</b>4</div>')($rootScope); - expect(element.text()).toEqual('0hello2angular4'); - })); - - - it('should allow directives in classes', inject(function($compile, $rootScope, log) { - element = $compile('<div class="greet: angular; log:123;"></div>')($rootScope); - expect(element.html()).toEqual('Hello angular'); - expect(log).toEqual('123'); - })); - - - it('should ignore not set CSS classes on SVG elements', inject(function($compile, $rootScope, log) { - if (!window.SVGElement) return; - // According to spec SVG element className property is readonly, but only FF - // implements it this way which causes compile exceptions. - element = $compile('<svg><text>{{1}}</text></svg>')($rootScope); - $rootScope.$digest(); - expect(element.text()).toEqual('1'); - })); - - - it('should allow directives in comments', inject( - function($compile, $rootScope, log) { - element = $compile('<div>0<!-- directive: log angular -->1</div>')($rootScope); - expect(log).toEqual('angular'); - } - )); - - - it('should receive scope, element, and attributes', function() { - var injector; - module(function($compileProvider) { - $compileProvider.directive('log', function($injector, $rootScope) { - injector = $injector; - return { - restrict: 'CA', - compile: function(element, templateAttr) { - expect(typeof templateAttr.$normalize).toBe('function'); - expect(typeof templateAttr.$set).toBe('function'); - expect(isElement(templateAttr.$element)).toBeTruthy(); - expect(element.text()).toEqual('unlinked'); - expect(templateAttr.exp).toEqual('abc'); - expect(templateAttr.aa).toEqual('A'); - expect(templateAttr.bb).toEqual('B'); - expect(templateAttr.cc).toEqual('C'); - return function(scope, element, attr) { - expect(element.text()).toEqual('unlinked'); - expect(attr).toBe(templateAttr); - expect(scope).toEqual($rootScope); - element.text('worked'); - } - } - }; - }); - }); - inject(function($rootScope, $compile, $injector) { - element = $compile( - '<div class="log" exp="abc" aa="A" x-Bb="B" daTa-cC="C">unlinked</div>')($rootScope); - expect(element.text()).toEqual('worked'); - expect(injector).toBe($injector); // verify that directive is injectable - }); - }); - }); - - describe('error handling', function() { - - it('should handle exceptions', function() { - module(function($compileProvider, $exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - $compileProvider.directive('factoryError', function() { throw 'FactoryError'; }); - $compileProvider.directive('templateError', - valueFn({ compile: function() { throw 'TemplateError'; } })); - $compileProvider.directive('linkingError', - valueFn(function() { throw 'LinkingError'; })); - }); - inject(function($rootScope, $compile, $exceptionHandler) { - element = $compile('<div factory-error template-error linking-error></div>')($rootScope); - expect($exceptionHandler.errors[0]).toEqual('FactoryError'); - expect($exceptionHandler.errors[1][0]).toEqual('TemplateError'); - expect(ie($exceptionHandler.errors[1][1])). - toEqual('<div factory-error linking-error template-error>'); - expect($exceptionHandler.errors[2][0]).toEqual('LinkingError'); - expect(ie($exceptionHandler.errors[2][1])). - toEqual('<div class="ng-scope" factory-error linking-error template-error>'); - - - // crazy stuff to make IE happy - function ie(text) { - var list = [], - parts, elementName; - - parts = lowercase(text). - replace('<', ''). - replace('>', ''). - split(' '); - elementName = parts.shift(); - parts.sort(); - parts.unshift(elementName); - forEach(parts, function(value, key){ - if (value.substring(0,3) == 'ng-') { - } else { - value = value.replace('=""', ''); - var match = value.match(/=(.*)/); - if (match && match[1].charAt(0) != '"') { - value = value.replace(/=(.*)/, '="$1"'); - } - list.push(value); - } - }); - return '<' + list.join(' ') + '>'; - } - }); - }); - - - it('should prevent changing of structure', inject( - function($compile, $rootScope){ - element = jqLite("<div><div log></div></div>"); - var linkFn = $compile(element); - element.append("<div></div>"); - expect(function() { - linkFn($rootScope); - }).toThrow('Template changed structure!'); - } - )); - }); - - describe('compiler control', function() { - describe('priority', function() { - it('should honor priority', inject(function($compile, $rootScope, log){ - element = $compile( - '<span log="L" x-high-log="H" data-medium-log="M"></span>') - ($rootScope); - expect(log).toEqual('H; M; L'); - })); - }); - - - describe('terminal', function() { - - it('should prevent further directives from running', inject(function($rootScope, $compile) { - element = $compile('<div negative-stop><a set="FAIL">OK</a></div>')($rootScope); - expect(element.text()).toEqual('OK'); - } - )); - - - it('should prevent further directives from running, but finish current priority level', - inject(function($rootScope, $compile, log) { - // class is processed after attrs, so putting log in class will put it after - // the stop in the current level. This proves that the log runs after stop - element = $compile( - '<div high-log medium-stop log class="medium-log"><a set="FAIL">OK</a></div>')($rootScope); - expect(element.text()).toEqual('OK'); - expect(log.toArray().sort()).toEqual(['HIGH', 'MEDIUM']); - }) - ); - }); - - - describe('restrict', function() { - - it('should allow restriction of attributes', function() { - module(function($compileProvider, $provide) { - forEach({div:'E', attr:'A', clazz:'C', all:'EAC'}, function(restrict, name) { - $compileProvider.directive(name, function(log) { - return { - restrict: restrict, - compile: valueFn(function(scope, element, attr) { - log(name); - }) - }; - }); - }); - }); - inject(function($rootScope, $compile, log) { - dealoc($compile('<span div class="div"></span>')($rootScope)); - expect(log).toEqual(''); - log.reset(); - - dealoc($compile('<div></div>')($rootScope)); - expect(log).toEqual('div'); - log.reset(); - - dealoc($compile('<attr class=""attr"></attr>')($rootScope)); - expect(log).toEqual(''); - log.reset(); - - dealoc($compile('<span attr></span>')($rootScope)); - expect(log).toEqual('attr'); - log.reset(); - - dealoc($compile('<clazz clazz></clazz>')($rootScope)); - expect(log).toEqual(''); - log.reset(); - - dealoc($compile('<span class="clazz"></span>')($rootScope)); - expect(log).toEqual('clazz'); - log.reset(); - - dealoc($compile('<all class="all" all></all>')($rootScope)); - expect(log).toEqual('all; all; all'); - }); - }); - }); - - - describe('template', function() { - - - beforeEach(module(function($compileProvider) { - $compileProvider.directive('replace', valueFn({ - restrict: 'CAM', - replace: true, - template: '<div class="log" style="width: 10px" high-log>Hello: <<CONTENT>></div>', - compile: function(element, attr) { - attr.$set('compiled', 'COMPILED'); - expect(element).toBe(attr.$element); - } - })); - $compileProvider.directive('append', valueFn({ - restrict: 'CAM', - template: '<div class="log" style="width: 10px" high-log>Hello: <<CONTENT>></div>', - compile: function(element, attr) { - attr.$set('compiled', 'COMPILED'); - expect(element).toBe(attr.$element); - } - })); - })); - - - it('should replace element with template', inject(function($compile, $rootScope) { - element = $compile('<div><div replace>content</div><div>')($rootScope); - expect(element.text()).toEqual('Hello: content'); - expect(element.find('div').attr('compiled')).toEqual('COMPILED'); - })); - - - it('should append element with template', inject(function($compile, $rootScope) { - element = $compile('<div><div append>content</div><div>')($rootScope); - expect(element.text()).toEqual('Hello: content'); - expect(element.find('div').attr('compiled')).toEqual('COMPILED'); - })); - - - it('should compile replace template', inject(function($compile, $rootScope, log) { - element = $compile('<div><div replace medium-log>{{ "angular" }}</div><div>') - ($rootScope); - $rootScope.$digest(); - expect(element.text()).toEqual('Hello: angular'); - // HIGH goes after MEDIUM since it executes as part of replaced template - expect(log).toEqual('MEDIUM; HIGH; LOG'); - })); - - - it('should compile append template', inject(function($compile, $rootScope, log) { - element = $compile('<div><div append medium-log>{{ "angular" }}</div><div>') - ($rootScope); - $rootScope.$digest(); - expect(element.text()).toEqual('Hello: angular'); - expect(log).toEqual('HIGH; LOG; MEDIUM'); - })); - - - it('should merge attributes including style attr', inject(function($compile, $rootScope) { - element = $compile( - '<div><div replace class="medium-log" style="height: 20px" ></div><div>') - ($rootScope); - var div = element.find('div'); - expect(div.hasClass('medium-log')).toBe(true); - expect(div.hasClass('log')).toBe(true); - expect(div.css('width')).toBe('10px'); - expect(div.css('height')).toBe('20px'); - expect(div.attr('replace')).toEqual(''); - expect(div.attr('high-log')).toEqual(''); - })); - - it('should prevent multiple templates per element', inject(function($compile) { - try { - $compile('<div><span replace class="replace"></span></div>') - fail(); - } catch(e) { - expect(e.message).toMatch(/Multiple directives .* asking for template/); - } - })); - - it('should play nice with repeater when inline', inject(function($compile, $rootScope) { - element = $compile( - '<div>' + - '<div ng-repeat="i in [1,2]" replace>{{i}}; </div>' + - '</div>')($rootScope); - $rootScope.$digest(); - expect(element.text()).toEqual('Hello: 1; Hello: 2; '); - })); - - - it('should play nice with repeater when append', inject(function($compile, $rootScope) { - element = $compile( - '<div>' + - '<div ng-repeat="i in [1,2]" append>{{i}}; </div>' + - '</div>')($rootScope); - $rootScope.$digest(); - expect(element.text()).toEqual('Hello: 1; Hello: 2; '); - })); - - - it('should merge interpolated css class', inject(function($compile, $rootScope) { - element = $compile('<div class="one {{cls}} three" replace></div>')($rootScope); - - $rootScope.$apply(function() { - $rootScope.cls = 'two'; - }); - - expect(element).toHaveClass('one'); - expect(element).toHaveClass('two'); // interpolated - expect(element).toHaveClass('three'); - expect(element).toHaveClass('log'); // merged from replace directive template - })); - - - it('should merge interpolated css class with ng-repeat', - inject(function($compile, $rootScope) { - element = $compile( - '<div>' + - '<div ng-repeat="i in [1]" class="one {{cls}} three" replace></div>' + - '</div>')($rootScope); - - $rootScope.$apply(function() { - $rootScope.cls = 'two'; - }); - - var child = element.find('div').eq(0); - expect(child).toHaveClass('one'); - expect(child).toHaveClass('two'); // interpolated - expect(child).toHaveClass('three'); - expect(child).toHaveClass('log'); // merged from replace directive template - })); - }); - - - describe('async templates', function() { - - beforeEach(module( - function($compileProvider) { - $compileProvider.directive('hello', valueFn({ restrict: 'CAM', templateUrl: 'hello.html' })); - $compileProvider.directive('cau', valueFn({ restrict: 'CAM', templateUrl:'cau.html' })); - - $compileProvider.directive('cError', valueFn({ - restrict: 'CAM', - templateUrl:'error.html', - compile: function() { - throw Error('cError'); - } - })); - $compileProvider.directive('lError', valueFn({ - restrict: 'CAM', - templateUrl: 'error.html', - compile: function() { - throw Error('lError'); - } - })); - - - $compileProvider.directive('iHello', valueFn({ - restrict: 'CAM', - replace: true, - templateUrl: 'hello.html' - })); - $compileProvider.directive('iCau', valueFn({ - restrict: 'CAM', - replace: true, - templateUrl:'cau.html' - })); - - $compileProvider.directive('iCError', valueFn({ - restrict: 'CAM', - replace: true, - templateUrl:'error.html', - compile: function() { - throw Error('cError'); - } - })); - $compileProvider.directive('iLError', valueFn({ - restrict: 'CAM', - replace: true, - templateUrl: 'error.html', - compile: function() { - throw Error('lError'); - } - })); - - } - )); - - - it('should append template via $http and cache it in $templateCache', inject( - function($compile, $httpBackend, $templateCache, $rootScope, $browser) { - $httpBackend.expect('GET', 'hello.html').respond('<span>Hello!</span> World!'); - $templateCache.put('cau.html', '<span>Cau!</span>'); - element = $compile('<div><b class="hello">ignore</b><b class="cau">ignore</b></div>')($rootScope); - expect(sortedHtml(element)). - toEqual('<div><b class="hello"></b><b class="cau"></b></div>'); - - $rootScope.$digest(); - - - expect(sortedHtml(element)). - toEqual('<div><b class="hello"></b><b class="cau"><span>Cau!</span></b></div>'); - - $httpBackend.flush(); - expect(sortedHtml(element)).toEqual( - '<div>' + - '<b class="hello"><span>Hello!</span> World!</b>' + - '<b class="cau"><span>Cau!</span></b>' + - '</div>'); - } - )); - - - it('should inline template via $http and cache it in $templateCache', inject( - function($compile, $httpBackend, $templateCache, $rootScope) { - $httpBackend.expect('GET', 'hello.html').respond('<span>Hello!</span>'); - $templateCache.put('cau.html', '<span>Cau!</span>'); - element = $compile('<div><b class=i-hello>ignore</b><b class=i-cau>ignore</b></div>')($rootScope); - expect(sortedHtml(element)). - toEqual('<div><b class="i-hello"></b><b class="i-cau"></b></div>'); - - $rootScope.$digest(); - - - expect(sortedHtml(element)). - toEqual('<div><b class="i-hello"></b><span class="i-cau">Cau!</span></div>'); - - $httpBackend.flush(); - expect(sortedHtml(element)). - toEqual('<div><span class="i-hello">Hello!</span><span class="i-cau">Cau!</span></div>'); - } - )); - - - it('should compile, link and flush the template append', inject( - function($compile, $templateCache, $rootScope, $browser) { - $templateCache.put('hello.html', '<span>Hello, {{name}}!</span>'); - $rootScope.name = 'Elvis'; - element = $compile('<div><b class="hello"></b></div>')($rootScope); - - $rootScope.$digest(); - - expect(sortedHtml(element)). - toEqual('<div><b class="hello"><span>Hello, Elvis!</span></b></div>'); - } - )); - - - it('should compile, link and flush the template inline', inject( - function($compile, $templateCache, $rootScope) { - $templateCache.put('hello.html', '<span>Hello, {{name}}!</span>'); - $rootScope.name = 'Elvis'; - element = $compile('<div><b class=i-hello></b></div>')($rootScope); - - $rootScope.$digest(); - - expect(sortedHtml(element)). - toEqual('<div><span class="i-hello">Hello, Elvis!</span></div>'); - } - )); - - - it('should compile, flush and link the template append', inject( - function($compile, $templateCache, $rootScope) { - $templateCache.put('hello.html', '<span>Hello, {{name}}!</span>'); - $rootScope.name = 'Elvis'; - var template = $compile('<div><b class="hello"></b></div>'); - - element = template($rootScope); - $rootScope.$digest(); - - expect(sortedHtml(element)). - toEqual('<div><b class="hello"><span>Hello, Elvis!</span></b></div>'); - } - )); - - - it('should compile, flush and link the template inline', inject( - function($compile, $templateCache, $rootScope) { - $templateCache.put('hello.html', '<span>Hello, {{name}}!</span>'); - $rootScope.name = 'Elvis'; - var template = $compile('<div><b class=i-hello></b></div>'); - - element = template($rootScope); - $rootScope.$digest(); - - expect(sortedHtml(element)). - toEqual('<div><span class="i-hello">Hello, Elvis!</span></div>'); - } - )); - - - it('should resolve widgets after cloning in append mode', function() { - module(function($exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - }); - inject(function($compile, $templateCache, $rootScope, $httpBackend, $browser, - $exceptionHandler) { - $httpBackend.expect('GET', 'hello.html').respond('<span>{{greeting}} </span>'); - $httpBackend.expect('GET', 'error.html').respond('<div></div>'); - $templateCache.put('cau.html', '<span>{{name}}</span>'); - $rootScope.greeting = 'Hello'; - $rootScope.name = 'Elvis'; - var template = $compile( - '<div>' + - '<b class="hello"></b>' + - '<b class="cau"></b>' + - '<b class=c-error></b>' + - '<b class=l-error></b>' + - '</div>'); - var e1; - var e2; - - e1 = template($rootScope.$new(), noop); // clone - expect(e1.text()).toEqual(''); - - $httpBackend.flush(); - - e2 = template($rootScope.$new(), noop); // clone - $rootScope.$digest(); - expect(e1.text()).toEqual('Hello Elvis'); - expect(e2.text()).toEqual('Hello Elvis'); - - expect($exceptionHandler.errors.length).toEqual(2); - expect($exceptionHandler.errors[0][0].message).toEqual('cError'); - expect($exceptionHandler.errors[1][0].message).toEqual('lError'); - - dealoc(e1); - dealoc(e2); - }); - }); - - - it('should resolve widgets after cloning in inline mode', function() { - module(function($exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - }); - inject(function($compile, $templateCache, $rootScope, $httpBackend, $browser, - $exceptionHandler) { - $httpBackend.expect('GET', 'hello.html').respond('<span>{{greeting}} </span>'); - $httpBackend.expect('GET', 'error.html').respond('<div></div>'); - $templateCache.put('cau.html', '<span>{{name}}</span>'); - $rootScope.greeting = 'Hello'; - $rootScope.name = 'Elvis'; - var template = $compile( - '<div>' + - '<b class=i-hello></b>' + - '<b class=i-cau></b>' + - '<b class=i-c-error></b>' + - '<b class=i-l-error></b>' + - '</div>'); - var e1; - var e2; - - e1 = template($rootScope.$new(), noop); // clone - expect(e1.text()).toEqual(''); - - $httpBackend.flush(); - - e2 = template($rootScope.$new(), noop); // clone - $rootScope.$digest(); - expect(e1.text()).toEqual('Hello Elvis'); - expect(e2.text()).toEqual('Hello Elvis'); - - expect($exceptionHandler.errors.length).toEqual(2); - expect($exceptionHandler.errors[0][0].message).toEqual('cError'); - expect($exceptionHandler.errors[1][0].message).toEqual('lError'); - - dealoc(e1); - dealoc(e2); - }); - }); - - - it('should be implicitly terminal and not compile placeholder content in append', inject( - function($compile, $templateCache, $rootScope, log) { - // we can't compile the contents because that would result in a memory leak - - $templateCache.put('hello.html', 'Hello!'); - element = $compile('<div><b class="hello"><div log></div></b></div>')($rootScope); - - expect(log).toEqual(''); - } - )); - - - it('should be implicitly terminal and not compile placeholder content in inline', inject( - function($compile, $templateCache, $rootScope, log) { - // we can't compile the contents because that would result in a memory leak - - $templateCache.put('hello.html', 'Hello!'); - element = $compile('<div><b class=i-hello><div log></div></b></div>')($rootScope); - - expect(log).toEqual(''); - } - )); - - - it('should throw an error and clear element content if the template fails to load', inject( - function($compile, $httpBackend, $rootScope) { - $httpBackend.expect('GET', 'hello.html').respond(404, 'Not Found!'); - element = $compile('<div><b class="hello">content</b></div>')($rootScope); - - expect(function() { - $httpBackend.flush(); - }).toThrow('Failed to load template: hello.html'); - expect(sortedHtml(element)).toBe('<div><b class="hello"></b></div>'); - } - )); - - - it('should prevent multiple templates per element', function() { - module(function($compileProvider) { - $compileProvider.directive('sync', valueFn({ - restrict: 'C', - template: '<span></span>' - })); - $compileProvider.directive('async', valueFn({ - restrict: 'C', - templateUrl: 'template.html' - })); - }); - inject(function($compile){ - expect(function() { - $compile('<div><div class="sync async"></div></div>'); - }).toThrow('Multiple directives [sync, async] asking for template on: <'+ - (msie <= 8 ? 'DIV' : 'div') + ' class="sync async">'); - }); - }); - - - describe('delay compile / linking functions until after template is resolved', function(){ - var template; - beforeEach(module(function($compileProvider) { - function directive (name, priority, options) { - $compileProvider.directive(name, function(log) { - return (extend({ - priority: priority, - compile: function() { - log(name + '-C'); - return function() { log(name + '-L'); } - } - }, options || {})); - }); - } - - directive('first', 10); - directive('second', 5, { templateUrl: 'second.html' }); - directive('third', 3); - directive('last', 0); - - directive('iFirst', 10, {replace: true}); - directive('iSecond', 5, {replace: true, templateUrl: 'second.html' }); - directive('iThird', 3, {replace: true}); - directive('iLast', 0, {replace: true}); - })); - - it('should flush after link append', inject( - function($compile, $rootScope, $httpBackend, log) { - $httpBackend.expect('GET', 'second.html').respond('<div third>{{1+2}}</div>'); - template = $compile('<div><span first second last></span></div>'); - element = template($rootScope); - expect(log).toEqual('first-C'); - - log('FLUSH'); - $httpBackend.flush(); - $rootScope.$digest(); - expect(log).toEqual( - 'first-C; FLUSH; second-C; last-C; third-C; ' + - 'third-L; first-L; second-L; last-L'); - - var span = element.find('span'); - expect(span.attr('first')).toEqual(''); - expect(span.attr('second')).toEqual(''); - expect(span.find('div').attr('third')).toEqual(''); - expect(span.attr('last')).toEqual(''); - - expect(span.text()).toEqual('3'); - })); - - - it('should flush after link inline', inject( - function($compile, $rootScope, $httpBackend, log) { - $httpBackend.expect('GET', 'second.html').respond('<div i-third>{{1+2}}</div>'); - template = $compile('<div><span i-first i-second i-last></span></div>'); - element = template($rootScope); - expect(log).toEqual('iFirst-C'); - - log('FLUSH'); - $httpBackend.flush(); - $rootScope.$digest(); - expect(log).toEqual( - 'iFirst-C; FLUSH; iSecond-C; iThird-C; iLast-C; ' + - 'iFirst-L; iSecond-L; iThird-L; iLast-L'); - - var div = element.find('div'); - expect(div.attr('i-first')).toEqual(''); - expect(div.attr('i-second')).toEqual(''); - expect(div.attr('i-third')).toEqual(''); - expect(div.attr('i-last')).toEqual(''); - - expect(div.text()).toEqual('3'); - })); - - - it('should flush before link append', inject( - function($compile, $rootScope, $httpBackend, log) { - $httpBackend.expect('GET', 'second.html').respond('<div third>{{1+2}}</div>'); - template = $compile('<div><span first second last></span></div>'); - expect(log).toEqual('first-C'); - log('FLUSH'); - $httpBackend.flush(); - expect(log).toEqual('first-C; FLUSH; second-C; last-C; third-C'); - - element = template($rootScope); - $rootScope.$digest(); - expect(log).toEqual( - 'first-C; FLUSH; second-C; last-C; third-C; ' + - 'third-L; first-L; second-L; last-L'); - - var span = element.find('span'); - expect(span.attr('first')).toEqual(''); - expect(span.attr('second')).toEqual(''); - expect(span.find('div').attr('third')).toEqual(''); - expect(span.attr('last')).toEqual(''); - - expect(span.text()).toEqual('3'); - })); - - - it('should flush before link inline', inject( - function($compile, $rootScope, $httpBackend, log) { - $httpBackend.expect('GET', 'second.html').respond('<div i-third>{{1+2}}</div>'); - template = $compile('<div><span i-first i-second i-last></span></div>'); - expect(log).toEqual('iFirst-C'); - log('FLUSH'); - $httpBackend.flush(); - expect(log).toEqual('iFirst-C; FLUSH; iSecond-C; iThird-C; iLast-C'); - - element = template($rootScope); - $rootScope.$digest(); - expect(log).toEqual( - 'iFirst-C; FLUSH; iSecond-C; iThird-C; iLast-C; ' + - 'iFirst-L; iSecond-L; iThird-L; iLast-L'); - - var div = element.find('div'); - expect(div.attr('i-first')).toEqual(''); - expect(div.attr('i-second')).toEqual(''); - expect(div.attr('i-third')).toEqual(''); - expect(div.attr('i-last')).toEqual(''); - - expect(div.text()).toEqual('3'); - })); - }); - - - it('should check that template has root element', inject(function($compile, $httpBackend) { - $httpBackend.expect('GET', 'hello.html').respond('before <b>mid</b> after'); - $compile('<div i-hello></div>'); - expect(function(){ - $httpBackend.flush(); - }).toThrow('Template must have exactly one root element: before <b>mid</b> after'); - })); - - - it('should allow multiple elements in template', inject(function($compile, $httpBackend) { - $httpBackend.expect('GET', 'hello.html').respond('before <b>mid</b> after'); - element = jqLite('<div hello></div>'); - $compile(element); - $httpBackend.flush(); - expect(element.text()).toEqual('before mid after'); - })); - - - it('should work when widget is in root element', inject( - function($compile, $httpBackend, $rootScope) { - $httpBackend.expect('GET', 'hello.html').respond('<span>3==<<content>></span>'); - element = jqLite('<b class="hello">{{1+2}}</b>'); - $compile(element)($rootScope); - - $httpBackend.flush(); - expect(element.text()).toEqual('3==3'); - } - )); - - - it('should work when widget is a repeater', inject( - function($compile, $httpBackend, $rootScope) { - $httpBackend.expect('GET', 'hello.html').respond('<span>i=<<content>>;</span>'); - element = jqLite('<div><b class=hello ng-repeat="i in [1,2]">{{i}}</b></div>'); - $compile(element)($rootScope); - - $httpBackend.flush(); - expect(element.text()).toEqual('i=1;i=2;'); - } - )); - }); - - - describe('scope', function() { - var iscope; - - beforeEach(module(function($compileProvider) { - forEach(['', 'a', 'b'], function(name) { - $compileProvider.directive('scope' + uppercase(name), function(log) { - return { - scope: true, - restrict: 'CA', - compile: function() { - return function (scope, element) { - log(scope.$id); - expect(element.data('$scope')).toBe(scope); - }; - } - }; - }); - $compileProvider.directive('iscope' + uppercase(name), function(log) { - return { - scope: {}, - restrict: 'CA', - compile: function() { - return function (scope, element) { - iscope = scope; - log(scope.$id); - expect(element.data('$scope')).toBe(scope); - }; - } - }; - }); - $compileProvider.directive('tiscope' + uppercase(name), function(log) { - return { - scope: {}, - restrict: 'CA', - templateUrl: 'tiscope.html', - compile: function() { - return function (scope, element) { - iscope = scope; - log(scope.$id); - expect(element.data('$scope')).toBe(scope); - }; - } - }; - }); - }); - $compileProvider.directive('log', function(log) { - return { - restrict: 'CA', - link: function(scope) { - log('log-' + scope.$id + '-' + scope.$parent.$id); - } - }; - }); - })); - - - it('should allow creation of new scopes', inject(function($rootScope, $compile, log) { - element = $compile('<div><span scope><a log></a></span></div>')($rootScope); - expect(log).toEqual('LOG; log-002-001; 002'); - expect(element.find('span').hasClass('ng-scope')).toBe(true); - })); - - - it('should allow creation of new isolated scopes for directives', inject( - function($rootScope, $compile, log) { - element = $compile('<div><span iscope><a log></a></span></div>')($rootScope); - expect(log).toEqual('LOG; log-002-001; 002'); - $rootScope.name = 'abc'; - expect(iscope.$parent).toBe($rootScope); - expect(iscope.name).toBeUndefined(); - })); - - - it('should allow creation of new isolated scopes for directives with templates', inject( - function($rootScope, $compile, log, $httpBackend) { - $httpBackend.expect('GET', 'tiscope.html').respond('<a log></a>'); - element = $compile('<div><span tiscope></span></div>')($rootScope); - $httpBackend.flush(); - expect(log).toEqual('LOG; log-002-001; 002'); - $rootScope.name = 'abc'; - expect(iscope.$parent).toBe($rootScope); - expect(iscope.name).toBeUndefined(); - })); - - - it('should correctly create the scope hierachy', inject( - function($rootScope, $compile, log) { - element = $compile( - '<div>' + //1 - '<b class=scope>' + //2 - '<b class=scope><b class=log></b></b>' + //3 - '<b class=log></b>' + - '</b>' + - '<b class=scope>' + //4 - '<b class=log></b>' + - '</b>' + - '</div>' - )($rootScope); - expect(log).toEqual('LOG; log-003-002; 003; LOG; log-002-001; 002; LOG; log-004-001; 004'); - }) - ); - - - it('should allow more one new scope directives per element, but directives should share' + - 'the scope', inject( - function($rootScope, $compile, log) { - element = $compile('<div class="scope-a; scope-b"></div>')($rootScope); - expect(log).toEqual('002; 002'); - }) - ); - - it('should not allow more then one isolate scope creation per element', inject( - function($rootScope, $compile) { - expect(function(){ - $compile('<div class="iscope-a; scope-b"></div>'); - }).toThrow('Multiple directives [iscopeA, scopeB] asking for isolated scope on: ' + - '<' + (msie < 9 ? 'DIV' : 'div') + - ' class="iscope-a; scope-b ng-isolate-scope ng-scope">'); - }) - ); - - - it('should not allow more then one isolate scope creation per element', inject( - function($rootScope, $compile) { - expect(function(){ - $compile('<div class="iscope-a; iscope-b"></div>'); - }).toThrow('Multiple directives [iscopeA, iscopeB] asking for isolated scope on: ' + - '<' + (msie < 9 ? 'DIV' : 'div') + - ' class="iscope-a; iscope-b ng-isolate-scope ng-scope">'); - }) - ); - - - it('should create new scope even at the root of the template', inject( - function($rootScope, $compile, log) { - element = $compile('<div scope-a></div>')($rootScope); - expect(log).toEqual('002'); - }) - ); - - - it('should create isolate scope even at the root of the template', inject( - function($rootScope, $compile, log) { - element = $compile('<div iscope></div>')($rootScope); - expect(log).toEqual('002'); - }) - ); - }); - }); - }); - - - describe('interpolation', function() { - var observeSpy, attrValueDuringLinking; - - beforeEach(module(function($compileProvider) { - $compileProvider.directive('observer', function() { - return function(scope, elm, attr) { - observeSpy = jasmine.createSpy('$observe attr'); - - attr.$observe('someAttr', observeSpy); - attrValueDuringLinking = attr.someAttr; - }; - }); - })); - - - it('should compile and link both attribute and text bindings', inject( - function($rootScope, $compile) { - $rootScope.name = 'angular'; - element = $compile('<div name="attr: {{name}}">text: {{name}}</div>')($rootScope); - $rootScope.$digest(); - expect(element.text()).toEqual('text: angular'); - expect(element.attr('name')).toEqual('attr: angular'); - })); - - - it('should decorate the binding with ng-binding and interpolation function', inject( - function($compile, $rootScope) { - element = $compile('<div>{{1+2}}</div>')($rootScope); - expect(element.hasClass('ng-binding')).toBe(true); - expect(element.data('$binding')[0].exp).toEqual('{{1+2}}'); - })); - - - it('should observe interpolated attrs', inject(function($rootScope, $compile) { - $compile('<div some-attr="{{value}}" observer></div>')($rootScope); - - // should be async - expect(observeSpy).not.toHaveBeenCalled(); - - $rootScope.$apply(function() { - $rootScope.value = 'bound-value'; - }); - expect(observeSpy).toHaveBeenCalledOnceWith('bound-value'); - })); - - - it('should set interpolated attrs to undefined', inject(function($rootScope, $compile) { - attrValueDuringLinking = null; - $compile('<div some-attr="{{whatever}}" observer></div>')($rootScope); - expect(attrValueDuringLinking).toBeUndefined(); - })); - - - it('should not call observer of non-interpolated attr', inject(function($rootScope, $compile) { - $compile('<div some-attr="nonBound" observer></div>')($rootScope); - expect(attrValueDuringLinking).toBe('nonBound'); - - $rootScope.$digest(); - expect(observeSpy).not.toHaveBeenCalled(); - })); - - - it('should delegate exceptions to $exceptionHandler', function() { - observeSpy = jasmine.createSpy('$observe attr').andThrow('ERROR'); - - module(function($compileProvider, $exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - $compileProvider.directive('error', function() { - return function(scope, elm, attr) { - attr.$observe('someAttr', observeSpy); - attr.$observe('someAttr', observeSpy); - }; - }); - }); - - inject(function($compile, $rootScope, $exceptionHandler) { - $compile('<div some-attr="{{value}}" error></div>')($rootScope); - $rootScope.$digest(); - - expect(observeSpy).toHaveBeenCalled(); - expect(observeSpy.callCount).toBe(2); - expect($exceptionHandler.errors).toEqual(['ERROR', 'ERROR']); - }); - }); - - - it('should translate {{}} in terminal nodes', inject(function($rootScope, $compile) { - element = $compile('<select ng:model="x"><option value="">Greet {{name}}!</option></select>')($rootScope) - $rootScope.$digest(); - expect(sortedHtml(element).replace(' selected="true"', '')). - toEqual('<select ng:model="x">' + - '<option>Greet !</option>' + - '</select>'); - $rootScope.name = 'Misko'; - $rootScope.$digest(); - expect(sortedHtml(element).replace(' selected="true"', '')). - toEqual('<select ng:model="x">' + - '<option>Greet Misko!</option>' + - '</select>'); - })); - }); - - - describe('link phase', function() { - - beforeEach(module(function($compileProvider) { - - forEach(['a', 'b', 'c'], function(name) { - $compileProvider.directive(name, function(log) { - return { - restrict: 'ECA', - compile: function() { - log('t' + uppercase(name)) - return { - pre: function() { - log('pre' + uppercase(name)); - }, - post: function linkFn() { - log('post' + uppercase(name)); - } - }; - } - }; - }); - }); - })); - - - it('should not store linkingFns for noop branches', inject(function ($rootScope, $compile) { - element = jqLite('<div name="{{a}}"><span>ignore</span></div>'); - var linkingFn = $compile(element); - // Now prune the branches with no directives - element.find('span').remove(); - expect(element.find('span').length).toBe(0); - // and we should still be able to compile without errors - linkingFn($rootScope); - })); - - - it('should compile from top to bottom but link from bottom up', inject( - function($compile, $rootScope, log) { - element = $compile('<a b><c></c></a>')($rootScope); - expect(log).toEqual('tA; tB; tC; preA; preB; preC; postC; postA; postB'); - } - )); - - - it('should support link function on directive object', function() { - module(function($compileProvider) { - $compileProvider.directive('abc', valueFn({ - link: function(scope, element, attrs) { - element.text(attrs.abc); - } - })); - }); - inject(function($compile, $rootScope) { - element = $compile('<div abc="WORKS">FAIL</div>')($rootScope); - expect(element.text()).toEqual('WORKS'); - }); - }); - }); - - - describe('attrs', function() { - - it('should allow setting of attributes', function() { - module(function($compileProvider) { - $compileProvider.directive({ - setter: valueFn(function(scope, element, attr) { - attr.$set('name', 'abc'); - attr.$set('disabled', true); - expect(attr.name).toBe('abc'); - expect(attr.disabled).toBe(true); - }) - }); - }); - inject(function($rootScope, $compile) { - element = $compile('<div setter></div>')($rootScope); - expect(element.attr('name')).toEqual('abc'); - expect(element.attr('disabled')).toEqual('disabled'); - }); - }); - - - it('should read boolean attributes as boolean only on control elements', function() { - var value; - module(function($compileProvider) { - $compileProvider.directive({ - input: valueFn({ - restrict: 'ECA', - link:function(scope, element, attr) { - value = attr.required; - } - }) - }); - }); - inject(function($rootScope, $compile) { - element = $compile('<input required></input>')($rootScope); - expect(value).toEqual(true); - }); - }); - - it('should read boolean attributes as text on non-controll elements', function() { - var value; - module(function($compileProvider) { - $compileProvider.directive({ - div: valueFn({ - restrict: 'ECA', - link:function(scope, element, attr) { - value = attr.required; - } - }) - }); - }); - inject(function($rootScope, $compile) { - element = $compile('<div required="some text"></div>')($rootScope); - expect(value).toEqual('some text'); - }); - }); - - it('should allow setting of attributes', function() { - module(function($compileProvider) { - $compileProvider.directive({ - setter: valueFn(function(scope, element, attr) { - attr.$set('name', 'abc'); - attr.$set('disabled', true); - expect(attr.name).toBe('abc'); - expect(attr.disabled).toBe(true); - }) - }); - }); - inject(function($rootScope, $compile) { - element = $compile('<div setter></div>')($rootScope); - expect(element.attr('name')).toEqual('abc'); - expect(element.attr('disabled')).toEqual('disabled'); - }); - }); - - - it('should create new instance of attr for each template stamping', function() { - module(function($compileProvider, $provide) { - var state = { first: [], second: [] }; - $provide.value('state', state); - $compileProvider.directive({ - first: valueFn({ - priority: 1, - compile: function(templateElement, templateAttr) { - return function(scope, element, attr) { - state.first.push({ - template: {element: templateElement, attr:templateAttr}, - link: {element: element, attr: attr} - }); - } - } - }), - second: valueFn({ - priority: 2, - compile: function(templateElement, templateAttr) { - return function(scope, element, attr) { - state.second.push({ - template: {element: templateElement, attr:templateAttr}, - link: {element: element, attr: attr} - }); - } - } - }) - }); - }); - inject(function($rootScope, $compile, state) { - var template = $compile('<div first second>'); - dealoc(template($rootScope.$new(), noop)); - dealoc(template($rootScope.$new(), noop)); - - // instance between directives should be shared - expect(state.first[0].template.element).toBe(state.second[0].template.element); - expect(state.first[0].template.attr).toBe(state.second[0].template.attr); - - // the template and the link can not be the same instance - expect(state.first[0].template.element).not.toBe(state.first[0].link.element); - expect(state.first[0].template.attr).not.toBe(state.first[0].link.attr); - - // each new template needs to be new instance - expect(state.first[0].link.element).not.toBe(state.first[1].link.element); - expect(state.first[0].link.attr).not.toBe(state.first[1].link.attr); - expect(state.second[0].link.element).not.toBe(state.second[1].link.element); - expect(state.second[0].link.attr).not.toBe(state.second[1].link.attr); - }); - }); - - - describe('$set', function() { - var attr; - beforeEach(function(){ - module(function($compileProvider) { - $compileProvider.directive('input', valueFn({ - restrict: 'ECA', - link: function(scope, element, attr) { - scope.attr = attr; - } - })); - }); - inject(function($compile, $rootScope) { - element = $compile('<input></input>')($rootScope); - attr = $rootScope.attr; - expect(attr).toBeDefined(); - }); - }); - - - it('should set attributes', function() { - attr.$set('ngMyAttr', 'value'); - expect(element.attr('ng-my-attr')).toEqual('value'); - expect(attr.ngMyAttr).toEqual('value'); - }); - - - it('should allow overriding of attribute name and remember the name', function() { - attr.$set('ngOther', '123', true, 'other'); - expect(element.attr('other')).toEqual('123'); - expect(attr.ngOther).toEqual('123'); - - attr.$set('ngOther', '246'); - expect(element.attr('other')).toEqual('246'); - expect(attr.ngOther).toEqual('246'); - }); - - - it('should remove attribute', function() { - attr.$set('ngMyAttr', 'value'); - expect(element.attr('ng-my-attr')).toEqual('value'); - - attr.$set('ngMyAttr', undefined); - expect(element.attr('ng-my-attr')).toBe(undefined); - - attr.$set('ngMyAttr', 'value'); - attr.$set('ngMyAttr', null); - expect(element.attr('ng-my-attr')).toBe(undefined); - }); - - - it('should not set DOM element attr if writeAttr false', function() { - attr.$set('test', 'value', false); - - expect(element.attr('test')).toBeUndefined(); - expect(attr.test).toBe('value'); - }); - }); - }); - - - describe('locals', function() { - it('should marshal to locals', function() { - module(function($compileProvider) { - $compileProvider.directive('widget', function(log) { - return { - scope: { - attr: 'attribute', - prop: 'evaluate', - bind: 'bind', - assign: 'accessor', - read: 'accessor', - exp: 'expression', - nonExist: 'accessor', - nonExistExpr: 'expression' - }, - link: function(scope, element, attrs) { - scope.nonExist(); // noop - scope.nonExist(123); // noop - scope.nonExistExpr(); // noop - scope.nonExistExpr(123); // noop - log(scope.attr); - log(scope.prop); - log(scope.assign()); - log(scope.read()); - log(scope.assign('ng')); - scope.exp({myState:'OK'}); - expect(function() { scope.read(undefined); }). - toThrow("Expression ''D'' not assignable."); - scope.$watch('bind', log); - } - }; - }); - }); - inject(function(log, $compile, $rootScope) { - $rootScope.myProp = 'B'; - $rootScope.bi = {nd: 'C'}; - $rootScope.name = 'C'; - element = $compile( - '<div><div widget attr="A" prop="myProp" bind="{{bi.nd}}" assign="name" read="\'D\'" ' + - 'exp="state=myState">{{bind}}</div></div>') - ($rootScope); - expect(log).toEqual('A; B; C; D; ng'); - expect($rootScope.name).toEqual('ng'); - expect($rootScope.state).toEqual('OK'); - log.reset(); - $rootScope.$apply(); - expect(element.text()).toEqual('C'); - expect(log).toEqual('C'); - $rootScope.bi.nd = 'c'; - $rootScope.$apply(); - expect(log).toEqual('C; c'); - }); - }); - }); - - - describe('controller', function() { - it('should inject locals to controller', function() { - module(function($compileProvider) { - $compileProvider.directive('widget', function(log) { - return { - controller: function(attr, prop, assign, read, exp){ - log(attr); - log(prop); - log(assign()); - log(read()); - log(assign('ng')); - exp(); - expect(function() { read(undefined); }). - toThrow("Expression ''D'' not assignable."); - this.result = 'OK'; - }, - inject: { - attr: 'attribute', - prop: 'evaluate', - assign: 'accessor', - read: 'accessor', - exp: 'expression' - }, - link: function(scope, element, attrs, controller) { - log(controller.result); - } - }; - }); - }); - inject(function(log, $compile, $rootScope) { - $rootScope.myProp = 'B'; - $rootScope.bi = {nd: 'C'}; - $rootScope.name = 'C'; - element = $compile( - '<div><div widget attr="A" prop="myProp" bind="{{bi.nd}}" assign="name" read="\'D\'" ' + - 'exp="state=\'OK\'">{{bind}}</div></div>') - ($rootScope); - expect(log).toEqual('A; B; C; D; ng; OK'); - expect($rootScope.name).toEqual('ng'); - }); - }); - - - it('should get required controller', function() { - module(function($compileProvider) { - $compileProvider.directive('main', function(log) { - return { - priority: 2, - controller: function() { - this.name = 'main'; - }, - link: function(scope, element, attrs, controller) { - log(controller.name); - } - }; - }); - $compileProvider.directive('dep', function(log) { - return { - priority: 1, - require: 'main', - link: function(scope, element, attrs, controller) { - log('dep:' + controller.name); - } - }; - }); - $compileProvider.directive('other', function(log) { - return { - link: function(scope, element, attrs, controller) { - log(!!controller); // should be false - } - }; - }); - }); - inject(function(log, $compile, $rootScope) { - element = $compile('<div main dep other></div>')($rootScope); - expect(log).toEqual('main; dep:main; false'); - }); - }); - - - it('should require controller on parent element',function() { - module(function($compileProvider) { - $compileProvider.directive('main', function(log) { - return { - controller: function() { - this.name = 'main'; - } - }; - }); - $compileProvider.directive('dep', function(log) { - return { - require: '^main', - link: function(scope, element, attrs, controller) { - log('dep:' + controller.name); - } - }; - }); - }); - inject(function(log, $compile, $rootScope) { - element = $compile('<div main><div dep></div></div>')($rootScope); - expect(log).toEqual('dep:main'); - }); - }); - - - it('should have optional controller on current element', function() { - module(function($compileProvider) { - $compileProvider.directive('dep', function(log) { - return { - require: '?main', - link: function(scope, element, attrs, controller) { - log('dep:' + !!controller); - } - }; - }); - }); - inject(function(log, $compile, $rootScope) { - element = $compile('<div main><div dep></div></div>')($rootScope); - expect(log).toEqual('dep:false'); - }); - }); - - - it('should support multiple controllers', function() { - module(function($compileProvider) { - $compileProvider.directive('c1', valueFn({ - controller: function() { this.name = 'c1'; } - })); - $compileProvider.directive('c2', valueFn({ - controller: function() { this.name = 'c2'; } - })); - $compileProvider.directive('dep', function(log) { - return { - require: ['^c1', '^c2'], - link: function(scope, element, attrs, controller) { - log('dep:' + controller[0].name + '-' + controller[1].name); - } - }; - }); - }); - inject(function(log, $compile, $rootScope) { - element = $compile('<div c1 c2><div dep></div></div>')($rootScope); - expect(log).toEqual('dep:c1-c2'); - }); - - }); - }); - - - describe('transclude', function() { - it('should compile get templateFn', function() { - module(function($compileProvider) { - $compileProvider.directive('trans', function(log) { - return { - transclude: 'element', - priority: 2, - controller: function($transclude) { this.$transclude = $transclude; }, - compile: function(element, attrs, template) { - log('compile: ' + angular.mock.dump(element)); - return function(scope, element, attrs, ctrl) { - log('link'); - var cursor = element; - template(scope.$new(), function(clone) {cursor.after(cursor = clone)}); - ctrl.$transclude(function(clone) {cursor.after(clone)}); - }; - } - } - }); - }); - inject(function(log, $rootScope, $compile) { - element = $compile('<div><div high-log trans="text" log>{{$parent.$id}}-{{$id}};</div></div>') - ($rootScope); - $rootScope.$apply(); - expect(log).toEqual('compile: <!-- trans: text -->; HIGH; link; LOG; LOG'); - expect(element.text()).toEqual('001-002;001-003;'); - }); - }); - - - it('should support transclude directive', function() { - module(function($compileProvider) { - $compileProvider.directive('trans', function() { - return { - transclude: 'content', - replace: true, - scope: true, - template: '<ul><li>W:{{$parent.$id}}-{{$id}};</li><li ng-transclude></li></ul>' - } - }); - }); - inject(function(log, $rootScope, $compile) { - element = $compile('<div><div trans>T:{{$parent.$id}}-{{$id}}<span>;</span></div></div>') - ($rootScope); - $rootScope.$apply(); - expect(element.text()).toEqual('W:001-002;T:001-003;'); - expect(jqLite(element.find('span')[0]).text()).toEqual('T:001-003'); - expect(jqLite(element.find('span')[1]).text()).toEqual(';'); - }); - }); - - - it('should transclude transcluded content', function() { - module(function($compileProvider) { - $compileProvider.directive('book', valueFn({ - transclude: 'content', - template: '<div>book-<div chapter>(<div ng-transclude></div>)</div></div>' - })); - $compileProvider.directive('chapter', valueFn({ - transclude: 'content', - templateUrl: 'chapter.html' - })); - $compileProvider.directive('section', valueFn({ - transclude: 'content', - template: '<div>section-!<div ng-transclude></div>!</div></div>' - })); - return function($httpBackend) { - $httpBackend. - expect('GET', 'chapter.html'). - respond('<div>chapter-<div section>[<div ng-transclude></div>]</div></div>'); - } - }); - inject(function(log, $rootScope, $compile, $httpBackend) { - element = $compile('<div><div book>paragraph</div></div>')($rootScope); - $rootScope.$apply(); - - expect(element.text()).toEqual('book-'); - - $httpBackend.flush(); - $rootScope.$apply(); - expect(element.text()).toEqual('book-chapter-section-![(paragraph)]!'); - }); - }); - - - it('should only allow one transclude per element', function() { - module(function($compileProvider) { - $compileProvider.directive('first', valueFn({ - scope: {}, - restrict: 'CA', - transclude: 'content' - })); - $compileProvider.directive('second', valueFn({ - restrict: 'CA', - transclude: 'content' - })); - }); - inject(function($compile) { - expect(function() { - $compile('<div class="first second"></div>'); - }).toThrow('Multiple directives [first, second] asking for transclusion on: <' + - (msie <= 8 ? 'DIV' : 'div') + ' class="first second ng-isolate-scope ng-scope">'); - }); - }); - - - it('should remove transclusion scope, when the DOM is destroyed', function() { - module(function($compileProvider) { - $compileProvider.directive('box', valueFn({ - transclude: 'content', - scope: { name: 'evaluate', show: 'accessor' }, - template: '<div><h1>Hello: {{name}}!</h1><div ng-transclude></div></div>', - link: function(scope, element) { - scope.$watch( - function() { return scope.show(); }, - function(show) { - if (!show) { - element.find('div').find('div').remove(); - } - } - ); - } - })); - }); - inject(function($compile, $rootScope) { - $rootScope.username = 'Misko'; - $rootScope.select = true; - element = $compile( - '<div><div box name="username" show="select">user: {{username}}</div></div>') - ($rootScope); - $rootScope.$apply(); - expect(element.text()).toEqual('Hello: Misko!user: Misko'); - - var widgetScope = $rootScope.$$childHead; - var transcludeScope = widgetScope.$$nextSibling; - expect(widgetScope.name).toEqual('Misko'); - expect(widgetScope.$parent).toEqual($rootScope); - expect(transcludeScope.$parent).toEqual($rootScope); - - $rootScope.select = false; - $rootScope.$apply(); - expect(element.text()).toEqual('Hello: Misko!'); - expect(widgetScope.$$nextSibling).toEqual(null); - }); - }); - - - it('should support transcluded element on root content', function() { - var comment; - module(function($compileProvider) { - $compileProvider.directive('transclude', valueFn({ - transclude: 'element', - compile: function(element, attr, linker) { - return function(scope, element, attr) { - comment = element; - }; - } - })); - }); - inject(function($compile, $rootScope) { - var element = jqLite('<div>before<div transclude></div>after</div>').contents(); - expect(element.length).toEqual(3); - expect(nodeName_(element[1])).toBe('DIV'); - $compile(element)($rootScope); - expect(nodeName_(element[1])).toBe('#comment'); - expect(nodeName_(comment)).toBe('#comment'); - }); - }); - }); -}); diff --git a/test/service/controllerSpec.js b/test/service/controllerSpec.js deleted file mode 100644 index 91389013..00000000 --- a/test/service/controllerSpec.js +++ /dev/null @@ -1,73 +0,0 @@ -'use strict'; - -describe('$controller', function() { - var $controllerProvider, $controller; - - beforeEach(module(function(_$controllerProvider_) { - $controllerProvider = _$controllerProvider_; - })); - - - beforeEach(inject(function(_$controller_) { - $controller = _$controller_; - })); - - - describe('provider', function() { - - it('should allow registration of controllers', function() { - var FooCtrl = function($scope) { $scope.foo = 'bar' }, - scope = {}, - ctrl; - - $controllerProvider.register('FooCtrl', FooCtrl); - ctrl = $controller('FooCtrl', {$scope: scope}); - - expect(scope.foo).toBe('bar'); - expect(ctrl instanceof FooCtrl).toBe(true); - }); - - - it('should allow registration of controllers annotated with arrays', function() { - var FooCtrl = function($scope) { $scope.foo = 'bar' }, - scope = {}, - ctrl; - - $controllerProvider.register('FooCtrl', ['$scope', FooCtrl]); - ctrl = $controller('FooCtrl', {$scope: scope}); - - expect(scope.foo).toBe('bar'); - expect(ctrl instanceof FooCtrl).toBe(true); - }); - }); - - - it('should return instance of given controller class', function() { - var MyClass = function() {}, - ctrl = $controller(MyClass); - - expect(ctrl).toBeDefined(); - expect(ctrl instanceof MyClass).toBe(true); - }); - - it('should inject arguments', inject(function($http) { - var MyClass = function($http) { - this.$http = $http; - }; - - var ctrl = $controller(MyClass); - expect(ctrl.$http).toBe($http); - })); - - - it('should inject given scope', function() { - var MyClass = function($scope) { - this.$scope = $scope; - }; - - var scope = {}, - ctrl = $controller(MyClass, {$scope: scope}); - - expect(ctrl.$scope).toBe(scope); - }); -}); diff --git a/test/service/cookieStoreSpec.js b/test/service/cookieStoreSpec.js deleted file mode 100644 index 50ac7797..00000000 --- a/test/service/cookieStoreSpec.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -describe('$cookieStore', function() { - - - it('should serialize objects to json', inject(function($cookieStore, $browser, $rootScope) { - $cookieStore.put('objectCookie', {id: 123, name: 'blah'}); - $rootScope.$digest(); - expect($browser.cookies()).toEqual({'objectCookie': '{"id":123,"name":"blah"}'}); - })); - - - it('should deserialize json to object', inject(function($cookieStore, $browser) { - $browser.cookies('objectCookie', '{"id":123,"name":"blah"}'); - $browser.poll(); - expect($cookieStore.get('objectCookie')).toEqual({id: 123, name: 'blah'}); - })); - - - it('should delete objects from the store when remove is called', inject(function($cookieStore, $browser, $rootScope) { - $cookieStore.put('gonner', { "I'll":"Be Back"}); - $rootScope.$digest(); //force eval in test - $browser.poll(); - expect($browser.cookies()).toEqual({'gonner': '{"I\'ll":"Be Back"}'}); - - $cookieStore.remove('gonner'); - $rootScope.$digest(); - expect($browser.cookies()).toEqual({}); - })); -}); diff --git a/test/service/cookiesSpec.js b/test/service/cookiesSpec.js deleted file mode 100644 index 5427ac36..00000000 --- a/test/service/cookiesSpec.js +++ /dev/null @@ -1,97 +0,0 @@ -'use strict'; - -describe('$cookies', function() { - beforeEach(module(function($provide) { - $provide.factory('$browser', function(){ - return angular.extend(new angular.mock.$Browser(), {cookieHash: {preexisting:'oldCookie'}}); - }); - })); - - - it('should provide access to existing cookies via object properties and keep them in sync', - inject(function($cookies, $browser, $rootScope) { - expect($cookies).toEqual({'preexisting': 'oldCookie'}); - - // access internal cookie storage of the browser mock directly to simulate behavior of - // document.cookie - $browser.cookieHash['brandNew'] = 'cookie'; - $browser.poll(); - - expect($cookies).toEqual({'preexisting': 'oldCookie', 'brandNew':'cookie'}); - - $browser.cookieHash['brandNew'] = 'cookie2'; - $browser.poll(); - expect($cookies).toEqual({'preexisting': 'oldCookie', 'brandNew':'cookie2'}); - - delete $browser.cookieHash['brandNew']; - $browser.poll(); - expect($cookies).toEqual({'preexisting': 'oldCookie'}); - })); - - - it('should create or update a cookie when a value is assigned to a property', - inject(function($cookies, $browser, $rootScope) { - $cookies.oatmealCookie = 'nom nom'; - $rootScope.$digest(); - - expect($browser.cookies()). - toEqual({'preexisting': 'oldCookie', 'oatmealCookie':'nom nom'}); - - $cookies.oatmealCookie = 'gone'; - $rootScope.$digest(); - - expect($browser.cookies()). - toEqual({'preexisting': 'oldCookie', 'oatmealCookie': 'gone'}); - })); - - - it('should drop or reset any cookie that was set to a non-string value', - inject(function($cookies, $browser, $rootScope) { - $cookies.nonString = [1, 2, 3]; - $cookies.nullVal = null; - $cookies.undefVal = undefined; - $cookies.preexisting = function() {}; - $rootScope.$digest(); - expect($browser.cookies()).toEqual({'preexisting': 'oldCookie'}); - expect($cookies).toEqual({'preexisting': 'oldCookie'}); - })); - - - it('should remove a cookie when a $cookies property is deleted', - inject(function($cookies, $browser, $rootScope) { - $cookies.oatmealCookie = 'nom nom'; - $rootScope.$digest(); - $browser.poll(); - expect($browser.cookies()). - toEqual({'preexisting': 'oldCookie', 'oatmealCookie':'nom nom'}); - - delete $cookies.oatmealCookie; - $rootScope.$digest(); - - expect($browser.cookies()).toEqual({'preexisting': 'oldCookie'}); - })); - - - it('should drop or reset cookies that browser refused to store', - inject(function($cookies, $browser, $rootScope) { - var i, longVal; - - for (i=0; i<5000; i++) { - longVal += '*'; - } - - //drop if no previous value - $cookies.longCookie = longVal; - $rootScope.$digest(); - expect($cookies).toEqual({'preexisting': 'oldCookie'}); - - - //reset if previous value existed - $cookies.longCookie = 'shortVal'; - $rootScope.$digest(); - expect($cookies).toEqual({'preexisting': 'oldCookie', 'longCookie': 'shortVal'}); - $cookies.longCookie = longVal; - $rootScope.$digest(); - expect($cookies).toEqual({'preexisting': 'oldCookie', 'longCookie': 'shortVal'}); - })); -}); diff --git a/test/service/deferSpec.js b/test/service/deferSpec.js deleted file mode 100644 index 48c9e912..00000000 --- a/test/service/deferSpec.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -describe('$defer', function() { - beforeEach(module(function($provide) { - $provide.factory('$exceptionHandler', function(){ - return jasmine.createSpy('$exceptionHandler'); - }); - })); - - - it('should delegate functions to $browser.defer', inject(function($defer, $browser, $exceptionHandler) { - var counter = 0; - $defer(function() { counter++; }); - - expect(counter).toBe(0); - - $browser.defer.flush(); - expect(counter).toBe(1); - - expect(function() {$browser.defer.flush();}).toThrow('No deferred tasks to be flushed'); - expect(counter).toBe(1); - - expect($exceptionHandler).not.toHaveBeenCalled(); - })); - - - it('should delegate exception to the $exceptionHandler service', inject(function($defer, $browser, $exceptionHandler) { - $defer(function() {throw "Test Error";}); - expect($exceptionHandler).not.toHaveBeenCalled(); - - $browser.defer.flush(); - expect($exceptionHandler).toHaveBeenCalledWith("Test Error"); - })); - - - it('should call $apply after each callback is executed', inject(function($defer, $browser, $rootScope) { - var applySpy = this.spyOn($rootScope, '$apply').andCallThrough(); - - $defer(function() {}); - expect(applySpy).not.toHaveBeenCalled(); - - $browser.defer.flush(); - expect(applySpy).toHaveBeenCalled(); - - applySpy.reset(); //reset the spy; - - $defer(function() {}); - $defer(function() {}); - $browser.defer.flush(); - expect(applySpy.callCount).toBe(2); - })); - - - it('should call $apply even if an exception is thrown in callback', inject(function($defer, $browser, $rootScope) { - var applySpy = this.spyOn($rootScope, '$apply').andCallThrough(); - - $defer(function() {throw "Test Error";}); - expect(applySpy).not.toHaveBeenCalled(); - - $browser.defer.flush(); - expect(applySpy).toHaveBeenCalled(); - })); - - - it('should allow you to specify the delay time', inject(function($defer, $browser) { - var defer = this.spyOn($browser, 'defer'); - $defer(noop, 123); - expect(defer.callCount).toEqual(1); - expect(defer.mostRecentCall.args[1]).toEqual(123); - })); - - - it('should return a cancelation token', inject(function($defer, $browser) { - var defer = this.spyOn($browser, 'defer').andReturn('xxx'); - expect($defer(noop)).toEqual('xxx'); - })); - - - describe('cancel', function() { - it('should cancel tasks', inject(function($defer, $browser) { - var task1 = jasmine.createSpy('task1'), - task2 = jasmine.createSpy('task2'), - task3 = jasmine.createSpy('task3'), - token1, token3; - - token1 = $defer(task1); - $defer(task2); - token3 = $defer(task3, 333); - - $defer.cancel(token3); - $defer.cancel(token1); - $browser.defer.flush(); - - expect(task1).not.toHaveBeenCalled(); - expect(task2).toHaveBeenCalledOnce(); - expect(task3).not.toHaveBeenCalled(); - })); - - - it('should return true if a task was succesffuly canceled', inject(function($defer, $browser) { - var task1 = jasmine.createSpy('task1'), - task2 = jasmine.createSpy('task2'), - token1, token2; - - token1 = $defer(task1); - $browser.defer.flush(); - token2 = $defer(task2); - - expect($defer.cancel(token1)).toBe(false); - expect($defer.cancel(token2)).toBe(true); - })); - }); -}); diff --git a/test/service/documentSpec.js b/test/service/documentSpec.js deleted file mode 100644 index 064904a2..00000000 --- a/test/service/documentSpec.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -describe('$document', function() { - - - it("should inject $document", inject(function($document) { - expect($document).toEqual(jqLite(document)); - })); -}); diff --git a/test/service/exceptionHandlerSpec.js b/test/service/exceptionHandlerSpec.js deleted file mode 100644 index 3f3dd800..00000000 --- a/test/service/exceptionHandlerSpec.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -describe('$exceptionHandler', function() { - it('should log errors with single argument', function() { - module(function($provide){ - $provide.provider('$exceptionHandler', $ExceptionHandlerProvider); - }); - inject(function($log, $exceptionHandler) { - $exceptionHandler('myError'); - expect($log.error.logs.shift()).toEqual(['myError']); - }); - }); - - - it('should log errors with multiple arguments', function() { - module(function($provide){ - $provide.provider('$exceptionHandler', $ExceptionHandlerProvider); - }); - inject(function($log, $exceptionHandler) { - $exceptionHandler('myError', 'comment'); - expect($log.error.logs.shift()).toEqual(['myError', 'comment']); - }); - }); -}); diff --git a/test/service/filter/filterSpec.js b/test/service/filter/filterSpec.js deleted file mode 100644 index a33358d0..00000000 --- a/test/service/filter/filterSpec.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -describe('Filter: filter', function() { - var filter; - - beforeEach(inject(function($filter){ - filter = $filter('filter'); - })); - - it('should filter by string', function() { - var items = ['MIsKO', {name: 'shyam'}, ['adam'], 1234]; - expect(filter(items, '').length).toBe(4); - expect(filter(items, undefined).length).toBe(4); - - expect(filter(items, 'iSk').length).toBe(1); - expect(filter(items, 'isk')[0]).toBe('MIsKO'); - - expect(filter(items, 'yam').length).toBe(1); - expect(filter(items, 'yam')[0]).toEqual(items[1]); - - expect(filter(items, 'da').length).toBe(1); - expect(filter(items, 'da')[0]).toEqual(items[2]); - - expect(filter(items, '34').length).toBe(1); - expect(filter(items, '34')[0]).toBe(1234); - - expect(filter(items, "I don't exist").length).toBe(0); - }); - - it('should not read $ properties', function() { - expect(''.charAt(0)).toBe(''); // assumption - - var items = [{$name: 'misko'}]; - expect(filter(items, 'misko').length).toBe(0); - }); - - it('should filter on specific property', function() { - var items = [{ignore: 'a', name: 'a'}, {ignore: 'a', name: 'abc'}]; - expect(filter(items, {}).length).toBe(2); - - expect(filter(items, {name: 'a'}).length).toBe(2); - - expect(filter(items, {name: 'b'}).length).toBe(1); - expect(filter(items, {name: 'b'})[0].name).toBe('abc'); - }); - - it('should take function as predicate', function() { - var items = [{name: 'a'}, {name: 'abc', done: true}]; - expect(filter(items, function(i) {return i.done;}).length).toBe(1); - }); - - it('should take object as perdicate', function() { - var items = [{first: 'misko', last: 'hevery'}, - {first: 'adam', last: 'abrons'}]; - - expect(filter(items, {first:'', last:''}).length).toBe(2); - expect(filter(items, {first:'', last:'hevery'}).length).toBe(1); - expect(filter(items, {first:'adam', last:'hevery'}).length).toBe(0); - expect(filter(items, {first:'misko', last:'hevery'}).length).toBe(1); - expect(filter(items, {first:'misko', last:'hevery'})[0]).toEqual(items[0]); - }); - - it('should support negation operator', function() { - var items = ['misko', 'adam']; - - expect(filter(items, '!isk').length).toBe(1); - expect(filter(items, '!isk')[0]).toEqual(items[1]); - }); -}); diff --git a/test/service/filter/filtersSpec.js b/test/service/filter/filtersSpec.js deleted file mode 100644 index 98651c58..00000000 --- a/test/service/filter/filtersSpec.js +++ /dev/null @@ -1,280 +0,0 @@ -'use strict'; - -describe('filters', function() { - - var filter; - - beforeEach(inject(function($filter){ - filter = $filter; - })); - - it('should call the filter when evaluating expression', function(){ - var filter = jasmine.createSpy('myFilter'); - createInjector(['ng', function($filterProvider) { - $filterProvider.register('myFilter', valueFn(filter)); - }]).invoke(function($rootScope) { - $rootScope.$eval('10|myFilter'); - }); - expect(filter).toHaveBeenCalledWith(10); - }); - - describe('formatNumber', function() { - var pattern; - - beforeEach(function() { - pattern = { minInt: 1, - minFrac: 0, - maxFrac: 3, - posPre: '', - posSuf: '', - negPre: '-', - negSuf: '', - gSize: 3, - lgSize: 3 }; - }); - - it('should format according to different patterns', function() { - pattern.gSize = 2; - var num = formatNumber(1234567.89, pattern, ',', '.'); - expect(num).toBe('12,34,567.89'); - num = formatNumber(1234.56, pattern, ',', '.'); - expect(num).toBe('1,234.56'); - - pattern.negPre = '('; - pattern.negSuf = '-)'; - num = formatNumber(-1234, pattern, ',', '.'); - expect(num).toBe('(1,234-)'); - pattern.posPre = '+'; - pattern.posSuf = '+'; - num = formatNumber(1234, pattern, ',', '.'); - expect(num).toBe('+1,234+'); - pattern.posPre = pattern.posSuf = ''; - - pattern.minFrac = 2; - num = formatNumber(1, pattern, ',', '.'); - expect(num).toBe('1.00'); - pattern.maxFrac = 4; - num = formatNumber(1.11119, pattern, ',', '.'); - expect(num).toBe('1.1112'); - }); - - it('should format according different seperators', function() { - var num = formatNumber(1234567.1, pattern, '.', ',', 2); - expect(num).toBe('1.234.567,10'); - }); - - it('should format with or without fractionSize', function() { - var num = formatNumber(123.1, pattern, ',', '.', 3); - expect(num).toBe('123.100'); - num = formatNumber(123.12, pattern, ',', '.'); - expect(num).toBe('123.12'); - var num = formatNumber(123.1116, pattern, ',', '.'); - expect(num).toBe('123.112'); - }); - }); - - describe('currency', function() { - var currency; - - beforeEach(function() { - currency = filter('currency'); - }); - - it('should do basic currency filtering', function() { - expect(currency(0)).toEqual('$0.00'); - expect(currency(-999)).toEqual('($999.00)'); - expect(currency(1234.5678, "USD$")).toEqual('USD$1,234.57'); - }); - - - it('should return empty string for non-numbers', function() { - expect(currency()).toBe(''); - expect(currency('abc')).toBe(''); - }); - }); - - - describe('number', function() { - var number; - - beforeEach(inject(function($rootScope) { - number = filter('number'); - })); - - - it('should do basic filter', function() { - expect(number(0, 0)).toEqual('0'); - expect(number(-999)).toEqual('-999'); - expect(number(123)).toEqual('123'); - expect(number(1234567)).toEqual('1,234,567'); - expect(number(1234)).toEqual('1,234'); - expect(number(1234.5678)).toEqual('1,234.568'); - expect(number(Number.NaN)).toEqual(''); - expect(number("1234.5678")).toEqual('1,234.568'); - expect(number(1/0)).toEqual(""); - expect(number(1, 2)).toEqual("1.00"); - expect(number(.1, 2)).toEqual("0.10"); - expect(number(.01, 2)).toEqual("0.01"); - expect(number(.001, 3)).toEqual("0.001"); - expect(number(.0001, 3)).toEqual("0.000"); - expect(number(9, 2)).toEqual("9.00"); - expect(number(.9, 2)).toEqual("0.90"); - expect(number(.99, 2)).toEqual("0.99"); - expect(number(.999, 3)).toEqual("0.999"); - expect(number(.9999, 3)).toEqual("1.000"); - expect(number(1234.567, 0)).toEqual("1,235"); - expect(number(1234.567, 1)).toEqual("1,234.6"); - expect(number(1234.567, 2)).toEqual("1,234.57"); - }); - - it('should filter exponential numbers', function() { - expect(number(1e50, 0)).toEqual('1e+50'); - expect(number(-2e50, 2)).toEqual('-2e+50'); - }); - }); - - describe('json', function () { - it('should do basic filter', function() { - expect(filter('json')({a:"b"})).toEqual(toJson({a:"b"}, true)); - }); - }); - - describe('lowercase', function() { - it('should do basic filter', function() { - expect(filter('lowercase')('AbC')).toEqual('abc'); - expect(filter('lowercase')(null)).toBeNull(); - }); - }); - - describe('uppercase', function() { - it('should do basic filter', function() { - expect(filter('uppercase')('AbC')).toEqual('ABC'); - expect(filter('uppercase')(null)).toBeNull(); - }); - }); - - describe('linky', function() { - var linky; - - beforeEach(inject(function($filter){ - linky = $filter('linky') - })); - - it('should do basic filter', function() { - expect(linky("http://ab/ (http://a/) <http://a/> http://1.2/v:~-123. c")). - toEqual('<a href="http://ab/">http://ab/</a> ' + - '(<a href="http://a/">http://a/</a>) ' + - '<<a href="http://a/">http://a/</a>> ' + - '<a href="http://1.2/v:~-123">http://1.2/v:~-123</a>. c'); - expect(linky(undefined)).not.toBeDefined(); - }); - - it('should handle mailto:', function() { - expect(linky("mailto:me@example.com")). - toEqual('<a href="mailto:me@example.com">me@example.com</a>'); - expect(linky("me@example.com")). - toEqual('<a href="mailto:me@example.com">me@example.com</a>'); - expect(linky("send email to me@example.com, but")). - toEqual('send email to <a href="mailto:me@example.com">me@example.com</a>, but'); - }); - }); - - describe('date', function() { - - var morning = new angular.mock.TzDate(+5, '2010-09-03T12:05:08.000Z'); //7am - var noon = new angular.mock.TzDate(+5, '2010-09-03T17:05:08.000Z'); //12pm - var midnight = new angular.mock.TzDate(+5, '2010-09-03T05:05:08.000Z'); //12am - var earlyDate = new angular.mock.TzDate(+5, '0001-09-03T05:05:08.000Z'); - - var date; - - beforeEach(inject(function($filter) { - date = $filter('date'); - })); - - it('should ignore falsy inputs', function() { - expect(date(null)).toBeNull(); - expect(date('')).toEqual(''); - }); - - it('should do basic filter', function() { - expect(date(noon)).toEqual(date(noon, 'mediumDate')); - expect(date(noon, '')).toEqual(date(noon, 'mediumDate')); - }); - - it('should accept number or number string representing milliseconds as input', function() { - expect(date(noon.getTime())).toEqual(date(noon.getTime(), 'mediumDate')); - expect(date(noon.getTime() + "")).toEqual(date(noon.getTime() + "", 'mediumDate')); - }); - - it('should accept various format strings', function() { - expect(date(morning, "yy-MM-dd HH:mm:ss")). - toEqual('10-09-03 07:05:08'); - - expect(date(midnight, "yyyy-M-d h=H:m:saZ")). - toEqual('2010-9-3 12=0:5:8AM0500'); - - expect(date(midnight, "yyyy-MM-dd hh=HH:mm:ssaZ")). - toEqual('2010-09-03 12=00:05:08AM0500'); - - expect(date(noon, "yyyy-MM-dd hh=HH:mm:ssaZ")). - toEqual('2010-09-03 12=12:05:08PM0500'); - - expect(date(noon, "EEE, MMM d, yyyy")). - toEqual('Fri, Sep 3, 2010'); - - expect(date(noon, "EEEE, MMMM dd, yyyy")). - toEqual('Friday, September 03, 2010'); - - expect(date(earlyDate, "MMMM dd, y")). - toEqual('September 03, 1'); - }); - - it('should treat single quoted strings as string literals', function() { - expect(date(midnight, "yyyy'de' 'a'x'dd' 'adZ' h=H:m:saZ")). - toEqual('2010de axdd adZ 12=0:5:8AM0500'); - }); - - it('should treat a sequence of two single quotes as a literal single quote', function() { - expect(date(midnight, "yyyy'de' 'a''dd' 'adZ' h=H:m:saZ")). - toEqual("2010de a'dd adZ 12=0:5:8AM0500"); - }); - - it('should accept default formats', function() { - - expect(date(noon, "medium")). - toEqual('Sep 3, 2010 12:05:08 PM'); - - expect(date(noon, "short")). - toEqual('9/3/10 12:05 PM'); - - expect(date(noon, "fullDate")). - toEqual('Friday, September 3, 2010'); - - expect(date(noon, "longDate")). - toEqual('September 3, 2010'); - - expect(date(noon, "mediumDate")). - toEqual('Sep 3, 2010'); - - expect(date(noon, "shortDate")). - toEqual('9/3/10'); - - expect(date(noon, "mediumTime")). - toEqual('12:05:08 PM'); - - expect(date(noon, "shortTime")). - toEqual('12:05 PM'); - }); - - it('should be able to parse ISO 8601 dates/times using', function() { - var isoString = '2010-09-03T05:05:08.872Z'; - expect(date(isoString)). - toEqual(date(isoString, 'mediumDate')); - }); - - it('should parse format ending with non-replaced string', function() { - expect(date(morning, 'yy/xxx')).toEqual('10/xxx'); - }); - }); -}); diff --git a/test/service/filter/limitToSpec.js b/test/service/filter/limitToSpec.js deleted file mode 100644 index b0977235..00000000 --- a/test/service/filter/limitToSpec.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -describe('Filter: limitTo', function() { - var items; - var limitTo; - - beforeEach(inject(function($filter) { - items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; - limitTo = $filter('limitTo'); - })); - - - it('should return the first X items when X is positive', function() { - expect(limitTo(items, 3)).toEqual(['a', 'b', 'c']); - expect(limitTo(items, '3')).toEqual(['a', 'b', 'c']); - }); - - - it('should return the last X items when X is negative', function() { - expect(limitTo(items, -3)).toEqual(['f', 'g', 'h']); - expect(limitTo(items, '-3')).toEqual(['f', 'g', 'h']); - }); - - - it('should return an empty array when X cannot be parsed', function() { - expect(limitTo(items, 'bogus')).toEqual([]); - expect(limitTo(items, 'null')).toEqual([]); - expect(limitTo(items, 'undefined')).toEqual([]); - expect(limitTo(items, null)).toEqual([]); - expect(limitTo(items, undefined)).toEqual([]); - }); - - - it('should return an empty array when input is not Array type', function() { - expect(limitTo('bogus', 1)).toEqual('bogus'); - expect(limitTo(null, 1)).toEqual(null); - expect(limitTo(undefined, 1)).toEqual(undefined); - expect(limitTo(null, 1)).toEqual(null); - expect(limitTo(undefined, 1)).toEqual(undefined); - expect(limitTo({}, 1)).toEqual({}); - }); - - - it('should return a copy of input array if X is exceeds array length', function () { - expect(limitTo(items, 19)).toEqual(items); - expect(limitTo(items, '9')).toEqual(items); - expect(limitTo(items, -9)).toEqual(items); - expect(limitTo(items, '-9')).toEqual(items); - - expect(limitTo(items, 9)).not.toBe(items); - }); -}); diff --git a/test/service/filter/orderBySpec.js b/test/service/filter/orderBySpec.js deleted file mode 100644 index 5c117891..00000000 --- a/test/service/filter/orderBySpec.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -describe('Filter: orderBy', function() { - var orderBy; - beforeEach(inject(function($filter) { - orderBy = $filter('orderBy'); - })); - - it('should return same array if predicate is falsy', function() { - var array = [1, 2, 3]; - expect(orderBy(array)).toBe(array); - }); - - it('shouldSortArrayInReverse', function() { - expect(orderBy([{a:15}, {a:2}], 'a', true)).toEqualData([{a:15}, {a:2}]); - expect(orderBy([{a:15}, {a:2}], 'a', "T")).toEqualData([{a:15}, {a:2}]); - expect(orderBy([{a:15}, {a:2}], 'a', "reverse")).toEqualData([{a:15}, {a:2}]); - }); - - it('should sort array by predicate', function() { - expect(orderBy([{a:15, b:1}, {a:2, b:1}], ['a', 'b'])).toEqualData([{a:2, b:1}, {a:15, b:1}]); - expect(orderBy([{a:15, b:1}, {a:2, b:1}], ['b', 'a'])).toEqualData([{a:2, b:1}, {a:15, b:1}]); - expect(orderBy([{a:15, b:1}, {a:2, b:1}], ['+b', '-a'])).toEqualData([{a:15, b:1}, {a:2, b:1}]); - }); - - it('should use function', function() { - expect( - orderBy( - [{a:15, b:1},{a:2, b:1}], - function(value) { return value.a; })). - toEqual([{a:2, b:1},{a:15, b:1}]); - }); - -}); diff --git a/test/service/httpBackendSpec.js b/test/service/httpBackendSpec.js deleted file mode 100644 index 820099e8..00000000 --- a/test/service/httpBackendSpec.js +++ /dev/null @@ -1,241 +0,0 @@ -describe('$httpBackend', function() { - - var $backend, $browser, callbacks, - xhr, fakeBody, callback; - - // TODO(vojta): should be replaced by $defer mock - function fakeTimeout(fn, delay) { - fakeTimeout.fns.push(fn); - fakeTimeout.delays.push(delay); - } - - fakeTimeout.fns = []; - fakeTimeout.delays = []; - fakeTimeout.flush = function() { - var len = fakeTimeout.fns.length; - fakeTimeout.delays = []; - while (len--) fakeTimeout.fns.shift()(); - }; - - - beforeEach(inject(function($injector) { - callbacks = {counter: 0}; - $browser = $injector.get('$browser'); - fakeBody = {removeChild: jasmine.createSpy('body.removeChild')}; - $backend = createHttpBackend($browser, MockXhr, fakeTimeout, callbacks, fakeBody); - callback = jasmine.createSpy('done'); - })); - - - it('should do basics - open async xhr and send data', function() { - $backend('GET', '/some-url', 'some-data', noop); - xhr = MockXhr.$$lastInstance; - - expect(xhr.$$method).toBe('GET'); - expect(xhr.$$url).toBe('/some-url'); - expect(xhr.$$data).toBe('some-data'); - expect(xhr.$$async).toBe(true); - }); - - - it('should normalize IE\'s 1223 status code into 204', function() { - callback.andCallFake(function(status) { - expect(status).toBe(204); - }); - - $backend('GET', 'URL', null, callback); - xhr = MockXhr.$$lastInstance; - - xhr.status = 1223; - xhr.readyState = 4; - xhr.onreadystatechange(); - - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should set only the requested headers', function() { - $backend('POST', 'URL', null, noop, {'X-header1': 'value1', 'X-header2': 'value2'}); - xhr = MockXhr.$$lastInstance; - - expect(xhr.$$reqHeaders).toEqual({ - 'X-header1': 'value1', - 'X-header2': 'value2' - }); - }); - - - it('should abort request on timeout', function() { - callback.andCallFake(function(status, response) { - expect(status).toBe(-1); - }); - - $backend('GET', '/url', null, callback, {}, 2000); - xhr = MockXhr.$$lastInstance; - spyOn(xhr, 'abort'); - - expect(fakeTimeout.delays[0]).toBe(2000); - - fakeTimeout.flush(); - expect(xhr.abort).toHaveBeenCalledOnce(); - - xhr.status = 0; - xhr.readyState = 4; - xhr.onreadystatechange(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should register onreadystatechange callback before sending', function() { - // send() in IE6, IE7 is sync when serving from cache - function SyncXhr() { - xhr = this; - this.open = this.setRequestHeader = noop; - - this.send = function() { - this.status = 200; - this.responseText = 'response'; - this.readyState = 4; - this.onreadystatechange(); - }; - - this.getAllResponseHeaders = valueFn(''); - } - - callback.andCallFake(function(status, response) { - expect(status).toBe(200); - expect(response).toBe('response'); - }); - - $backend = createHttpBackend($browser, SyncXhr); - $backend('GET', '/url', null, callback); - expect(callback).toHaveBeenCalledOnce(); - }); - - - describe('JSONP', function() { - - var SCRIPT_URL = /([^\?]*)\?cb=angular\.callbacks\.(.*)/; - - - it('should add script tag for JSONP request', function() { - callback.andCallFake(function(status, response) { - expect(status).toBe(200); - expect(response).toBe('some-data'); - }); - - $backend('JSONP', 'http://example.org/path?cb=JSON_CALLBACK', null, callback); - expect($browser.$$scripts.length).toBe(1); - - var script = $browser.$$scripts.shift(), - url = script.url.match(SCRIPT_URL); - - expect(url[1]).toBe('http://example.org/path'); - callbacks[url[2]]('some-data'); - script.done(); - - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should clean up the callback and remove the script', function() { - $backend('JSONP', 'http://example.org/path?cb=JSON_CALLBACK', null, callback); - expect($browser.$$scripts.length).toBe(1); - - var script = $browser.$$scripts.shift(), - callbackId = script.url.match(SCRIPT_URL)[2]; - - callbacks[callbackId]('some-data'); - script.done(); - - expect(callbacks[callbackId]).toBeUndefined(); - expect(fakeBody.removeChild).toHaveBeenCalledOnce(); - expect(fakeBody.removeChild).toHaveBeenCalledWith(script); - }); - - - it('should call callback with status -2 when script fails to load', function() { - callback.andCallFake(function(status, response) { - expect(status).toBe(-2); - expect(response).toBeUndefined(); - }); - - $backend('JSONP', 'http://example.org/path?cb=JSON_CALLBACK', null, callback); - expect($browser.$$scripts.length).toBe(1); - - $browser.$$scripts.shift().done(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should set url to current location if not specified or empty string', function() { - $backend('JSONP', undefined, null, callback); - expect($browser.$$scripts[0].url).toBe($browser.url()); - $browser.$$scripts.shift(); - - $backend('JSONP', '', null, callback); - expect($browser.$$scripts[0].url).toBe($browser.url()); - $browser.$$scripts.shift(); - }); - - - // TODO(vojta): test whether it fires "async-start" - // TODO(vojta): test whether it fires "async-end" on both success and error - }); - - describe('file protocol', function() { - - function respond(status, content) { - xhr = MockXhr.$$lastInstance; - xhr.status = status; - xhr.responseText = content; - xhr.readyState = 4; - xhr.onreadystatechange(); - } - - - it('should convert 0 to 200 if content', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'http'); - - $backend('GET', 'file:///whatever/index.html', null, callback); - respond(0, 'SOME CONTENT'); - - expect(callback).toHaveBeenCalled(); - expect(callback.mostRecentCall.args[0]).toBe(200); - }); - - - it('should convert 0 to 200 if content - relative url', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'file'); - - $backend('GET', '/whatever/index.html', null, callback); - respond(0, 'SOME CONTENT'); - - expect(callback).toHaveBeenCalled(); - expect(callback.mostRecentCall.args[0]).toBe(200); - }); - - - it('should convert 0 to 404 if no content', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'http'); - - $backend('GET', 'file:///whatever/index.html', null, callback); - respond(0, ''); - - expect(callback).toHaveBeenCalled(); - expect(callback.mostRecentCall.args[0]).toBe(404); - }); - - - it('should convert 0 to 200 if content - relative url', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'file'); - - $backend('GET', '/whatever/index.html', null, callback); - respond(0, ''); - - expect(callback).toHaveBeenCalled(); - expect(callback.mostRecentCall.args[0]).toBe(404); - }); - }); -}); - diff --git a/test/service/httpSpec.js b/test/service/httpSpec.js deleted file mode 100644 index ab50827c..00000000 --- a/test/service/httpSpec.js +++ /dev/null @@ -1,946 +0,0 @@ -'use strict'; - -describe('$http', function() { - - var callback; - - beforeEach(function() { - callback = jasmine.createSpy('done'); - }); - beforeEach(module(function($exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - })); - - afterEach(inject(function($exceptionHandler, $httpBackend) { - forEach($exceptionHandler.errors, function(e) { - dump('Unhandled exception: ', e) - }); - - if ($exceptionHandler.errors.length) { - throw 'Unhandled exceptions trapped in $exceptionHandler!'; - } - - $httpBackend.verifyNoOutstandingExpectation(); - })); - - - describe('$httpProvider', function() { - - describe('interceptors', function() { - - it('should default to an empty array', module(function($httpProvider) { - expect($httpProvider.responseInterceptors).toEqual([]); - })); - - - it('should pass the responses through interceptors', function() { - module(function($httpProvider, $provide) { - $provide.factory('testInterceptor', function ($q) { - return function(httpPromise) { - return httpPromise.then(function(response) { - var deferred = $q.defer(); - deferred.resolve({ - data: response.data + '?', - status: 209, - headers: response.headers, - config: response.config - }); - return deferred.promise; - }); - }; - }); - // just change the response data and pass the response object along - $httpProvider.responseInterceptors.push(function() { - return function(httpPromise) { - return httpPromise.then(function(response) { - response.data += '!'; - return response; - }); - } - }); - - // return a new resolved promise representing modified response object - $httpProvider.responseInterceptors.push('testInterceptor'); - }); - inject(function($http, $httpBackend) { - $httpBackend.expect('GET', '/foo').respond(201, 'Hello'); - $http.get('/foo').success(function(data, status) { - expect(data).toBe('Hello!?'); - expect(status).toBe(209); - callback(); - }); - $httpBackend.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - }); - - - it('should support interceptors defined as services', function() { - module(function($provide, $httpProvider) { - $provide.factory('myInterceptor', function() { - return function(promise) { - return promise.then(function(response) { - response.data = uppercase(response.data); - return response; - }); - } - }); - $httpProvider.responseInterceptors.push('myInterceptor'); - }); - inject(function($http, $httpBackend) { - var response; - - $httpBackend.expect('GET', '/test').respond('hello!'); - $http.get('/test').success(function(data) {response = data;}); - expect(response).toBeUndefined(); - - $httpBackend.flush(); - expect(response).toBe('HELLO!'); - }); - }); - }); - }); - - - describe('the instance', function() { - var $httpBackend, $http, $rootScope; - - beforeEach(inject(['$rootScope', function($rs) { - $rootScope = $rs; - - spyOn($rootScope, '$apply').andCallThrough(); - }])); - - beforeEach(inject(['$httpBackend', '$http', function($hb, $h) { - $httpBackend = $hb; - $http = $h; - }])); - - - it('should do basic request', inject(function($httpBackend, $http) { - $httpBackend.expect('GET', '/url').respond(''); - $http({url: '/url', method: 'GET'}); - })); - - - it('should pass data if specified', inject(function($httpBackend, $http) { - $httpBackend.expect('POST', '/url', 'some-data').respond(''); - $http({url: '/url', method: 'POST', data: 'some-data'}); - })); - - - // TODO(vojta): test passing timeout - - - describe('params', function() { - it('should do basic request with params and encode', inject(function($httpBackend, $http) { - $httpBackend.expect('GET', '/url?a%3D=%3F%26&b=2').respond(''); - $http({url: '/url', params: {'a=':'?&', b:2}, method: 'GET'}); - })); - - - it('should merge params if url contains some already', inject(function($httpBackend, $http) { - $httpBackend.expect('GET', '/url?c=3&a=1&b=2').respond(''); - $http({url: '/url?c=3', params: {a:1, b:2}, method: 'GET'}); - })); - - - it('should jsonify objects in params map', inject(function($httpBackend, $http) { - $httpBackend.expect('GET', '/url?a=1&b=%7B%22c%22%3A3%7D').respond(''); - $http({url: '/url', params: {a:1, b:{c:3}}, method: 'GET'}); - })); - }); - - - describe('callbacks', function() { - - it('should pass in the response object when a request is successful', function() { - $httpBackend.expect('GET', '/url').respond(207, 'my content', {'content-encoding': 'smurf'}); - $http({url: '/url', method: 'GET'}).then(function(response) { - expect(response.data).toBe('my content'); - expect(response.status).toBe(207); - expect(response.headers()).toEqual({'content-encoding': 'smurf'}); - expect(response.config.url).toBe('/url'); - callback(); - }); - - $httpBackend.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should pass in the response object when a request failed', function() { - $httpBackend.expect('GET', '/url').respond(543, 'bad error', {'request-id': '123'}); - $http({url: '/url', method: 'GET'}).then(null, function(response) { - expect(response.data).toBe('bad error'); - expect(response.status).toBe(543); - expect(response.headers()).toEqual({'request-id': '123'}); - expect(response.config.url).toBe('/url'); - callback(); - }); - - $httpBackend.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - describe('success', function() { - it('should allow http specific callbacks to be registered via "success"', function() { - $httpBackend.expect('GET', '/url').respond(207, 'my content', {'content-encoding': 'smurf'}); - $http({url: '/url', method: 'GET'}).success(function(data, status, headers, config) { - expect(data).toBe('my content'); - expect(status).toBe(207); - expect(headers()).toEqual({'content-encoding': 'smurf'}); - expect(config.url).toBe('/url'); - callback(); - }); - - $httpBackend.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should return the original http promise', function() { - $httpBackend.expect('GET', '/url').respond(207, 'my content', {'content-encoding': 'smurf'}); - var httpPromise = $http({url: '/url', method: 'GET'}); - expect(httpPromise.success(callback)).toBe(httpPromise); - }); - }); - - - describe('error', function() { - it('should allow http specific callbacks to be registered via "error"', function() { - $httpBackend.expect('GET', '/url').respond(543, 'bad error', {'request-id': '123'}); - $http({url: '/url', method: 'GET'}).error(function(data, status, headers, config) { - expect(data).toBe('bad error'); - expect(status).toBe(543); - expect(headers()).toEqual({'request-id': '123'}); - expect(config.url).toBe('/url'); - callback(); - }); - - $httpBackend.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should return the original http promise', function() { - $httpBackend.expect('GET', '/url').respond(543, 'bad error', {'request-id': '123'}); - var httpPromise = $http({url: '/url', method: 'GET'}); - expect(httpPromise.error(callback)).toBe(httpPromise); - }); - }); - }); - - - describe('response headers', function() { - - it('should return single header', function() { - $httpBackend.expect('GET', '/url').respond('', {'date': 'date-val'}); - callback.andCallFake(function(r) { - expect(r.headers('date')).toBe('date-val'); - }); - - $http({url: '/url', method: 'GET'}).then(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should return null when single header does not exist', function() { - $httpBackend.expect('GET', '/url').respond('', {'Some-Header': 'Fake'}); - callback.andCallFake(function(r) { - r.headers(); // we need that to get headers parsed first - expect(r.headers('nothing')).toBe(null); - }); - - $http({url: '/url', method: 'GET'}).then(callback) - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should return all headers as object', function() { - $httpBackend.expect('GET', '/url').respond('', { - 'content-encoding': 'gzip', - 'server': 'Apache' - }); - - callback.andCallFake(function(r) { - expect(r.headers()).toEqual({'content-encoding': 'gzip', 'server': 'Apache'}); - }); - - $http({url: '/url', method: 'GET'}).then(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should return empty object for jsonp request', function() { - callback.andCallFake(function(r) { - expect(r.headers()).toEqual({}); - }); - - $httpBackend.expect('JSONP', '/some').respond(200); - $http({url: '/some', method: 'JSONP'}).then(callback); - $httpBackend.flush(); - expect(callback).toHaveBeenCalledOnce(); - }); - }); - - - describe('response headers parser', function() { - - it('should parse basic', function() { - var parsed = parseHeaders( - 'date: Thu, 04 Aug 2011 20:23:08 GMT\n' + - 'content-encoding: gzip\n' + - 'transfer-encoding: chunked\n' + - 'x-cache-info: not cacheable; response has already expired, not cacheable; response has already expired\n' + - 'connection: Keep-Alive\n' + - 'x-backend-server: pm-dekiwiki03\n' + - 'pragma: no-cache\n' + - 'server: Apache\n' + - 'x-frame-options: DENY\n' + - 'content-type: text/html; charset=utf-8\n' + - 'vary: Cookie, Accept-Encoding\n' + - 'keep-alive: timeout=5, max=1000\n' + - 'expires: Thu: , 19 Nov 1981 08:52:00 GMT\n'); - - expect(parsed['date']).toBe('Thu, 04 Aug 2011 20:23:08 GMT'); - expect(parsed['content-encoding']).toBe('gzip'); - expect(parsed['transfer-encoding']).toBe('chunked'); - expect(parsed['keep-alive']).toBe('timeout=5, max=1000'); - }); - - - it('should parse lines without space after colon', function() { - expect(parseHeaders('key:value').key).toBe('value'); - }); - - - it('should trim the values', function() { - expect(parseHeaders('key: value ').key).toBe('value'); - }); - - - it('should allow headers without value', function() { - expect(parseHeaders('key:').key).toBe(''); - }); - - - it('should merge headers with same key', function() { - expect(parseHeaders('key: a\nkey:b\n').key).toBe('a, b'); - }); - - - it('should normalize keys to lower case', function() { - expect(parseHeaders('KeY: value').key).toBe('value'); - }); - - - it('should parse CRLF as delimiter', function() { - // IE does use CRLF - expect(parseHeaders('a: b\r\nc: d\r\n')).toEqual({a: 'b', c: 'd'}); - expect(parseHeaders('a: b\r\nc: d\r\n').a).toBe('b'); - }); - - - it('should parse tab after semi-colon', function() { - expect(parseHeaders('a:\tbb').a).toBe('bb'); - expect(parseHeaders('a: \tbb').a).toBe('bb'); - }); - }); - - - describe('request headers', function() { - - it('should send custom headers', function() { - $httpBackend.expect('GET', '/url', undefined, function(headers) { - return headers['Custom'] == 'header'; - }).respond(''); - - $http({url: '/url', method: 'GET', headers: { - 'Custom': 'header', - }}); - - $httpBackend.flush(); - }); - - - it('should set default headers for GET request', function() { - $httpBackend.expect('GET', '/url', undefined, function(headers) { - return headers['Accept'] == 'application/json, text/plain, */*' && - headers['X-Requested-With'] == 'XMLHttpRequest'; - }).respond(''); - - $http({url: '/url', method: 'GET', headers: {}}); - $httpBackend.flush(); - }); - - - it('should set default headers for POST request', function() { - $httpBackend.expect('POST', '/url', 'messageBody', function(headers) { - return headers['Accept'] == 'application/json, text/plain, */*' && - headers['X-Requested-With'] == 'XMLHttpRequest' && - headers['Content-Type'] == 'application/json'; - }).respond(''); - - $http({url: '/url', method: 'POST', headers: {}, data: 'messageBody'}); - $httpBackend.flush(); - }); - - - it('should set default headers for PUT request', function() { - $httpBackend.expect('PUT', '/url', 'messageBody', function(headers) { - return headers['Accept'] == 'application/json, text/plain, */*' && - headers['X-Requested-With'] == 'XMLHttpRequest' && - headers['Content-Type'] == 'application/json'; - }).respond(''); - - $http({url: '/url', method: 'PUT', headers: {}, data: 'messageBody'}); - $httpBackend.flush(); - }); - - - it('should set default headers for custom HTTP method', function() { - $httpBackend.expect('FOO', '/url', undefined, function(headers) { - return headers['Accept'] == 'application/json, text/plain, */*' && - headers['X-Requested-With'] == 'XMLHttpRequest'; - }).respond(''); - - $http({url: '/url', method: 'FOO', headers: {}}); - $httpBackend.flush(); - }); - - - it('should override default headers with custom', function() { - $httpBackend.expect('POST', '/url', 'messageBody', function(headers) { - return headers['Accept'] == 'Rewritten' && - headers['X-Requested-With'] == 'XMLHttpRequest' && - headers['Content-Type'] == 'Rewritten'; - }).respond(''); - - $http({url: '/url', method: 'POST', data: 'messageBody', headers: { - 'Accept': 'Rewritten', - 'Content-Type': 'Rewritten' - }}); - $httpBackend.flush(); - }); - - - it('should not send Content-Type header if request data/body is undefined', function() { - $httpBackend.expect('POST', '/url', undefined, function(headers) { - return !headers.hasOwnProperty('Content-Type'); - }).respond(''); - - $http({url: '/url', method: 'POST'}); - $httpBackend.flush(); - }); - - - it('should set the XSRF cookie into a XSRF header', inject(function($browser) { - function checkXSRF(secret) { - return function(headers) { - return headers['X-XSRF-TOKEN'] == secret; - }; - } - - $browser.cookies('XSRF-TOKEN', 'secret'); - $httpBackend.expect('GET', '/url', undefined, checkXSRF('secret')).respond(''); - $httpBackend.expect('POST', '/url', undefined, checkXSRF('secret')).respond(''); - $httpBackend.expect('PUT', '/url', undefined, checkXSRF('secret')).respond(''); - $httpBackend.expect('DELETE', '/url', undefined, checkXSRF('secret')).respond(''); - - $http({url: '/url', method: 'GET'}); - $http({url: '/url', method: 'POST', headers: {'S-ome': 'Header'}}); - $http({url: '/url', method: 'PUT', headers: {'Another': 'Header'}}); - $http({url: '/url', method: 'DELETE', headers: {}}); - - $httpBackend.flush(); - })); - }); - - - describe('short methods', function() { - - function checkHeader(name, value) { - return function(headers) { - return headers[name] == value; - }; - } - - it('should have get()', function() { - $httpBackend.expect('GET', '/url').respond(''); - $http.get('/url'); - }); - - - it('get() should allow config param', function() { - $httpBackend.expect('GET', '/url', undefined, checkHeader('Custom', 'Header')).respond(''); - $http.get('/url', {headers: {'Custom': 'Header'}}); - }); - - - it('should have delete()', function() { - $httpBackend.expect('DELETE', '/url').respond(''); - $http['delete']('/url'); - }); - - - it('delete() should allow config param', function() { - $httpBackend.expect('DELETE', '/url', undefined, checkHeader('Custom', 'Header')).respond(''); - $http['delete']('/url', {headers: {'Custom': 'Header'}}); - }); - - - it('should have head()', function() { - $httpBackend.expect('HEAD', '/url').respond(''); - $http.head('/url'); - }); - - - it('head() should allow config param', function() { - $httpBackend.expect('HEAD', '/url', undefined, checkHeader('Custom', 'Header')).respond(''); - $http.head('/url', {headers: {'Custom': 'Header'}}); - }); - - - it('should have post()', function() { - $httpBackend.expect('POST', '/url', 'some-data').respond(''); - $http.post('/url', 'some-data'); - }); - - - it('post() should allow config param', function() { - $httpBackend.expect('POST', '/url', 'some-data', checkHeader('Custom', 'Header')).respond(''); - $http.post('/url', 'some-data', {headers: {'Custom': 'Header'}}); - }); - - - it('should have put()', function() { - $httpBackend.expect('PUT', '/url', 'some-data').respond(''); - $http.put('/url', 'some-data'); - }); - - - it('put() should allow config param', function() { - $httpBackend.expect('PUT', '/url', 'some-data', checkHeader('Custom', 'Header')).respond(''); - $http.put('/url', 'some-data', {headers: {'Custom': 'Header'}}); - }); - - - it('should have jsonp()', function() { - $httpBackend.expect('JSONP', '/url').respond(''); - $http.jsonp('/url'); - }); - - - it('jsonp() should allow config param', function() { - $httpBackend.expect('JSONP', '/url', undefined, checkHeader('Custom', 'Header')).respond(''); - $http.jsonp('/url', {headers: {'Custom': 'Header'}}); - }); - }); - - - describe('scope.$apply', function() { - - it('should $apply after success callback', function() { - $httpBackend.when('GET').respond(200); - $http({method: 'GET', url: '/some'}); - $httpBackend.flush(); - expect($rootScope.$apply).toHaveBeenCalledOnce(); - }); - - - it('should $apply after error callback', function() { - $httpBackend.when('GET').respond(404); - $http({method: 'GET', url: '/some'}); - $httpBackend.flush(); - expect($rootScope.$apply).toHaveBeenCalledOnce(); - }); - - - it('should $apply even if exception thrown during callback', inject(function($exceptionHandler){ - $httpBackend.when('GET').respond(200); - callback.andThrow('error in callback'); - - $http({method: 'GET', url: '/some'}).then(callback); - $httpBackend.flush(); - expect($rootScope.$apply).toHaveBeenCalledOnce(); - - $exceptionHandler.errors = []; - })); - }); - - - describe('transformData', function() { - - describe('request', function() { - - describe('default', function() { - - it('should transform object into json', function() { - $httpBackend.expect('POST', '/url', '{"one":"two"}').respond(''); - $http({method: 'POST', url: '/url', data: {one: 'two'}}); - }); - - - it('should ignore strings', function() { - $httpBackend.expect('POST', '/url', 'string-data').respond(''); - $http({method: 'POST', url: '/url', data: 'string-data'}); - }); - - - it('should ignore File objects', function() { - var file = { - some: true, - // $httpBackend compares toJson values by default, - // we need to be sure it's not serialized into json string - test: function(actualValue) { - return this === actualValue; - } - }; - - // I'm really sorry for doing this :-D - // Unfortunatelly I don't know how to trick toString.apply(obj) comparison - spyOn(window, 'isFile').andReturn(true); - - $httpBackend.expect('POST', '/some', file).respond(''); - $http({method: 'POST', url: '/some', data: file}); - }); - }); - - - it('should have access to request headers', function() { - $httpBackend.expect('POST', '/url', 'header1').respond(200); - $http.post('/url', 'req', { - headers: {h1: 'header1'}, - transformRequest: function(data, headers) { - return headers('h1'); - } - }).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should pipeline more functions', function() { - function first(d, h) {return d + '-first' + ':' + h('h1')} - function second(d) {return uppercase(d)} - - $httpBackend.expect('POST', '/url', 'REQ-FIRST:V1').respond(200); - $http.post('/url', 'req', { - headers: {h1: 'v1'}, - transformRequest: [first, second] - }).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - }); - }); - - - describe('response', function() { - - describe('default', function() { - - it('should deserialize json objects', function() { - $httpBackend.expect('GET', '/url').respond('{"foo":"bar","baz":23}'); - $http({method: 'GET', url: '/url'}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toEqual({foo: 'bar', baz: 23}); - }); - - - it('should deserialize json arrays', function() { - $httpBackend.expect('GET', '/url').respond('[1, "abc", {"foo":"bar"}]'); - $http({method: 'GET', url: '/url'}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo: 'bar'}]); - }); - - - it('should deserialize json with security prefix', function() { - $httpBackend.expect('GET', '/url').respond(')]}\',\n[1, "abc", {"foo":"bar"}]'); - $http({method: 'GET', url: '/url'}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo:'bar'}]); - }); - - - it('should deserialize json with security prefix ")]}\'"', function() { - $httpBackend.expect('GET', '/url').respond(')]}\'\n\n[1, "abc", {"foo":"bar"}]'); - $http({method: 'GET', url: '/url'}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toEqual([1, 'abc', {foo:'bar'}]); - }); - - - it('should not deserialize tpl beginning with ng expression', function() { - $httpBackend.expect('GET', '/url').respond('{{some}}'); - $http.get('/url').success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toEqual('{{some}}'); - }); - }); - - - it('should have access to response headers', function() { - $httpBackend.expect('GET', '/url').respond(200, 'response', {h1: 'header1'}); - $http.get('/url', { - transformResponse: function(data, headers) { - return headers('h1'); - } - }).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toBe('header1'); - }); - - - it('should pipeline more functions', function() { - function first(d, h) {return d + '-first' + ':' + h('h1')} - function second(d) {return uppercase(d)} - - $httpBackend.expect('POST', '/url').respond(200, 'resp', {h1: 'v1'}); - $http.post('/url', '', {transformResponse: [first, second]}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toBe('RESP-FIRST:V1'); - }); - }); - }); - - - describe('cache', function() { - - var cache; - - beforeEach(inject(function($cacheFactory) { - cache = $cacheFactory('testCache'); - })); - - - function doFirstCacheRequest(method, respStatus, headers) { - $httpBackend.expect(method || 'GET', '/url').respond(respStatus || 200, 'content', headers); - $http({method: method || 'GET', url: '/url', cache: cache}); - $httpBackend.flush(); - } - - - it('should cache GET request when cache is provided', inject(function($rootScope) { - doFirstCacheRequest(); - - $http({method: 'get', url: '/url', cache: cache}).success(callback); - $rootScope.$digest(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toBe('content'); - })); - - - it('should not cache when cache is not provided', function() { - doFirstCacheRequest(); - - $httpBackend.expect('GET', '/url').respond(); - $http({method: 'GET', url: '/url'}); - }); - - - it('should perform request when cache cleared', function() { - doFirstCacheRequest(); - - cache.removeAll(); - $httpBackend.expect('GET', '/url').respond(); - $http({method: 'GET', url: '/url', cache: cache}); - }); - - - it('should always call callback asynchronously', function() { - doFirstCacheRequest(); - $http({method: 'get', url: '/url', cache: cache}).then(callback); - - expect(callback).not.toHaveBeenCalled(); - }); - - - it('should not cache POST request', function() { - doFirstCacheRequest('POST'); - - $httpBackend.expect('POST', '/url').respond('content2'); - $http({method: 'POST', url: '/url', cache: cache}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toBe('content2'); - }); - - - it('should not cache PUT request', function() { - doFirstCacheRequest('PUT'); - - $httpBackend.expect('PUT', '/url').respond('content2'); - $http({method: 'PUT', url: '/url', cache: cache}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toBe('content2'); - }); - - - it('should not cache DELETE request', function() { - doFirstCacheRequest('DELETE'); - - $httpBackend.expect('DELETE', '/url').respond(206); - $http({method: 'DELETE', url: '/url', cache: cache}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - }); - - - it('should not cache non 2xx responses', function() { - doFirstCacheRequest('GET', 404); - - $httpBackend.expect('GET', '/url').respond('content2'); - $http({method: 'GET', url: '/url', cache: cache}).success(callback); - $httpBackend.flush(); - - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toBe('content2'); - }); - - - it('should cache the headers as well', inject(function($rootScope) { - doFirstCacheRequest('GET', 200, {'content-encoding': 'gzip', 'server': 'Apache'}); - callback.andCallFake(function(r, s, headers) { - expect(headers()).toEqual({'content-encoding': 'gzip', 'server': 'Apache'}); - expect(headers('server')).toBe('Apache'); - }); - - $http({method: 'GET', url: '/url', cache: cache}).success(callback); - $rootScope.$digest(); - expect(callback).toHaveBeenCalledOnce(); - })); - - - it('should not share the cached headers object instance', inject(function($rootScope) { - doFirstCacheRequest('GET', 200, {'content-encoding': 'gzip', 'server': 'Apache'}); - callback.andCallFake(function(r, s, headers) { - expect(headers()).toEqual(cache.get('/url')[2]); - expect(headers()).not.toBe(cache.get('/url')[2]); - }); - - $http({method: 'GET', url: '/url', cache: cache}).success(callback); - $rootScope.$digest(); - expect(callback).toHaveBeenCalledOnce(); - })); - - - it('should cache status code as well', inject(function($rootScope) { - doFirstCacheRequest('GET', 201); - callback.andCallFake(function(r, status, h) { - expect(status).toBe(201); - }); - - $http({method: 'get', url: '/url', cache: cache}).success(callback); - $rootScope.$digest(); - expect(callback).toHaveBeenCalledOnce(); - })); - - - it('should use cache even if second request was made before the first returned', function() { - $httpBackend.expect('GET', '/url').respond(201, 'fake-response'); - - callback.andCallFake(function(response, status, headers) { - expect(response).toBe('fake-response'); - expect(status).toBe(201); - }); - - $http({method: 'GET', url: '/url', cache: cache}).success(callback); - $http({method: 'GET', url: '/url', cache: cache}).success(callback); - - $httpBackend.flush(); - expect(callback).toHaveBeenCalled(); - expect(callback.callCount).toBe(2); - }); - - - it('should default to status code 200 and empty headers if cache contains a non-array element', - inject(function($rootScope) { - cache.put('/myurl', 'simple response'); - $http.get('/myurl', {cache: cache}).success(function(data, status, headers) { - expect(data).toBe('simple response'); - expect(status).toBe(200); - expect(headers()).toEqual({}); - callback(); - }); - - $rootScope.$digest(); - expect(callback).toHaveBeenCalledOnce(); - }) - ); - }); - - - describe('pendingRequests', function() { - - it('should be an array of pending requests', function() { - $httpBackend.when('GET').respond(200); - expect($http.pendingRequests.length).toBe(0); - - $http({method: 'get', url: '/some'}); - expect($http.pendingRequests.length).toBe(1); - - $httpBackend.flush(); - expect($http.pendingRequests.length).toBe(0); - }); - - - it('should update pending requests even when served from cache', inject(function($rootScope) { - $httpBackend.when('GET').respond(200); - - $http({method: 'get', url: '/cached', cache: true}); - $http({method: 'get', url: '/cached', cache: true}); - expect($http.pendingRequests.length).toBe(2); - - $httpBackend.flush(); - expect($http.pendingRequests.length).toBe(0); - - $http({method: 'get', url: '/cached', cache: true}); - expect($http.pendingRequests.length).toBe(1); - - $rootScope.$apply(); - expect($http.pendingRequests.length).toBe(0); - })); - - - it('should remove the request before firing callbacks', function() { - $httpBackend.when('GET').respond(200); - $http({method: 'get', url: '/url'}).success(function() { - expect($http.pendingRequests.length).toBe(0); - }); - - expect($http.pendingRequests.length).toBe(1); - $httpBackend.flush(); - }); - }); - }); -}); diff --git a/test/service/interpolateSpec.js b/test/service/interpolateSpec.js deleted file mode 100644 index d5f251ea..00000000 --- a/test/service/interpolateSpec.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -describe('$interpolate', function() { - - it('should return a function when there are no bindings and textOnly is undefined', - inject(function($interpolate) { - expect(typeof $interpolate('some text')).toBe('function'); - })); - - - it('should return undefined when there are no bindings and textOnly is set to true', - inject(function($interpolate) { - expect($interpolate('some text', true)).toBeUndefined(); - })); - - it('should suppress falsy objects', inject(function($interpolate) { - expect($interpolate('{{undefined}}')()).toEqual(''); - expect($interpolate('{{null}}')()).toEqual(''); - expect($interpolate('{{a.b}}')()).toEqual(''); - })); - - it('should jsonify objects', inject(function($interpolate) { - expect($interpolate('{{ {} }}')()).toEqual('{}'); - expect($interpolate('{{ true }}')()).toEqual('true'); - expect($interpolate('{{ false }}')()).toEqual('false'); - })); - - - it('should return interpolation function', inject(function($interpolate, $rootScope) { - $rootScope.name = 'Misko'; - expect($interpolate('Hello {{name}}!')($rootScope)).toEqual('Hello Misko!'); - })); - - describe('provider', function() { - beforeEach(module(function($interpolateProvider) { - $interpolateProvider.startSymbol('--'); - $interpolateProvider.endSymbol('--'); - })); - - it('should not get confused with same markers', inject(function($interpolate) { - expect($interpolate('---').parts).toEqual(['---']); - expect($interpolate('----')()).toEqual(''); - expect($interpolate('--1--')()).toEqual('1'); - })); - }); - - describe('parseBindings', function() { - it('should Parse Text With No Bindings', inject(function($interpolate) { - var parts = $interpolate("a").parts; - expect(parts.length).toEqual(1); - expect(parts[0]).toEqual("a"); - })); - - it('should Parse Empty Text', inject(function($interpolate) { - var parts = $interpolate("").parts; - expect(parts.length).toEqual(1); - expect(parts[0]).toEqual(""); - })); - - it('should Parse Inner Binding', inject(function($interpolate) { - var parts = $interpolate("a{{b}}C").parts; - expect(parts.length).toEqual(3); - expect(parts[0]).toEqual("a"); - expect(parts[1].exp).toEqual("b"); - expect(parts[1]({b:123})).toEqual(123); - expect(parts[2]).toEqual("C"); - })); - - it('should Parse Ending Binding', inject(function($interpolate) { - var parts = $interpolate("a{{b}}").parts; - expect(parts.length).toEqual(2); - expect(parts[0]).toEqual("a"); - expect(parts[1].exp).toEqual("b"); - expect(parts[1]({b:123})).toEqual(123); - })); - - it('should Parse Begging Binding', inject(function($interpolate) { - var parts = $interpolate("{{b}}c").parts; - expect(parts.length).toEqual(2); - expect(parts[0].exp).toEqual("b"); - expect(parts[1]).toEqual("c"); - })); - - it('should Parse Loan Binding', inject(function($interpolate) { - var parts = $interpolate("{{b}}").parts; - expect(parts.length).toEqual(1); - expect(parts[0].exp).toEqual("b"); - })); - - it('should Parse Two Bindings', inject(function($interpolate) { - var parts = $interpolate("{{b}}{{c}}").parts; - expect(parts.length).toEqual(2); - expect(parts[0].exp).toEqual("b"); - expect(parts[1].exp).toEqual("c"); - })); - - it('should Parse Two Bindings With Text In Middle', inject(function($interpolate) { - var parts = $interpolate("{{b}}x{{c}}").parts; - expect(parts.length).toEqual(3); - expect(parts[0].exp).toEqual("b"); - expect(parts[1]).toEqual("x"); - expect(parts[2].exp).toEqual("c"); - })); - - it('should Parse Multiline', inject(function($interpolate) { - var parts = $interpolate('"X\nY{{A\n+B}}C\nD"').parts; - expect(parts.length).toEqual(3); - expect(parts[0]).toEqual('"X\nY'); - expect(parts[1].exp).toEqual('A\n+B'); - expect(parts[2]).toEqual('C\nD"'); - })); - }); -}); diff --git a/test/service/localeSpec.js b/test/service/localeSpec.js deleted file mode 100644 index 83c4ecee..00000000 --- a/test/service/localeSpec.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; - -describe('$locale', function() { - - var $locale = new $LocaleProvider().$get(); - - it('should have locale id set to en-us', function() { - expect($locale.id).toBe('en-us'); - }); - - - it('should have NUMBER_FORMATS', function() { - var numberFormats = $locale.NUMBER_FORMATS; - expect(numberFormats).toBeDefined(); - expect(numberFormats.PATTERNS.length).toBe(2); - angular.forEach(numberFormats.PATTERNS, function(pattern) { - expect(pattern.minInt).toBeDefined(); - expect(pattern.minFrac).toBeDefined(); - expect(pattern.maxFrac).toBeDefined(); - expect(pattern.posPre).toBeDefined(); - expect(pattern.posSuf).toBeDefined(); - expect(pattern.negPre).toBeDefined(); - expect(pattern.negSuf).toBeDefined(); - expect(pattern.gSize).toBeDefined(); - expect(pattern.lgSize).toBeDefined(); - }); - }); - - - it('should have DATETIME_FORMATS', function() { - var datetime = $locale.DATETIME_FORMATS; - expect(datetime).toBeDefined(); - expect(datetime.DAY.length).toBe(7); - expect(datetime.SHORTDAY.length).toBe(7); - expect(datetime.SHORTMONTH.length).toBe(12); - expect(datetime.MONTH.length).toBe(12); - expect(datetime.AMPMS.length).toBe(2); - }); - - - it('should return correct plural types', function() { - expect($locale.pluralCat(-1)).toBe('other'); - expect($locale.pluralCat(0)).toBe('other'); - expect($locale.pluralCat(2)).toBe('other'); - expect($locale.pluralCat(1)).toBe('one'); - }); -}); diff --git a/test/service/locationSpec.js b/test/service/locationSpec.js deleted file mode 100644 index 646a9ca0..00000000 --- a/test/service/locationSpec.js +++ /dev/null @@ -1,883 +0,0 @@ -'use strict'; - -/** - * Create jasmine.Spy on given method, but ignore calls without arguments - * This is helpful when need to spy only setter methods and ignore getters - */ -function spyOnlyCallsWithArgs(obj, method) { - var spy = spyOn(obj, method); - obj[method] = function() { - if (arguments.length) return spy.apply(this, arguments); - return spy.originalValue.apply(this); - }; - return spy; -} - - -describe('$location', function() { - var url; - - afterEach(function() { - // link rewriting used in html5 mode on legacy browsers binds to document.onClick, so we need - // to clean this up after each test. - jqLite(document).unbind('click'); - }); - - describe('NewUrl', function() { - beforeEach(function() { - url = new LocationUrl('http://www.domain.com:9877/path/b?search=a&b=c&d#hash'); - }); - - - it('should provide common getters', function() { - expect(url.absUrl()).toBe('http://www.domain.com:9877/path/b?search=a&b=c&d#hash'); - expect(url.protocol()).toBe('http'); - expect(url.host()).toBe('www.domain.com'); - expect(url.port()).toBe(9877); - expect(url.path()).toBe('/path/b'); - expect(url.search()).toEqual({search: 'a', b: 'c', d: true}); - expect(url.hash()).toBe('hash'); - expect(url.url()).toBe('/path/b?search=a&b=c&d#hash'); - }); - - - it('path() should change path', function() { - url.path('/new/path'); - expect(url.path()).toBe('/new/path'); - expect(url.absUrl()).toBe('http://www.domain.com:9877/new/path?search=a&b=c&d#hash'); - }); - - - it('search() should accept string', function() { - url.search('x=y&c'); - expect(url.search()).toEqual({x: 'y', c: true}); - expect(url.absUrl()).toBe('http://www.domain.com:9877/path/b?x=y&c#hash'); - }); - - - it('search() should accept object', function() { - url.search({one: 1, two: true}); - expect(url.search()).toEqual({one: 1, two: true}); - expect(url.absUrl()).toBe('http://www.domain.com:9877/path/b?one=1&two#hash'); - }); - - - it('search() should change single parameter', function() { - url.search({id: 'old', preserved: true}); - url.search('id', 'new'); - - expect(url.search()).toEqual({id: 'new', preserved: true}); - }); - - - it('search() should remove single parameter', function() { - url.search({id: 'old', preserved: true}); - url.search('id', null); - - expect(url.search()).toEqual({preserved: true}); - }); - - - it('hash() should change hash fragment', function() { - url.hash('new-hash'); - expect(url.hash()).toBe('new-hash'); - expect(url.absUrl()).toBe('http://www.domain.com:9877/path/b?search=a&b=c&d#new-hash'); - }); - - - it('url() should change the path, search and hash', function() { - url.url('/some/path?a=b&c=d#hhh'); - expect(url.url()).toBe('/some/path?a=b&c=d#hhh'); - expect(url.absUrl()).toBe('http://www.domain.com:9877/some/path?a=b&c=d#hhh'); - expect(url.path()).toBe('/some/path'); - expect(url.search()).toEqual({a: 'b', c: 'd'}); - expect(url.hash()).toBe('hhh'); - }); - - - it('url() should change only hash when no search and path specified', function() { - url.url('#some-hash'); - - expect(url.hash()).toBe('some-hash'); - expect(url.url()).toBe('/path/b?search=a&b=c&d#some-hash'); - expect(url.absUrl()).toBe('http://www.domain.com:9877/path/b?search=a&b=c&d#some-hash'); - }); - - - it('url() should change only search and hash when no path specified', function() { - url.url('?a=b'); - - expect(url.search()).toEqual({a: 'b'}); - expect(url.hash()).toBe(''); - expect(url.path()).toBe('/path/b'); - }); - - - it('url() should reset search and hash when only path specified', function() { - url.url('/new/path'); - - expect(url.path()).toBe('/new/path'); - expect(url.search()).toEqual({}); - expect(url.hash()).toBe(''); - }); - - - it('replace should set $$replace flag and return itself', function() { - expect(url.$$replace).toBe(false); - - url.replace(); - expect(url.$$replace).toBe(true); - expect(url.replace()).toBe(url); - }); - - - it('should parse new url', function() { - url = new LocationUrl('http://host.com/base'); - expect(url.path()).toBe('/base'); - - url = new LocationUrl('http://host.com/base#'); - expect(url.path()).toBe('/base'); - }); - - - it('should prefix path with forward-slash', function() { - url = new LocationUrl('http://server/a'); - url.path('b'); - - expect(url.path()).toBe('/b'); - expect(url.absUrl()).toBe('http://server/b'); - }); - - - it('should set path to forward-slash when empty', function() { - url = new LocationUrl('http://server'); - expect(url.path()).toBe('/'); - expect(url.absUrl()).toBe('http://server/'); - }); - - - it('setters should return Url object to allow chaining', function() { - expect(url.path('/any')).toBe(url); - expect(url.search('')).toBe(url); - expect(url.hash('aaa')).toBe(url); - expect(url.url('/some')).toBe(url); - }); - - - it('should not preserve old properties when parsing new url', function() { - url.$$parse('http://www.domain.com:9877/a'); - - expect(url.path()).toBe('/a'); - expect(url.search()).toEqual({}); - expect(url.hash()).toBe(''); - expect(url.absUrl()).toBe('http://www.domain.com:9877/a'); - }); - - - it('should prepend path with basePath', function() { - url = new LocationUrl('http://server/base/abc?a', '/base'); - expect(url.path()).toBe('/abc'); - expect(url.search()).toEqual({a: true}); - - url.path('/new/path'); - expect(url.absUrl()).toBe('http://server/base/new/path?a'); - }); - - - it('should throw error when invalid url given', function() { - url = new LocationUrl('http://server.org/base/abc', '/base'); - - expect(function() { - url.$$parse('http://server.org/path#/path'); - }).toThrow('Invalid url "http://server.org/path#/path", missing path prefix "/base" !'); - }); - - - describe('encoding', function() { - - it('should encode special characters', function() { - url.path('/a <>#'); - url.search({'i j': '<>#'}); - url.hash('<>#'); - - expect(url.path()).toBe('/a <>#'); - expect(url.search()).toEqual({'i j': '<>#'}); - expect(url.hash()).toBe('<>#'); - expect(url.absUrl()).toBe('http://www.domain.com:9877/a%20%3C%3E%23?i%20j=%3C%3E%23#%3C%3E%23'); - }); - - - it('should not encode !$:@', function() { - url.path('/!$:@'); - url.search(''); - url.hash('!$:@'); - - expect(url.absUrl()).toBe('http://www.domain.com:9877/!$:@#!$:@'); - }); - - - it('should decode special characters', function() { - url = new LocationUrl('http://host.com/a%20%3C%3E%23?i%20j=%3C%3E%23#x%20%3C%3E%23'); - expect(url.path()).toBe('/a <>#'); - expect(url.search()).toEqual({'i j': '<>#'}); - expect(url.hash()).toBe('x <>#'); - }); - }); - }); - - - describe('HashbangUrl', function() { - - beforeEach(function() { - url = new LocationHashbangUrl('http://www.server.org:1234/base#!/path?a=b&c#hash', '!'); - }); - - - it('should parse hashband url into path and search', function() { - expect(url.protocol()).toBe('http'); - expect(url.host()).toBe('www.server.org'); - expect(url.port()).toBe(1234); - expect(url.path()).toBe('/path'); - expect(url.search()).toEqual({a: 'b', c: true}); - expect(url.hash()).toBe('hash'); - }); - - - it('absUrl() should return hashbang url', function() { - expect(url.absUrl()).toBe('http://www.server.org:1234/base#!/path?a=b&c#hash'); - - url.path('/new/path'); - url.search({one: 1}); - url.hash('hhh'); - expect(url.absUrl()).toBe('http://www.server.org:1234/base#!/new/path?one=1#hhh'); - }); - - - it('should preserve query params in base', function() { - url = new LocationHashbangUrl('http://www.server.org:1234/base?base=param#/path?a=b&c#hash', ''); - expect(url.absUrl()).toBe('http://www.server.org:1234/base?base=param#/path?a=b&c#hash'); - - url.path('/new/path'); - url.search({one: 1}); - url.hash('hhh'); - expect(url.absUrl()).toBe('http://www.server.org:1234/base?base=param#/new/path?one=1#hhh'); - }); - - - it('should prefix path with forward-slash', function() { - url = new LocationHashbangUrl('http://host.com/base#path', ''); - expect(url.path()).toBe('/path'); - expect(url.absUrl()).toBe('http://host.com/base#/path'); - - url.path('wrong'); - expect(url.path()).toBe('/wrong'); - expect(url.absUrl()).toBe('http://host.com/base#/wrong'); - }); - - - it('should set path to forward-slash when empty', function() { - url = new LocationHashbangUrl('http://server/base#!', '!'); - url.path('aaa'); - - expect(url.path()).toBe('/aaa'); - expect(url.absUrl()).toBe('http://server/base#!/aaa'); - }); - - - it('should not preserve old properties when parsing new url', function() { - url.$$parse('http://www.server.org:1234/base#!/'); - - expect(url.path()).toBe('/'); - expect(url.search()).toEqual({}); - expect(url.hash()).toBe(''); - expect(url.absUrl()).toBe('http://www.server.org:1234/base#!/'); - }); - - - it('should throw error when invalid url given', function() { - expect(function() { - url.$$parse('http://server.org/path#/path'); - }).toThrow('Invalid url "http://server.org/path#/path", missing hash prefix "!" !'); - }); - - - describe('encoding', function() { - - it('should encode special characters', function() { - url.path('/a <>#'); - url.search({'i j': '<>#'}); - url.hash('<>#'); - - expect(url.path()).toBe('/a <>#'); - expect(url.search()).toEqual({'i j': '<>#'}); - expect(url.hash()).toBe('<>#'); - expect(url.absUrl()).toBe('http://www.server.org:1234/base#!/a%20%3C%3E%23?i%20j=%3C%3E%23#%3C%3E%23'); - }); - - - it('should not encode !$:@', function() { - url.path('/!$:@'); - url.search(''); - url.hash('!$:@'); - - expect(url.absUrl()).toBe('http://www.server.org:1234/base#!/!$:@#!$:@'); - }); - - - it('should decode special characters', function() { - url = new LocationHashbangUrl('http://host.com/a#/%20%3C%3E%23?i%20j=%3C%3E%23#x%20%3C%3E%23', ''); - expect(url.path()).toBe('/ <>#'); - expect(url.search()).toEqual({'i j': '<>#'}); - expect(url.hash()).toBe('x <>#'); - }); - }); - }); - - - function initService(html5Mode, hashPrefix, supportHistory) { - return module(function($provide, $locationProvider){ - $locationProvider.html5Mode(html5Mode); - $locationProvider.hashPrefix(hashPrefix); - $provide.value('$sniffer', {history: supportHistory}); - }); - } - function initBrowser(url, basePath) { - return function($browser){ - $browser.url(url); - $browser.$$baseHref = basePath; - }; - } - - describe('wiring', function() { - - beforeEach(initService(false, '!', true)); - beforeEach(inject(initBrowser('http://new.com/a/b#!', '/a/b'))); - - - it('should update $location when browser url changes', inject(function($browser, $location) { - spyOn($location, '$$parse').andCallThrough(); - $browser.url('http://new.com/a/b#!/aaa'); - $browser.poll(); - expect($location.absUrl()).toBe('http://new.com/a/b#!/aaa'); - expect($location.path()).toBe('/aaa'); - expect($location.$$parse).toHaveBeenCalledOnce(); - })); - - - // location.href = '...' fires hashchange event synchronously, so it might happen inside $apply - it('should not $apply when browser url changed inside $apply', inject( - function($rootScope, $browser, $location) { - var OLD_URL = $browser.url(), - NEW_URL = 'http://updated.com/url'; - - - $rootScope.$apply(function() { - $browser.url(NEW_URL); - $browser.poll(); // simulate firing event from browser - expect($location.absUrl()).toBe(OLD_URL); // should be async - }); - - expect($location.absUrl()).toBe(NEW_URL); - })); - - // location.href = '...' fires hashchange event synchronously, so it might happen inside $digest - it('should not $apply when browser url changed inside $digest', inject( - function($rootScope, $browser, $location) { - var OLD_URL = $browser.url(), - NEW_URL = 'http://updated.com/url', - notRunYet = true; - - $rootScope.$watch(function() { - if (notRunYet) { - notRunYet = false; - $browser.url(NEW_URL); - $browser.poll(); // simulate firing event from browser - expect($location.absUrl()).toBe(OLD_URL); // should be async - } - }); - - $rootScope.$digest(); - expect($location.absUrl()).toBe(NEW_URL); - })); - - - it('should update browser when $location changes', inject(function($rootScope, $browser, $location) { - var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough(); - $location.path('/new/path'); - expect($browserUrl).not.toHaveBeenCalled(); - $rootScope.$apply(); - - expect($browserUrl).toHaveBeenCalledOnce(); - expect($browser.url()).toBe('http://new.com/a/b#!/new/path'); - })); - - - it('should update browser only once per $apply cycle', inject(function($rootScope, $browser, $location) { - var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough(); - $location.path('/new/path'); - - $rootScope.$watch(function() { - $location.search('a=b'); - }); - - $rootScope.$apply(); - expect($browserUrl).toHaveBeenCalledOnce(); - expect($browser.url()).toBe('http://new.com/a/b#!/new/path?a=b'); - })); - - - it('should replace browser url when url was replaced at least once', - inject(function($rootScope, $location, $browser) { - var $browserUrl = spyOnlyCallsWithArgs($browser, 'url').andCallThrough(); - $location.path('/n/url').replace(); - $rootScope.$apply(); - - expect($browserUrl).toHaveBeenCalledOnce(); - expect($browserUrl.mostRecentCall.args).toEqual(['http://new.com/a/b#!/n/url', true]); - })); - - - it('should update the browser if changed from within a watcher', inject(function($rootScope, $location, $browser) { - $rootScope.$watch(function() { return true; }, function() { - $location.path('/changed'); - }); - - $rootScope.$digest(); - expect($browser.url()).toBe('http://new.com/a/b#!/changed'); - })); - }); - - - // html5 history is disabled - describe('disabled history', function() { - - it('should use hashbang url with hash prefix', function() { - initService(false, '!'); - inject( - initBrowser('http://domain.com/base/index.html#!/a/b', '/base/index.html'), - function($rootScope, $location, $browser) { - expect($browser.url()).toBe('http://domain.com/base/index.html#!/a/b'); - $location.path('/new'); - $location.search({a: true}); - $rootScope.$apply(); - expect($browser.url()).toBe('http://domain.com/base/index.html#!/new?a'); - } - ); - }); - - - it('should use hashbang url without hash prefix', function() { - initService(false, ''); - inject( - initBrowser('http://domain.com/base/index.html#/a/b', '/base/index.html'), - function($rootScope, $location, $browser) { - expect($browser.url()).toBe('http://domain.com/base/index.html#/a/b'); - $location.path('/new'); - $location.search({a: true}); - $rootScope.$apply(); - expect($browser.url()).toBe('http://domain.com/base/index.html#/new?a'); - } - ); - }); - }); - - - // html5 history enabled, but not supported by browser - describe('history on old browser', function() { - - afterEach(inject(function($document){ - dealoc($document); - })); - - it('should use hashbang url with hash prefix', function() { - initService(true, '!!', false); - inject( - initBrowser('http://domain.com/base/index.html#!!/a/b', '/base/index.html'), - function($rootScope, $location, $browser) { - expect($browser.url()).toBe('http://domain.com/base/index.html#!!/a/b'); - $location.path('/new'); - $location.search({a: true}); - $rootScope.$apply(); - expect($browser.url()).toBe('http://domain.com/base/index.html#!!/new?a'); - } - ); - }); - - - it('should redirect to hashbang url when new url given', function() { - initService(true, '!'); - inject( - initBrowser('http://domain.com/base/new-path/index.html', '/base/index.html'), - function($browser, $location) { - expect($browser.url()).toBe('http://domain.com/base/index.html#!/new-path/index.html'); - } - ); - }); - }); - - - // html5 history enabled and supported by browser - describe('history on new browser', function() { - - afterEach(inject(function($document){ - dealoc($document); - })); - - it('should use new url', function() { - initService(true, '', true); - inject( - initBrowser('http://domain.com/base/old/index.html#a', '/base/index.html'), - function($rootScope, $location, $browser) { - expect($browser.url()).toBe('http://domain.com/base/old/index.html#a'); - $location.path('/new'); - $location.search({a: true}); - $rootScope.$apply(); - expect($browser.url()).toBe('http://domain.com/base/new?a#a'); - } - ); - }); - - - it('should rewrite when hashbang url given', function() { - initService(true, '!', true); - inject( - initBrowser('http://domain.com/base/index.html#!/a/b', '/base/index.html'), - function($rootScope, $location, $browser) { - expect($browser.url()).toBe('http://domain.com/base/a/b'); - $location.path('/new'); - $location.hash('abc'); - $rootScope.$apply(); - expect($browser.url()).toBe('http://domain.com/base/new#abc'); - expect($location.path()).toBe('/new'); - } - ); - }); - - - it('should rewrite when hashbang url given (without hash prefix)', function() { - initService(true, '', true); - inject( - initBrowser('http://domain.com/base/index.html#/a/b', '/base/index.html'), - function($rootScope, $location, $browser) { - expect($browser.url()).toBe('http://domain.com/base/a/b'); - expect($location.path()).toBe('/a/b'); - } - ); - }); - }); - - - describe('URL_MATCH', function() { - - it('should parse basic url', function() { - var match = URL_MATCH.exec('http://www.angularjs.org/path?search#hash?x=x'); - - expect(match[1]).toBe('http'); - expect(match[3]).toBe('www.angularjs.org'); - expect(match[6]).toBe('/path'); - expect(match[8]).toBe('search'); - expect(match[10]).toBe('hash?x=x'); - }); - - - it('should parse file://', function() { - var match = URL_MATCH.exec('file:///Users/Shared/misko/work/angular.js/scenario/widgets.html'); - - expect(match[1]).toBe('file'); - expect(match[3]).toBe(''); - expect(match[5]).toBeFalsy(); - expect(match[6]).toBe('/Users/Shared/misko/work/angular.js/scenario/widgets.html'); - expect(match[8]).toBeFalsy(); - }); - - - it('should parse url with "-" in host', function() { - var match = URL_MATCH.exec('http://a-b1.c-d.09/path'); - - expect(match[1]).toBe('http'); - expect(match[3]).toBe('a-b1.c-d.09'); - expect(match[5]).toBeFalsy(); - expect(match[6]).toBe('/path'); - expect(match[8]).toBeFalsy(); - }); - - - it('should parse host without "/" at the end', function() { - var match = URL_MATCH.exec('http://host.org'); - expect(match[3]).toBe('host.org'); - - match = URL_MATCH.exec('http://host.org#'); - expect(match[3]).toBe('host.org'); - - match = URL_MATCH.exec('http://host.org?'); - expect(match[3]).toBe('host.org'); - }); - - - it('should match with just "/" path', function() { - var match = URL_MATCH.exec('http://server/#?book=moby'); - - expect(match[10]).toBe('?book=moby'); - }); - }); - - - describe('PATH_MATCH', function() { - - it('should parse just path', function() { - var match = PATH_MATCH.exec('/path'); - expect(match[1]).toBe('/path'); - }); - - - it('should parse path with search', function() { - var match = PATH_MATCH.exec('/ppp/a?a=b&c'); - expect(match[1]).toBe('/ppp/a'); - expect(match[3]).toBe('a=b&c'); - }); - - - it('should parse path with hash', function() { - var match = PATH_MATCH.exec('/ppp/a#abc?'); - expect(match[1]).toBe('/ppp/a'); - expect(match[5]).toBe('abc?'); - }); - - - it('should parse path with both search and hash', function() { - var match = PATH_MATCH.exec('/ppp/a?a=b&c#abc/d?'); - expect(match[3]).toBe('a=b&c'); - }); - }); - - - describe('link rewriting', function() { - - var root, link, originalBrowser, lastEventPreventDefault; - - function configureService(linkHref, html5Mode, supportHist, attrs, content) { - module(function($provide, $locationProvider) { - var jqRoot = jqLite('<div></div>'); - attrs = attrs ? ' ' + attrs + ' ' : ''; - link = jqLite('<a href="' + linkHref + '"' + attrs + '>' + content + '</a>')[0]; - root = jqRoot.append(link)[0]; - - jqLite(document.body).append(jqRoot); - - $provide.value('$document', jqRoot); - $provide.value('$sniffer', {history: supportHist}); - $locationProvider.html5Mode(html5Mode); - $locationProvider.hashPrefix('!'); - }); - } - - function initBrowser() { - return function($browser){ - $browser.url('http://host.com/base'); - $browser.$$baseHref = '/base/index.html'; - }; - } - - function initLocation() { - return function($browser, $location, $document) { - originalBrowser = $browser.url(); - // we have to prevent the default operation, as we need to test absolute links (http://...) - // and navigating to these links would kill jstd - $document.bind('click', function(e) { - lastEventPreventDefault = e.isDefaultPrevented(); - e.preventDefault(); - }); - }; - } - - function expectRewriteTo($browser, url) { - expect(lastEventPreventDefault).toBe(true); - expect($browser.url()).toBe(url); - } - - function expectNoRewrite($browser) { - expect(lastEventPreventDefault).toBe(false); - expect($browser.url()).toBe(originalBrowser); - } - - afterEach(function() { - dealoc(root); - dealoc(document.body); - }); - - - it('should rewrite rel link to new url when history enabled on new browser', function() { - configureService('link?a#b', true, true); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectRewriteTo($browser, 'http://host.com/base/link?a#b'); - } - ); - }); - - - it('should rewrite abs link to new url when history enabled on new browser', function() { - configureService('/base/link?a#b', true, true); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectRewriteTo($browser, 'http://host.com/base/link?a#b'); - } - ); - }); - - - it('should rewrite rel link to hashbang url when history enabled on old browser', function() { - configureService('link?a#b', true, false); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectRewriteTo($browser, 'http://host.com/base/index.html#!/link?a#b'); - } - ); - }); - - - it('should rewrite abs link to hashbang url when history enabled on old browser', function() { - configureService('/base/link?a#b', true, false); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectRewriteTo($browser, 'http://host.com/base/index.html#!/link?a#b'); - } - ); - }); - - - it('should not rewrite when history disabled', function() { - configureService('#new', false); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectNoRewrite($browser); - } - ); - }); - - - it('should not rewrite ng-ext-link', function() { - configureService('#new', true, true, 'ng-ext-link'); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectNoRewrite($browser); - } - ); - }); - - - it('should not rewrite full url links do different domain', function() { - configureService('http://www.dot.abc/a?b=c', true); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectNoRewrite($browser); - } - ); - }); - - - it('should not rewrite links with target="_blank"', function() { - configureService('/a?b=c', true, true, 'target="_blank"'); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectNoRewrite($browser); - } - ); - }); - - - it('should not rewrite links with target specified', function() { - configureService('/a?b=c', true, true, 'target="some-frame"'); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectNoRewrite($browser); - } - ); - }); - - - it('should rewrite full url links to same domain and base path', function() { - configureService('http://host.com/base/new', true); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click'); - expectRewriteTo($browser, 'http://host.com/base/index.html#!/new'); - } - ); - }); - - - it('should rewrite when clicked span inside link', function() { - configureService('some/link', true, true, '', '<span>link</span>'); - inject( - initBrowser(), - initLocation(), - function($browser) { - var span = jqLite(link).find('span'); - - browserTrigger(span, 'click'); - expectRewriteTo($browser, 'http://host.com/base/some/link'); - } - ); - }); - - - // don't run next tests on IE<9, as browserTrigger does not simulate pressed keys - if (!(msie < 9)) { - - it('should not rewrite when clicked with ctrl pressed', function() { - configureService('/a?b=c', true, true); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click', ['ctrl']); - expectNoRewrite($browser); - } - ); - }); - - - it('should not rewrite when clicked with meta pressed', function() { - configureService('/a?b=c', true, true); - inject( - initBrowser(), - initLocation(), - function($browser) { - browserTrigger(link, 'click', ['meta']); - expectNoRewrite($browser); - } - ); - }); - } - }); -}); diff --git a/test/service/logSpec.js b/test/service/logSpec.js deleted file mode 100644 index 269057a2..00000000 --- a/test/service/logSpec.js +++ /dev/null @@ -1,121 +0,0 @@ -'use strict'; - -describe('$log', function() { - var $window, logger, log, warn, info, error; - - - - beforeEach(module(function($provide){ - $window = {}; - logger = ''; - log = function() { logger+= 'log;'; }; - warn = function() { logger+= 'warn;'; }; - info = function() { logger+= 'info;'; }; - error = function() { logger+= 'error;'; }; - - $provide.provider('$log', $LogProvider); - $provide.value('$exceptionHandler', angular.mock.rethrow); - $provide.value('$window', $window); - })); - - it('should use console if present', inject( - function(){ - $window.console = {log: log, - warn: warn, - info: info, - error: error}; - }, - function($log) { - $log.log(); - $log.warn(); - $log.info(); - $log.error(); - expect(logger).toEqual('log;warn;info;error;'); - } - )); - - - it('should use console.log() if other not present', inject( - function(){ - $window.console = {log: log}; - }, - function($log) { - $log.log(); - $log.warn(); - $log.info(); - $log.error(); - expect(logger).toEqual('log;log;log;log;'); - } - )); - - - it('should use noop if no console', inject( - function($log) { - $log.log(); - $log.warn(); - $log.info(); - $log.error(); - } - )); - - - it("should work in IE where console.error doesn't have apply method", inject( - function() { - log.apply = log.call = - warn.apply = warn.call = - info.apply = info.call = - error.apply = error.call = null; - - $window.console = {log: log, - warn: warn, - info: info, - error: error}; - }, - function($log) { - $log.log.apply($log); - $log.warn.apply($log); - $log.info.apply($log); - $log.error.apply($log); - expect(logger).toEqual('log;warn;info;error;'); - }) - ); - - - describe('$log.error', function() { - var e, $log, errorArgs; - - beforeEach(function() { - e = new Error(''); - e.message = undefined; - e.sourceURL = undefined; - e.line = undefined; - e.stack = undefined; - - $log = new $LogProvider().$get[1]({console:{error:function() { - errorArgs = [].slice.call(arguments, 0); - }}}); - }); - - - it('should pass error if does not have trace', function() { - $log.error('abc', e); - expect(errorArgs).toEqual(['abc', e]); - }); - - - it('should print stack', function() { - e.stack = 'stack'; - $log.error('abc', e); - expect(errorArgs).toEqual(['abc', 'stack']); - }); - - - it('should print line', function() { - e.message = 'message'; - e.sourceURL = 'sourceURL'; - e.line = '123'; - $log.error('abc', e); - expect(errorArgs).toEqual(['abc', 'message\nsourceURL:123']); - }); - }); -}); diff --git a/test/service/parseSpec.js b/test/service/parseSpec.js deleted file mode 100644 index c98b180c..00000000 --- a/test/service/parseSpec.js +++ /dev/null @@ -1,631 +0,0 @@ -'use strict'; - -describe('parser', function() { - describe('lexer', function() { - it('should tokenize a string', function() { - var tokens = lex("a.bc[22]+1.3|f:'a\\\'c':\"d\\\"e\""); - var i = 0; - expect(tokens[i].index).toEqual(0); - expect(tokens[i].text).toEqual('a.bc'); - - i++; - expect(tokens[i].index).toEqual(4); - expect(tokens[i].text).toEqual('['); - - i++; - expect(tokens[i].index).toEqual(5); - expect(tokens[i].text).toEqual(22); - - i++; - expect(tokens[i].index).toEqual(7); - expect(tokens[i].text).toEqual(']'); - - i++; - expect(tokens[i].index).toEqual(8); - expect(tokens[i].text).toEqual('+'); - - i++; - expect(tokens[i].index).toEqual(9); - expect(tokens[i].text).toEqual(1.3); - - i++; - expect(tokens[i].index).toEqual(12); - expect(tokens[i].text).toEqual('|'); - - i++; - expect(tokens[i].index).toEqual(13); - expect(tokens[i].text).toEqual('f'); - - i++; - expect(tokens[i].index).toEqual(14); - expect(tokens[i].text).toEqual(':'); - - i++; - expect(tokens[i].index).toEqual(15); - expect(tokens[i].string).toEqual("a'c"); - - i++; - expect(tokens[i].index).toEqual(21); - expect(tokens[i].text).toEqual(':'); - - i++; - expect(tokens[i].index).toEqual(22); - expect(tokens[i].string).toEqual('d"e'); - }); - - it('should tokenize undefined', function() { - var tokens = lex("undefined"); - var i = 0; - expect(tokens[i].index).toEqual(0); - expect(tokens[i].text).toEqual('undefined'); - expect(undefined).toEqual(tokens[i].fn()); - }); - - it('should tokenize quoted string', function() { - var str = "['\\'', \"\\\"\"]"; - var tokens = lex(str); - - expect(tokens[1].index).toEqual(1); - expect(tokens[1].string).toEqual("'"); - - expect(tokens[3].index).toEqual(7); - expect(tokens[3].string).toEqual('"'); - }); - - it('should tokenize escaped quoted string', function() { - var str = '"\\"\\n\\f\\r\\t\\v\\u00A0"'; - var tokens = lex(str); - - expect(tokens[0].string).toEqual('"\n\f\r\t\v\u00A0'); - }); - - it('should tokenize unicode', function() { - var tokens = lex('"\\u00A0"'); - expect(tokens.length).toEqual(1); - expect(tokens[0].string).toEqual('\u00a0'); - }); - - it('should ignore whitespace', function() { - var tokens = lex("a \t \n \r b"); - expect(tokens[0].text).toEqual('a'); - expect(tokens[1].text).toEqual('b'); - }); - - it('should tokenize relation', function() { - var tokens = lex("! == != < > <= >="); - expect(tokens[0].text).toEqual('!'); - expect(tokens[1].text).toEqual('=='); - expect(tokens[2].text).toEqual('!='); - expect(tokens[3].text).toEqual('<'); - expect(tokens[4].text).toEqual('>'); - expect(tokens[5].text).toEqual('<='); - expect(tokens[6].text).toEqual('>='); - }); - - it('should tokenize statements', function() { - var tokens = lex("a;b;"); - expect(tokens[0].text).toEqual('a'); - expect(tokens[1].text).toEqual(';'); - expect(tokens[2].text).toEqual('b'); - expect(tokens[3].text).toEqual(';'); - }); - - it('should tokenize function invocation', function() { - var tokens = lex("a()") - expect(map(tokens, function(t) { return t.text;})).toEqual(['a', '(', ')']); - }); - - it('should tokenize method invocation', function() { - var tokens = lex("a.b.c (d) - e.f()"); - expect(map(tokens, function(t) { return t.text;})). - toEqual(['a.b', '.', 'c', '(', 'd', ')', '-', 'e', '.', 'f', '(', ')']); - }); - - it('should tokenize number', function() { - var tokens = lex("0.5"); - expect(tokens[0].text).toEqual(0.5); - }); - - it('should tokenize negative number', inject(function($rootScope) { - var value = $rootScope.$eval("-0.5"); - expect(value).toEqual(-0.5); - - value = $rootScope.$eval("{a:-0.5}"); - expect(value).toEqual({a:-0.5}); - })); - - it('should tokenize number with exponent', inject(function($rootScope) { - var tokens = lex("0.5E-10"); - expect(tokens[0].text).toEqual(0.5E-10); - expect($rootScope.$eval("0.5E-10")).toEqual(0.5E-10); - - tokens = lex("0.5E+10"); - expect(tokens[0].text).toEqual(0.5E+10); - })); - - it('should throws exception for invalid exponent', function() { - expect(function() { - lex("0.5E-"); - }).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-].')); - - expect(function() { - lex("0.5E-A"); - }).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-A].')); - }); - - it('should tokenize number starting with a dot', function() { - var tokens = lex(".5"); - expect(tokens[0].text).toEqual(0.5); - }); - - it('should throw error on invalid unicode', function() { - expect(function() { - lex("'\\u1''bla'"); - }).toThrow(new Error("Lexer Error: Invalid unicode escape [\\u1''b] at column 2 in expression ['\\u1''bla'].")); - }); - }); - - var scope, $filterProvider; - beforeEach(module(['$filterProvider', function (filterProvider) { - $filterProvider = filterProvider; - }])); - beforeEach(inject(function ($rootScope) { - scope = $rootScope; - })); - - it('should parse expressions', function() { - expect(scope.$eval("-1")).toEqual(-1); - expect(scope.$eval("1 + 2.5")).toEqual(3.5); - expect(scope.$eval("1 + -2.5")).toEqual(-1.5); - expect(scope.$eval("1+2*3/4")).toEqual(1+2*3/4); - expect(scope.$eval("0--1+1.5")).toEqual(0- -1 + 1.5); - expect(scope.$eval("-0--1++2*-3/-4")).toEqual(-0- -1+ +2*-3/-4); - expect(scope.$eval("1/2*3")).toEqual(1/2*3); - }); - - it('should parse comparison', function() { - expect(scope.$eval("false")).toBeFalsy(); - expect(scope.$eval("!true")).toBeFalsy(); - expect(scope.$eval("1==1")).toBeTruthy(); - expect(scope.$eval("1!=2")).toBeTruthy(); - expect(scope.$eval("1<2")).toBeTruthy(); - expect(scope.$eval("1<=1")).toBeTruthy(); - expect(scope.$eval("1>2")).toEqual(1>2); - expect(scope.$eval("2>=1")).toEqual(2>=1); - expect(scope.$eval("true==2<3")).toEqual(true === 2<3); - }); - - it('should parse logical', function() { - expect(scope.$eval("0&&2")).toEqual(0&&2); - expect(scope.$eval("0||2")).toEqual(0||2); - expect(scope.$eval("0||1&&2")).toEqual(0||1&&2); - }); - - it('should parse string', function() { - expect(scope.$eval("'a' + 'b c'")).toEqual("ab c"); - }); - - it('should parse filters', function() { - $filterProvider.register('substring', valueFn(function(input, start, end) { - return input.substring(start, end); - })); - - expect(function() { - scope.$eval("1|nonexistent"); - }).toThrow(new Error("Unknown provider: nonexistentFilterProvider <- nonexistentFilter")); - - scope.offset = 3; - expect(scope.$eval("'abcd'|substring:1:offset")).toEqual("bc"); - expect(scope.$eval("'abcd'|substring:1:3|uppercase")).toEqual("BC"); - }); - - it('should access scope', function() { - scope.a = 123; - scope.b = {c: 456}; - expect(scope.$eval("a", scope)).toEqual(123); - expect(scope.$eval("b.c", scope)).toEqual(456); - expect(scope.$eval("x.y.z", scope)).not.toBeDefined(); - }); - - it('should support property names that colide with native object properties', function() { - // regression - scope.watch = 1; - scope.constructor = 2; - scope.toString = 3; - - expect(scope.$eval('watch', scope)).toBe(1); - expect(scope.$eval('constructor', scope)).toBe(2); - expect(scope.$eval('toString', scope)).toBe(3); - }); - - it('should evaluate grouped expressions', function() { - expect(scope.$eval("(1+2)*3")).toEqual((1+2)*3); - }); - - it('should evaluate assignments', function() { - expect(scope.$eval("a=12")).toEqual(12); - expect(scope.a).toEqual(12); - - expect(scope.$eval("x.y.z=123;")).toEqual(123); - expect(scope.x.y.z).toEqual(123); - - expect(scope.$eval("a=123; b=234")).toEqual(234); - expect(scope.a).toEqual(123); - expect(scope.b).toEqual(234); - }); - - it('should evaluate function call without arguments', function() { - scope['const'] = function(a,b){return 123;}; - expect(scope.$eval("const()")).toEqual(123); - }); - - it('should evaluate function call with arguments', function() { - scope.add = function(a,b) { - return a+b; - }; - expect(scope.$eval("add(1,2)")).toEqual(3); - }); - - it('should evaluate function call from a return value', function() { - scope.val = 33; - scope.getter = function() { return function() { return this.val; }}; - expect(scope.$eval("getter()()")).toBe(33); - }); - - it('should evaluate multiplication and division', function() { - scope.taxRate = 8; - scope.subTotal = 100; - expect(scope.$eval("taxRate / 100 * subTotal")).toEqual(8); - expect(scope.$eval("subTotal * taxRate / 100")).toEqual(8); - }); - - it('should evaluate array', function() { - expect(scope.$eval("[]").length).toEqual(0); - expect(scope.$eval("[1, 2]").length).toEqual(2); - expect(scope.$eval("[1, 2]")[0]).toEqual(1); - expect(scope.$eval("[1, 2]")[1]).toEqual(2); - }); - - it('should evaluate array access', function() { - expect(scope.$eval("[1][0]")).toEqual(1); - expect(scope.$eval("[[1]][0][0]")).toEqual(1); - expect(scope.$eval("[].length")).toEqual(0); - expect(scope.$eval("[1, 2].length")).toEqual(2); - }); - - it('should evaluate object', function() { - expect(toJson(scope.$eval("{}"))).toEqual("{}"); - expect(toJson(scope.$eval("{a:'b'}"))).toEqual('{"a":"b"}'); - expect(toJson(scope.$eval("{'a':'b'}"))).toEqual('{"a":"b"}'); - expect(toJson(scope.$eval("{\"a\":'b'}"))).toEqual('{"a":"b"}'); - }); - - it('should evaluate object access', function() { - expect(scope.$eval("{false:'WC', true:'CC'}[false]")).toEqual("WC"); - }); - - it('should evaluate JSON', function() { - expect(toJson(scope.$eval("[{}]"))).toEqual("[{}]"); - expect(toJson(scope.$eval("[{a:[]}, {b:1}]"))).toEqual('[{"a":[]},{"b":1}]'); - }); - - it('should evaluate multiple statements', function() { - expect(scope.$eval("a=1;b=3;a+b")).toEqual(4); - expect(scope.$eval(";;1;;")).toEqual(1); - }); - - it('should evaluate object methods in correct context (this)', function() { - var C = function () { - this.a = 123; - }; - C.prototype.getA = function() { - return this.a; - }; - - scope.obj = new C(); - expect(scope.$eval("obj.getA()")).toEqual(123); - expect(scope.$eval("obj['getA']()")).toEqual(123); - }); - - it('should evaluate methods in correct context (this) in argument', function() { - var C = function () { - this.a = 123; - }; - C.prototype.sum = function(value) { - return this.a + value; - }; - C.prototype.getA = function() { - return this.a; - }; - - scope.obj = new C(); - expect(scope.$eval("obj.sum(obj.getA())")).toEqual(246); - expect(scope.$eval("obj['sum'](obj.getA())")).toEqual(246); - }); - - it('should evaluate objects on scope context', function() { - scope.a = "abc"; - expect(scope.$eval("{a:a}").a).toEqual("abc"); - }); - - it('should evaluate field access on function call result', function() { - scope.a = function() { - return {name:'misko'}; - }; - expect(scope.$eval("a().name")).toEqual("misko"); - }); - - it('should evaluate field access after array access', function () { - scope.items = [{}, {name:'misko'}]; - expect(scope.$eval('items[1].name')).toEqual("misko"); - }); - - it('should evaluate array assignment', function() { - scope.items = []; - - expect(scope.$eval('items[1] = "abc"')).toEqual("abc"); - expect(scope.$eval('items[1]')).toEqual("abc"); -// Dont know how to make this work.... -// expect(scope.$eval('books[1] = "moby"')).toEqual("moby"); -// expect(scope.$eval('books[1]')).toEqual("moby"); - }); - - it('should evaluate grouped filters', function() { - scope.name = 'MISKO'; - expect(scope.$eval('n = (name|lowercase)')).toEqual('misko'); - expect(scope.$eval('n')).toEqual('misko'); - }); - - it('should evaluate remainder', function() { - expect(scope.$eval('1%2')).toEqual(1); - }); - - it('should evaluate sum with undefined', function() { - expect(scope.$eval('1+undefined')).toEqual(1); - expect(scope.$eval('undefined+1')).toEqual(1); - }); - - it('should throw exception on non-closed bracket', function() { - expect(function() { - scope.$eval('[].count('); - }).toThrow('Unexpected end of expression: [].count('); - }); - - it('should evaluate double negation', function() { - expect(scope.$eval('true')).toBeTruthy(); - expect(scope.$eval('!true')).toBeFalsy(); - expect(scope.$eval('!!true')).toBeTruthy(); - expect(scope.$eval('{true:"a", false:"b"}[!!true]')).toEqual('a'); - }); - - it('should evaluate negation', function() { - expect(scope.$eval("!false || true")).toEqual(!false || true); - expect(scope.$eval("!11 == 10")).toEqual(!11 == 10); - expect(scope.$eval("12/6/2")).toEqual(12/6/2); - }); - - it('should evaluate exclamation mark', function() { - expect(scope.$eval('suffix = "!"')).toEqual('!'); - }); - - it('should evaluate minus', function() { - expect(scope.$eval("{a:'-'}")).toEqual({a: "-"}); - }); - - it('should evaluate undefined', function() { - expect(scope.$eval("undefined")).not.toBeDefined(); - expect(scope.$eval("a=undefined")).not.toBeDefined(); - expect(scope.a).not.toBeDefined(); - }); - - it('should allow assignment after array dereference', function() { - scope.obj = [{}]; - scope.$eval('obj[0].name=1'); - expect(scope.obj.name).toBeUndefined(); - expect(scope.obj[0].name).toEqual(1); - }); - - it('should short-circuit AND operator', function() { - scope.run = function() { - throw "IT SHOULD NOT HAVE RUN"; - }; - expect(scope.$eval('false && run()')).toBe(false); - }); - - it('should short-circuit OR operator', function() { - scope.run = function() { - throw "IT SHOULD NOT HAVE RUN"; - }; - expect(scope.$eval('true || run()')).toBe(true); - }); - - - describe('promises', function() { - var deferred, promise, q; - - beforeEach(inject(function($q) { - q = $q; - deferred = q.defer(); - promise = deferred.promise; - })); - - describe('{{promise}}', function() { - it('should evaluated resolved promise and get its value', function() { - deferred.resolve('hello!'); - scope.greeting = promise; - expect(scope.$eval('greeting')).toBe(undefined); - scope.$digest(); - expect(scope.$eval('greeting')).toBe('hello!'); - }); - - - it('should evaluated rejected promise and ignore the rejection reason', function() { - deferred.reject('sorry'); - scope.greeting = promise; - expect(scope.$eval('gretting')).toBe(undefined); - scope.$digest(); - expect(scope.$eval('greeting')).toBe(undefined); - }); - - - it('should evaluate a promise and eventualy get its value', function() { - scope.greeting = promise; - expect(scope.$eval('greeting')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('greeting')).toBe(undefined); - - deferred.resolve('hello!'); - expect(scope.$eval('greeting')).toBe(undefined); - scope.$digest(); - expect(scope.$eval('greeting')).toBe('hello!'); - }); - - - it('should evaluate a promise and eventualy ignore its rejection', function() { - scope.greeting = promise; - expect(scope.$eval('greeting')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('greeting')).toBe(undefined); - - deferred.reject('sorry'); - expect(scope.$eval('greeting')).toBe(undefined); - scope.$digest(); - expect(scope.$eval('greeting')).toBe(undefined); - }); - }); - - describe('dereferencing', function() { - it('should evaluate and dereference properties leading to and from a promise', function() { - scope.obj = {greeting: promise}; - expect(scope.$eval('obj.greeting')).toBe(undefined); - expect(scope.$eval('obj.greeting.polite')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('obj.greeting')).toBe(undefined); - expect(scope.$eval('obj.greeting.polite')).toBe(undefined); - - deferred.resolve({polite: 'Good morning!'}); - scope.$digest(); - expect(scope.$eval('obj.greeting')).toEqual({polite: 'Good morning!'}); - expect(scope.$eval('obj.greeting.polite')).toBe('Good morning!'); - }); - - it('should evaluate and dereference properties leading to and from a promise via bracket ' + - 'notation', function() { - scope.obj = {greeting: promise}; - expect(scope.$eval('obj["greeting"]')).toBe(undefined); - expect(scope.$eval('obj["greeting"]["polite"]')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('obj["greeting"]')).toBe(undefined); - expect(scope.$eval('obj["greeting"]["polite"]')).toBe(undefined); - - deferred.resolve({polite: 'Good morning!'}); - scope.$digest(); - expect(scope.$eval('obj["greeting"]')).toEqual({polite: 'Good morning!'}); - expect(scope.$eval('obj["greeting"]["polite"]')).toBe('Good morning!'); - }); - - - it('should evaluate and dereference array references leading to and from a promise', - function() { - scope.greetings = [promise]; - expect(scope.$eval('greetings[0]')).toBe(undefined); - expect(scope.$eval('greetings[0][0]')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('greetings[0]')).toBe(undefined); - expect(scope.$eval('greetings[0][0]')).toBe(undefined); - - deferred.resolve(['Hi!', 'Cau!']); - scope.$digest(); - expect(scope.$eval('greetings[0]')).toEqual(['Hi!', 'Cau!']); - expect(scope.$eval('greetings[0][0]')).toBe('Hi!'); - }); - - - it('should evaluate and dereference promises used as function arguments', function() { - scope.greet = function(name) { return 'Hi ' + name + '!'; }; - scope.name = promise; - expect(scope.$eval('greet(name)')).toBe('Hi undefined!'); - - scope.$digest(); - expect(scope.$eval('greet(name)')).toBe('Hi undefined!'); - - deferred.resolve('Veronica'); - expect(scope.$eval('greet(name)')).toBe('Hi undefined!'); - - scope.$digest(); - expect(scope.$eval('greet(name)')).toBe('Hi Veronica!'); - }); - - - it('should evaluate and dereference promises used as array indexes', function() { - scope.childIndex = promise; - scope.kids = ['Adam', 'Veronica', 'Elisa']; - expect(scope.$eval('kids[childIndex]')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('kids[childIndex]')).toBe(undefined); - - deferred.resolve(1); - expect(scope.$eval('kids[childIndex]')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('kids[childIndex]')).toBe('Veronica'); - }); - - - it('should evaluate and dereference promises used as keys in bracket notation', function() { - scope.childKey = promise; - scope.kids = {'a': 'Adam', 'v': 'Veronica', 'e': 'Elisa'}; - - expect(scope.$eval('kids[childKey]')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('kids[childKey]')).toBe(undefined); - - deferred.resolve('v'); - expect(scope.$eval('kids[childKey]')).toBe(undefined); - - scope.$digest(); - expect(scope.$eval('kids[childKey]')).toBe('Veronica'); - }); - - - it('should not mess with the promise if it was not directly evaluated', function() { - scope.obj = {greeting: promise, username: 'hi'}; - var obj = scope.$eval('obj'); - expect(obj.username).toEqual('hi'); - expect(typeof obj.greeting.then).toBe('function'); - }); - }); - }); - - - describe('assignable', function() { - it('should expose assignment function', inject(function($parse) { - var fn = $parse('a'); - expect(fn.assign).toBeTruthy(); - var scope = {}; - fn.assign(scope, 123); - expect(scope).toEqual({a:123}); - })); - }); - - - describe('locals', function() { - it('should expose local variables', inject(function($parse) { - expect($parse('a')({a: 0}, {a: 1})).toEqual(1); - expect($parse('add(a,b)')({b: 1, add: function(a, b) { return a + b; }}, {a: 2})).toEqual(3); - })); - - it('should expose traverse locals', inject(function($parse) { - expect($parse('a.b')({a: {b: 0}}, {a: {b:1}})).toEqual(1); - expect($parse('a.b')({a: null}, {a: {b:1}})).toEqual(1); - expect($parse('a.b')({a: {b: 0}}, {a: null})).toEqual(undefined); - })); - }); -}); diff --git a/test/service/qSpec.js b/test/service/qSpec.js deleted file mode 100644 index a230d1de..00000000 --- a/test/service/qSpec.js +++ /dev/null @@ -1,831 +0,0 @@ -'use strict'; - -/** - http://wiki.commonjs.org/wiki/Promises - http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript - - Q: https://github.com/kriskowal/q - https://github.com/kriskowal/q/blob/master/design/README.js - https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md - http://jsconf.eu/2010/speaker/commonjs_i_promise_by_kris_kow.html - - good walkthrough of the Q api's and design, jump to 15:30 - - twisted: http://twistedmatrix.com/documents/11.0.0/api/twisted.internet.defer.Deferred.html - dojo: https://github.com/dojo/dojo/blob/master/_base/Deferred.js - http://dojotoolkit.org/api/1.6/dojo/Deferred - http://dojotoolkit.org/documentation/tutorials/1.6/promises/ - when.js: https://github.com/briancavalier/when.js - DART: http://www.dartlang.org/docs/api/Promise.html#Promise::Promise - http://code.google.com/p/dart/source/browse/trunk/dart/corelib/src/promise.dart - http://codereview.chromium.org/8271014/patch/11003/12005 - https://chromereviews.googleplex.com/3365018/ - WinJS: http://msdn.microsoft.com/en-us/library/windows/apps/br211867.aspx - - http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Future.html - http://en.wikipedia.org/wiki/Futures_and_promises - http://wiki.ecmascript.org/doku.php?id=strawman:deferred_functions - http://wiki.ecmascript.org/doku.php?id=strawman:async_functions - - - http://jsperf.com/throw-vs-return -*/ - -describe('q', function() { - var q, defer, deferred, promise, log; - - /** - * Creates a callback that logs its invocation in `log`. - * - * @param {(number|string)} name Suffix for 'success' name. e.g. success(1) => success1 - * @param {*=} returnVal Value that the callback should return. If unspecified, the passed in - * value is returned. - * @param {boolean=} throwReturnVal If true, the `returnVal` will be thrown rather than returned. - */ - function success(name, returnVal, throwReturnVal) { - var returnValDefined = (arguments.length >= 2); - - return function() { - name = 'success' + (name || ''); - var args = toJson(sliceArgs(arguments)).replace(/(^\[|"|\]$)/g, ''); - log.push(name + '(' + args + ')'); - returnVal = returnValDefined ? returnVal : arguments[0]; - if (throwReturnVal) throw returnVal; - return returnVal; - } - } - - - /** - * Creates a callback that logs its invocation in `log`. - * - * @param {(number|string)} name Suffix for 'error' name. e.g. error(1) => error1 - * @param {*=} returnVal Value that the callback should return. If unspecified, the passed in - * value is rethrown. - * @param {boolean=} throwReturnVal If true, the `returnVal` will be thrown rather than returned. - */ - function error(name, returnVal, throwReturnVal) { - var returnValDefined = (arguments.length >= 2); - - return function(){ - name = 'error' + (name || ''); - log.push(name + '(' + [].join.call(arguments, ',') + ')'); - returnVal = returnValDefined ? returnVal : q.reject(arguments[0]); - if (throwReturnVal) throw returnVal; - return returnVal; - } - } - - - /** helper for synchronous resolution of deferred */ - function syncResolve(deferred, result) { - deferred.resolve(result); - mockNextTick.flush(); - } - - - /** helper for synchronous rejection of deferred */ - function syncReject(deferred, reason) { - deferred.reject(reason); - mockNextTick.flush(); - } - - - /** converts the `log` to a '; '-separated string */ - function logStr() { - return log.join('; '); - } - - - var mockNextTick = { - nextTick: function(task) { - mockNextTick.queue.push(task); - }, - queue: [], - flush: function() { - if (!mockNextTick.queue.length) throw new Error('Nothing to be flushed!'); - while (mockNextTick.queue.length) { - var queue = mockNextTick.queue; - mockNextTick.queue = []; - forEach(queue, function(task) { - try { - task(); - } catch(e) { - dump('exception in mockNextTick:', e, e.name, e.message, task); - } - }); - } - } - } - - - beforeEach(function() { - q = qFactory(mockNextTick.nextTick, noop), - defer = q.defer; - deferred = defer() - promise = deferred.promise; - log = []; - mockNextTick.queue = []; - }); - - - afterEach(function() { - expect(mockNextTick.queue.length).toBe(0); - }); - - - describe('defer', function() { - it('should create a new deferred', function() { - expect(deferred.promise).toBeDefined(); - expect(deferred.resolve).toBeDefined(); - expect(deferred.reject).toBeDefined(); - }); - - - describe('resolve', function() { - it('should fulfill the promise and execute all success callbacks in the registration order', - function() { - promise.then(success(1), error()); - promise.then(success(2), error()); - expect(logStr()).toBe(''); - - deferred.resolve('foo'); - mockNextTick.flush(); - expect(logStr()).toBe('success1(foo); success2(foo)'); - }); - - - it('should do nothing if a promise was previously resolved', function() { - promise.then(success(), error()); - expect(logStr()).toBe(''); - - deferred.resolve('foo'); - mockNextTick.flush(); - expect(logStr()).toBe('success(foo)'); - - log = []; - deferred.resolve('bar'); - deferred.reject('baz'); - expect(mockNextTick.queue.length).toBe(0); - expect(logStr()).toBe(''); - }); - - - it('should do nothing if a promise was previously rejected', function() { - promise.then(success(), error()); - expect(logStr()).toBe(''); - - deferred.reject('foo'); - mockNextTick.flush(); - expect(logStr()).toBe('error(foo)'); - - log = []; - deferred.resolve('bar'); - deferred.reject('baz'); - expect(mockNextTick.queue.length).toBe(0); - expect(logStr()).toBe(''); - }); - - - it('should allow deferred resolution with a new promise', function() { - var deferred2 = defer(); - promise.then(success(), error()); - - deferred.resolve(deferred2.promise); - mockNextTick.flush(); - expect(logStr()).toBe(''); - - deferred2.resolve('foo'); - mockNextTick.flush(); - expect(logStr()).toBe('success(foo)'); - }); - - - it('should call the callback in the next turn', function() { - promise.then(success()); - expect(logStr()).toBe(''); - - deferred.resolve('foo'); - expect(logStr()).toBe(''); - - mockNextTick.flush(); - expect(logStr()).toBe('success(foo)'); - }); - - - it('should support non-bound execution', function() { - var resolver = deferred.resolve; - promise.then(success(), error()); - resolver('detached'); - mockNextTick.flush(); - expect(logStr()).toBe('success(detached)'); - }); - - - it('should not break if a callbacks registers another callback', function() { - promise.then(function() { - log.push('outer'); - promise.then(function() { - log.push('inner'); - }); - }); - - deferred.resolve('foo'); - expect(logStr()).toBe(''); - - mockNextTick.flush(); - expect(logStr()).toBe('outer; inner'); - }); - - - it('should not break if a callbacks tries to resolve the deferred again', function() { - promise.then(function(val) { - log.push('success1(' + val + ')'); - deferred.resolve('bar'); - }); - - promise.then(success(2)); - - deferred.resolve('foo'); - expect(logStr()).toBe(''); - - mockNextTick.flush(); - expect(logStr()).toBe('success1(foo); success2(foo)'); - }); - }); - - - describe('reject', function() { - it('should reject the promise and execute all error callbacks in the registration order', - function() { - promise.then(success(), error(1)); - promise.then(success(), error(2)); - expect(logStr()).toBe(''); - - deferred.reject('foo'); - mockNextTick.flush(); - expect(logStr()).toBe('error1(foo); error2(foo)'); - }); - - - it('should do nothing if a promise was previously resolved', function() { - promise.then(success(1), error(1)); - expect(logStr()).toBe(''); - - deferred.resolve('foo'); - mockNextTick.flush(); - expect(logStr()).toBe('success1(foo)'); - - log = []; - deferred.reject('bar'); - deferred.resolve('baz'); - expect(mockNextTick.queue.length).toBe(0); - expect(logStr()).toBe(''); - - promise.then(success(2), error(2)) - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('success2(foo)'); - }); - - - it('should do nothing if a promise was previously rejected', function() { - promise.then(success(1), error(1)); - expect(logStr()).toBe(''); - - deferred.reject('foo'); - mockNextTick.flush(); - expect(logStr()).toBe('error1(foo)'); - - log = []; - deferred.reject('bar'); - deferred.resolve('baz'); - expect(mockNextTick.queue.length).toBe(0); - expect(logStr()).toBe(''); - - promise.then(success(2), error(2)) - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('error2(foo)'); - }); - - - it('should not defer rejection with a new promise', function() { - var deferred2 = defer(); - promise.then(success(), error()); - - deferred.reject(deferred2.promise); - mockNextTick.flush(); - expect(logStr()).toBe('error([object Object])'); - }); - - - it('should call the error callback in the next turn', function() { - promise.then(success(), error()); - expect(logStr()).toBe(''); - - deferred.reject('foo'); - expect(logStr()).toBe(''); - - mockNextTick.flush(); - expect(logStr()).toBe('error(foo)'); - }); - - - it('should support non-bound execution', function() { - var rejector = deferred.reject; - promise.then(success(), error()); - rejector('detached'); - mockNextTick.flush(); - expect(logStr()).toBe('error(detached)'); - }); - }); - - - describe('promise', function() { - it('should have a then method', function() { - expect(typeof promise.then).toBe('function'); - }); - - - describe('then', function() { - it('should allow registration of a success callback without an errback and resolve', - function() { - promise.then(success()); - syncResolve(deferred, 'foo'); - expect(logStr()).toBe('success(foo)'); - }); - - it('should allow registration of a success callback without an errback and reject', - function() { - promise.then(success()); - syncReject(deferred, 'foo'); - expect(logStr()).toBe(''); - }); - - - it('should allow registration of an errback without a success callback and reject', - function() { - promise.then(null, error()); - syncReject(deferred, 'oops!'); - expect(logStr()).toBe('error(oops!)'); - }); - - - it('should allow registration of an errback without a success callback and resolve', - function() { - promise.then(null, error()); - syncResolve(deferred, 'done'); - expect(logStr()).toBe(''); - }); - - - it('should resolve all callbacks with the original value', function() { - promise.then(success('A', 'aVal'), error()); - promise.then(success('B', 'bErr', true), error()); - promise.then(success('C', q.reject('cReason')), error()); - promise.then(success('D', 'dVal'), error()); - - expect(logStr()).toBe(''); - syncResolve(deferred, 'yup'); - expect(logStr()).toBe('successA(yup); successB(yup); successC(yup); successD(yup)'); - }); - - - it('should reject all callbacks with the original reason', function() { - promise.then(success(), error('A', 'aVal')); - promise.then(success(), error('B', 'bEr', true)); - promise.then(success(), error('C', q.reject('cReason'))); - promise.then(success(), error('D', 'dVal')); - - expect(logStr()).toBe(''); - syncReject(deferred, 'noo!'); - expect(logStr()).toBe('errorA(noo!); errorB(noo!); errorC(noo!); errorD(noo!)'); - }); - - - it('should propagate resolution and rejection between dependent promises', function() { - promise.then(success(1, 'x'), error('1')). - then(success(2, 'y', true), error('2')). - then(success(3), error(3, 'z', true)). - then(success(4), error(4, 'done')). - then(success(5), error(5)); - - expect(logStr()).toBe(''); - syncResolve(deferred, 'sweet!'); - expect(log).toEqual(['success1(sweet!)', - 'success2(x)', - 'error3(y)', - 'error4(z)', - 'success5(done)']); - }); - - - it('should reject a derived promise if an exception is thrown while resolving its parent', - function() { - promise.then(success(1, 'oops', true)). - then(success(2), error(2)); - syncResolve(deferred, 'done!'); - expect(logStr()).toBe('success1(done!); error2(oops)'); - }); - - - it('should reject a derived promise if an exception is thrown while rejecting its parent', - function() { - promise.then(null, error(1, 'oops', true)). - then(success(2), error(2)); - syncReject(deferred, 'timeout'); - expect(logStr()).toBe('error1(timeout); error2(oops)'); - }); - - - it('should call success callback in the next turn even if promise is already resolved', - function() { - deferred.resolve('done!'); - - promise.then(success()); - expect(logStr()).toBe(''); - - mockNextTick.flush(); - expect(log).toEqual(['success(done!)']); - }); - - - it('should call errpr callback in the next turn even if promise is already rejected', - function() { - deferred.reject('oops!'); - - promise.then(null, error()); - expect(logStr()).toBe(''); - - mockNextTick.flush(); - expect(log).toEqual(['error(oops!)']); - }); - }); - }); - }); - - - describe('reject', function() { - it('should package a string into a rejected promise', function() { - var rejectedPromise = q.reject('not gonna happen'); - promise.then(success(), error()); - syncResolve(deferred, rejectedPromise); - expect(log).toEqual(['error(not gonna happen)']); - }); - - - it('should package an exception into a rejected promise', function() { - var rejectedPromise = q.reject(Error('not gonna happen')); - promise.then(success(), error()); - syncResolve(deferred, rejectedPromise); - expect(log).toEqual(['error(Error: not gonna happen)']); - }); - }); - - - describe('when', function() { - describe('resolution', function() { - it('should call the success callback in the next turn when the value is a non-promise', - function() { - q.when('hello', success(), error()); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('success(hello)'); - }); - - - it('should call the success callback in the next turn when the value is a resolved promise', - function() { - deferred.resolve('hello'); - q.when(deferred.promise, success(), error()); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('success(hello)'); - }); - - - it('should call the errback in the next turn when the value is a rejected promise', function() { - deferred.reject('nope'); - q.when(deferred.promise, success(), error()); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('error(nope)'); - }); - - - it('should call the success callback after the original promise is resolved', - function() { - q.when(deferred.promise, success(), error()); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe(''); - syncResolve(deferred, 'hello'); - expect(logStr()).toBe('success(hello)'); - }); - - - it('should call the errback after the orignal promise is rejected', - function() { - q.when(deferred.promise, success(), error()); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe(''); - syncReject(deferred, 'nope'); - expect(logStr()).toBe('error(nope)'); - }); - }); - - - describe('optional callbacks', function() { - it('should not require success callback and propagate resolution', function() { - q.when('hi', null, error()).then(success(2), error()); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('success2(hi)'); - }); - - - it('should not require success callback and propagate rejection', function() { - q.when(q.reject('sorry'), null, error(1)).then(success(), error(2)); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('error1(sorry); error2(sorry)'); - }); - - - it('should not require errback and propagate resolution', function() { - q.when('hi', success(1, 'hello')).then(success(2), error()); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('success1(hi); success2(hello)'); - }); - - - it('should not require errback and propagate rejection', function() { - q.when(q.reject('sorry'), success()).then(success(2), error(2)); - expect(logStr()).toBe(''); - mockNextTick.flush(); - expect(logStr()).toBe('error2(sorry)'); - }); - }); - - - describe('returned promise', function() { - it('should return a promise that can be resolved with a value returned from the success ' + - 'callback', function() { - q.when('hello', success(1, 'hi'), error()).then(success(2), error()); - mockNextTick.flush(); - expect(logStr()).toBe('success1(hello); success2(hi)'); - }); - - - it('should return a promise that can be rejected with a rejected promise returned from the ' + - 'success callback', function() { - q.when('hello', success(1, q.reject('sorry')), error()).then(success(), error(2)); - mockNextTick.flush(); - expect(logStr()).toBe('success1(hello); error2(sorry)'); - }); - - - it('should return a promise that can be resolved with a value returned from the errback', - function() { - q.when(q.reject('sorry'), success(), error(1, 'hi')).then(success(2), error()); - mockNextTick.flush(); - expect(logStr()).toBe('error1(sorry); success2(hi)'); - }); - - - it('should return a promise that can be rejected with a rejected promise returned from the ' + - 'errback', function() { - q.when(q.reject('sorry'), success(), error(1, q.reject('sigh'))).then(success(), error(2)); - mockNextTick.flush(); - expect(logStr()).toBe('error1(sorry); error2(sigh)'); - }); - - - it('should return a promise that can be resolved with a promise returned from the success ' + - 'callback', function() { - var deferred2 = defer(); - q.when('hi', success(1, deferred2.promise), error()).then(success(2), error()); - mockNextTick.flush(); - expect(logStr()).toBe('success1(hi)'); - syncResolve(deferred2, 'finally!'); - expect(logStr()).toBe('success1(hi); success2(finally!)'); - }); - - - it('should return a promise that can be resolved with promise returned from the errback ' + - 'callback', function() { - var deferred2 = defer(); - q.when(q.reject('sorry'), success(), error(1, deferred2.promise)).then(success(2), error()); - mockNextTick.flush(); - expect(logStr()).toBe('error1(sorry)'); - syncResolve(deferred2, 'finally!'); - expect(logStr()).toBe('error1(sorry); success2(finally!)'); - }); - }); - - - describe('security', function() { - it('should call success callback only once even if the original promise gets fullfilled ' + - 'multiple times', function() { - var evilPromise = { - then: function(success, error) { - evilPromise.success = success; - evilPromise.error = error; - } - } - - q.when(evilPromise, success(), error()); - mockNextTick.flush(); - expect(logStr()).toBe(''); - evilPromise.success('done'); - mockNextTick.flush(); // TODO(i) wrong queue, evil promise would be resolved outside of the - // scope.$apply lifecycle and in that case we should have some kind - // of fallback queue for calling our callbacks from. Otherwise the - // application will get stuck until something triggers next $apply. - expect(logStr()).toBe('success(done)'); - - evilPromise.success('evil is me'); - evilPromise.error('burn burn'); - expect(logStr()).toBe('success(done)'); - }); - - - it('should call errback only once even if the original promise gets fullfilled multiple ' + - 'times', function() { - var evilPromise = { - then: function(success, error) { - evilPromise.success = success; - evilPromise.error = error; - } - } - - q.when(evilPromise, success(), error()); - mockNextTick.flush(); - expect(logStr()).toBe(''); - evilPromise.error('failed'); - expect(logStr()).toBe('error(failed)'); - - evilPromise.error('muhaha'); - evilPromise.success('take this'); - expect(logStr()).toBe('error(failed)'); - }); - }); - }); - - - describe('all', function() { - it('should resolve all of nothing', function() { - var result; - q.all([]).then(function(r) { result = r; }); - mockNextTick.flush(); - expect(result).toEqual([]); - }); - - - it('should take an array of promises and return a promise for an array of results', function() { - var deferred1 = defer(), - deferred2 = defer(); - - q.all([promise, deferred1.promise, deferred2.promise]).then(success(), error()); - expect(logStr()).toBe(''); - syncResolve(deferred, 'hi'); - expect(logStr()).toBe(''); - syncResolve(deferred2, 'cau'); - expect(logStr()).toBe(''); - syncResolve(deferred1, 'hola'); - expect(logStr()).toBe('success([hi,hola,cau])'); - }); - - - it('should reject the derived promise if at least one of the promises in the array is rejected', - function() { - var deferred1 = defer(), - deferred2 = defer(); - - q.all([promise, deferred1.promise, deferred2.promise]).then(success(), error()); - expect(logStr()).toBe(''); - syncResolve(deferred2, 'cau'); - expect(logStr()).toBe(''); - syncReject(deferred1, 'oops'); - expect(logStr()).toBe('error(oops)'); - }); - - - it('should ignore multiple resolutions of an (evil) array promise', function() { - var evilPromise = { - then: function(success, error) { - evilPromise.success = success; - evilPromise.error = error; - } - } - - q.all([promise, evilPromise]).then(success(), error()); - expect(logStr()).toBe(''); - - evilPromise.success('first'); - evilPromise.success('muhaha'); - evilPromise.error('arghhh'); - expect(logStr()).toBe(''); - - syncResolve(deferred, 'done'); - expect(logStr()).toBe('success([done,first])'); - }); - }); - - - describe('exception logging', function() { - var mockExceptionLogger = { - log: [], - logger: function(e) { - mockExceptionLogger.log.push(e); - } - } - - - beforeEach(function() { - q = qFactory(mockNextTick.nextTick, mockExceptionLogger.logger), - defer = q.defer; - deferred = defer() - promise = deferred.promise; - log = []; - mockExceptionLogger.log = []; - }); - - - describe('in then', function() { - it('should log exceptions thrown in a success callback and reject the derived promise', - function() { - var success1 = success(1, 'oops', true); - promise.then(success1).then(success(2), error(2)); - syncResolve(deferred, 'done'); - expect(logStr()).toBe('success1(done); error2(oops)'); - expect(mockExceptionLogger.log).toEqual(['oops']); - }); - - - it('should NOT log exceptions when a success callback returns rejected promise', function() { - promise.then(success(1, q.reject('rejected'))).then(success(2), error(2)); - syncResolve(deferred, 'done'); - expect(logStr()).toBe('success1(done); error2(rejected)'); - expect(mockExceptionLogger.log).toEqual([]); - }); - - - it('should log exceptions thrown in a errback and reject the derived promise', function() { - var error1 = error(1, 'oops', true); - promise.then(null, error1).then(success(2), error(2)); - syncReject(deferred, 'nope'); - expect(logStr()).toBe('error1(nope); error2(oops)'); - expect(mockExceptionLogger.log).toEqual(['oops']); - }); - - - it('should NOT log exceptions when an errback returns a rejected promise', function() { - promise.then(null, error(1, q.reject('rejected'))).then(success(2), error(2)); - syncReject(deferred, 'nope'); - expect(logStr()).toBe('error1(nope); error2(rejected)'); - expect(mockExceptionLogger.log).toEqual([]); - }); - }); - - - describe('in when', function() { - it('should log exceptions thrown in a success callback and reject the derived promise', - function() { - var success1 = success(1, 'oops', true); - q.when('hi', success1, error()).then(success(), error(2)); - mockNextTick.flush(); - expect(logStr()).toBe('success1(hi); error2(oops)'); - expect(mockExceptionLogger.log).toEqual(['oops']); - }); - - - it('should NOT log exceptions when a success callback returns rejected promise', function() { - q.when('hi', success(1, q.reject('rejected'))).then(success(2), error(2)); - mockNextTick.flush(); - expect(logStr()).toBe('success1(hi); error2(rejected)'); - expect(mockExceptionLogger.log).toEqual([]); - }); - - - it('should log exceptions thrown in a errback and reject the derived promise', function() { - var error1 = error(1, 'oops', true); - q.when(q.reject('sorry'), success(), error1).then(success(), error(2)); - mockNextTick.flush(); - expect(logStr()).toBe('error1(sorry); error2(oops)'); - expect(mockExceptionLogger.log).toEqual(['oops']); - }); - - - it('should NOT log exceptions when an errback returns a rejected promise', function() { - q.when(q.reject('sorry'), success(), error(1, q.reject('rejected'))). - then(success(2), error(2)); - mockNextTick.flush(); - expect(logStr()).toBe('error1(sorry); error2(rejected)'); - expect(mockExceptionLogger.log).toEqual([]); - }); - }); - }); -}); diff --git a/test/service/resourceSpec.js b/test/service/resourceSpec.js deleted file mode 100644 index e0049761..00000000 --- a/test/service/resourceSpec.js +++ /dev/null @@ -1,325 +0,0 @@ -'use strict'; - -describe("resource", function() { - var $resource, CreditCard, callback, $httpBackend; - - beforeEach(inject(function($injector) { - $httpBackend = $injector.get('$httpBackend'); - $resource = $injector.get('$resource'); - CreditCard = $resource('/CreditCard/:id:verb', {id:'@id.key'}, { - charge:{ - method:'POST', - params:{verb:'!charge'} - } - }); - callback = jasmine.createSpy(); - })); - - - afterEach(function() { - $httpBackend.verifyNoOutstandingExpectation(); - }); - - - it("should build resource", function() { - expect(typeof CreditCard).toBe('function'); - expect(typeof CreditCard.get).toBe('function'); - expect(typeof CreditCard.save).toBe('function'); - expect(typeof CreditCard.remove).toBe('function'); - expect(typeof CreditCard['delete']).toBe('function'); - expect(typeof CreditCard.query).toBe('function'); - }); - - - it('should default to empty parameters', function() { - $httpBackend.expect('GET', 'URL').respond({}); - $resource('URL').query(); - }); - - - it('should ignore slashes of undefinend parameters', function() { - var R = $resource('/Path/:a/:b/:c'); - - $httpBackend.when('GET').respond('{}'); - $httpBackend.expect('GET', '/Path'); - $httpBackend.expect('GET', '/Path/1'); - $httpBackend.expect('GET', '/Path/2/3'); - $httpBackend.expect('GET', '/Path/4/5/6'); - - R.get({}); - R.get({a:1}); - R.get({a:2, b:3}); - R.get({a:4, b:5, c:6}); - }); - - - it('should support escaping colons in url template', function() { - var R = $resource('http://localhost\\:8080/Path/:a/\\:stillPath/:b'); - - $httpBackend.expect('GET', 'http://localhost:8080/Path/foo/:stillPath/bar').respond(); - R.get({a: 'foo', b: 'bar'}); - }); - - - it('should correctly encode url params', function() { - var R = $resource('/Path/:a'); - - $httpBackend.expect('GET', '/Path/foo%231').respond('{}'); - $httpBackend.expect('GET', '/Path/doh!@foo?bar=baz%231').respond('{}'); - - R.get({a: 'foo#1'}); - R.get({a: 'doh!@foo', bar: 'baz#1'}); - }); - - - it('should not encode @ in url params', function() { - //encodeURIComponent is too agressive and doesn't follow http://www.ietf.org/rfc/rfc3986.txt - //with regards to the character set (pchar) allowed in path segments - //so we need this test to make sure that we don't over-encode the params and break stuff like - //buzz api which uses @self - - var R = $resource('/Path/:a'); - $httpBackend.expect('GET', '/Path/doh@fo%20o?!do%26h=g%3Da+h&:bar=$baz@1').respond('{}'); - R.get({a: 'doh@fo o', ':bar': '$baz@1', '!do&h': 'g=a h'}); - }); - - - it('should encode & in url params', function() { - var R = $resource('/Path/:a'); - $httpBackend.expect('GET', '/Path/doh&foo?bar=baz%261').respond('{}'); - R.get({a: 'doh&foo', bar: 'baz&1'}); - }); - - - it('should build resource with default param', function() { - $httpBackend.expect('GET', '/Order/123/Line/456.visa?minimum=0.05').respond({id: 'abc'}); - var LineItem = $resource('/Order/:orderId/Line/:id:verb', - {orderId: '123', id: '@id.key', verb:'.visa', minimum: 0.05}); - var item = LineItem.get({id: 456}); - $httpBackend.flush(); - expect(item).toEqualData({id:'abc'}); - }); - - - it("should build resource with action default param overriding default param", function() { - $httpBackend.expect('GET', '/Customer/123').respond({id: 'abc'}); - var TypeItem = $resource('/:type/:typeId', {type: 'Order'}, - {get: {method: 'GET', params: {type: 'Customer'}}}); - var item = TypeItem.get({typeId: 123}); - - $httpBackend.flush(); - expect(item).toEqualData({id: 'abc'}); - }); - - - it("should create resource", function() { - $httpBackend.expect('POST', '/CreditCard', '{"name":"misko"}').respond({id: 123, name: 'misko'}); - - var cc = CreditCard.save({name: 'misko'}, callback); - expect(cc).toEqualData({name: 'misko'}); - expect(callback).not.toHaveBeenCalled(); - - $httpBackend.flush(); - expect(cc).toEqualData({id: 123, name: 'misko'}); - expect(callback).toHaveBeenCalledOnce(); - expect(callback.mostRecentCall.args[0]).toEqual(cc); - expect(callback.mostRecentCall.args[1]()).toEqual({}); - }); - - - it("should read resource", function() { - $httpBackend.expect('GET', '/CreditCard/123').respond({id: 123, number: '9876'}); - var cc = CreditCard.get({id: 123}, callback); - - expect(cc instanceof CreditCard).toBeTruthy(); - expect(cc).toEqualData({}); - expect(callback).not.toHaveBeenCalled(); - - $httpBackend.flush(); - expect(cc).toEqualData({id: 123, number: '9876'}); - expect(callback.mostRecentCall.args[0]).toEqual(cc); - expect(callback.mostRecentCall.args[1]()).toEqual({}); - }); - - - it("should read partial resource", function() { - $httpBackend.expect('GET', '/CreditCard').respond([{id:{key:123}}]); - var ccs = CreditCard.query(); - - $httpBackend.flush(); - expect(ccs.length).toEqual(1); - - var cc = ccs[0]; - expect(cc instanceof CreditCard).toBe(true); - expect(cc.number).toBeUndefined(); - - $httpBackend.expect('GET', '/CreditCard/123').respond({id: {key: 123}, number: '9876'}); - cc.$get(callback); - $httpBackend.flush(); - expect(callback.mostRecentCall.args[0]).toEqual(cc); - expect(callback.mostRecentCall.args[1]()).toEqual({}); - expect(cc.number).toEqual('9876'); - }); - - - it("should update resource", function() { - $httpBackend.expect('POST', '/CreditCard/123', '{"id":{"key":123},"name":"misko"}'). - respond({id: {key: 123}, name: 'rama'}); - - var cc = CreditCard.save({id: {key: 123}, name: 'misko'}, callback); - expect(cc).toEqualData({id:{key:123}, name:'misko'}); - expect(callback).not.toHaveBeenCalled(); - $httpBackend.flush(); - }); - - - it("should query resource", function() { - $httpBackend.expect('GET', '/CreditCard?key=value').respond([{id: 1}, {id: 2}]); - - var ccs = CreditCard.query({key: 'value'}, callback); - expect(ccs).toEqual([]); - expect(callback).not.toHaveBeenCalled(); - - $httpBackend.flush(); - expect(ccs).toEqualData([{id:1}, {id:2}]); - expect(callback.mostRecentCall.args[0]).toEqual(ccs); - expect(callback.mostRecentCall.args[1]()).toEqual({}); - }); - - - it("should have all arguments optional", function() { - $httpBackend.expect('GET', '/CreditCard').respond([{id:1}]); - - var log = ''; - var ccs = CreditCard.query(function() { log += 'cb;'; }); - - $httpBackend.flush(); - expect(ccs).toEqualData([{id:1}]); - expect(log).toEqual('cb;'); - }); - - - it('should delete resource and call callback', function() { - $httpBackend.expect('DELETE', '/CreditCard/123').respond({}); - CreditCard.remove({id:123}, callback); - expect(callback).not.toHaveBeenCalled(); - - $httpBackend.flush(); - expect(callback.mostRecentCall.args[0]).toEqualData({}); - expect(callback.mostRecentCall.args[1]()).toEqual({}); - - callback.reset(); - $httpBackend.expect('DELETE', '/CreditCard/333').respond(204, null); - CreditCard.remove({id:333}, callback); - expect(callback).not.toHaveBeenCalled(); - - $httpBackend.flush(); - expect(callback.mostRecentCall.args[0]).toEqualData({}); - expect(callback.mostRecentCall.args[1]()).toEqual({}); - }); - - - it('should post charge verb', function() { - $httpBackend.expect('POST', '/CreditCard/123!charge?amount=10', '{"auth":"abc"}').respond({success: 'ok'}); - CreditCard.charge({id:123, amount:10}, {auth:'abc'}, callback); - }); - - - it('should post charge verb on instance', function() { - $httpBackend.expect('POST', '/CreditCard/123!charge?amount=10', - '{"id":{"key":123},"name":"misko"}').respond({success: 'ok'}); - - var card = new CreditCard({id:{key:123}, name:'misko'}); - card.$charge({amount:10}, callback); - }); - - - it('should create on save', function() { - $httpBackend.expect('POST', '/CreditCard', '{"name":"misko"}').respond({id: 123}, {header1: 'a'}); - - var cc = new CreditCard(); - expect(cc.$get).toBeDefined(); - expect(cc.$query).toBeDefined(); - expect(cc.$remove).toBeDefined(); - expect(cc.$save).toBeDefined(); - - cc.name = 'misko'; - cc.$save(callback); - expect(cc).toEqualData({name:'misko'}); - - $httpBackend.flush(); - expect(cc).toEqualData({id:123}); - expect(callback.mostRecentCall.args[0]).toEqual(cc); - expect(callback.mostRecentCall.args[1]()).toEqual({header1: 'a'}); - }); - - - it('should not mutate the resource object if response contains no body', function() { - var data = {id:{key:123}, number:'9876'}; - $httpBackend.expect('GET', '/CreditCard/123').respond(data); - - var cc = CreditCard.get({id:123}); - $httpBackend.flush(); - expect(cc instanceof CreditCard).toBe(true); - - $httpBackend.expect('POST', '/CreditCard/123', toJson(data)).respond(''); - var idBefore = cc.id; - - cc.$save(); - $httpBackend.flush(); - expect(idBefore).toEqual(cc.id); - }); - - - it('should bind default parameters', function() { - $httpBackend.expect('GET', '/CreditCard/123.visa?minimum=0.05').respond({id: 123}); - var Visa = CreditCard.bind({verb:'.visa', minimum:0.05}); - var visa = Visa.get({id:123}); - $httpBackend.flush(); - expect(visa).toEqualData({id:123}); - }); - - - it('should exercise full stack', function() { - var Person = $resource('/Person/:id'); - - $httpBackend.expect('GET', '/Person/123').respond('\n{\n"name":\n"misko"\n}\n'); - var person = Person.get({id:123}); - $httpBackend.flush(); - expect(person.name).toEqual('misko'); - }); - - - describe('failure mode', function() { - var ERROR_CODE = 500, - ERROR_RESPONSE = 'Server Error', - errorCB; - - beforeEach(function() { - errorCB = jasmine.createSpy('error').andCallFake(function(response) { - expect(response.data).toBe(ERROR_RESPONSE); - expect(response.status).toBe(ERROR_CODE); - }); - }); - - - it('should call the error callback if provided on non 2xx response', function() { - $httpBackend.expect('GET', '/CreditCard/123').respond(ERROR_CODE, ERROR_RESPONSE); - - CreditCard.get({id:123}, callback, errorCB); - $httpBackend.flush(); - expect(errorCB).toHaveBeenCalledOnce(); - expect(callback).not.toHaveBeenCalled(); - }); - - - it('should call the error callback if provided on non 2xx response', function() { - $httpBackend.expect('GET', '/CreditCard').respond(ERROR_CODE, ERROR_RESPONSE); - - CreditCard.get(callback, errorCB); - $httpBackend.flush(); - expect(errorCB).toHaveBeenCalledOnce(); - expect(callback).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/test/service/routeParamsSpec.js b/test/service/routeParamsSpec.js deleted file mode 100644 index d1b2ecb1..00000000 --- a/test/service/routeParamsSpec.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -describe('$routeParams', function() { - it('should publish the params into a service', function() { - module(function($routeProvider) { - $routeProvider.when('/foo'); - $routeProvider.when('/bar/:barId'); - }); - - inject(function($rootScope, $route, $location, $routeParams) { - $location.path('/foo').search('a=b'); - $rootScope.$digest(); - expect($routeParams).toEqual({a:'b'}); - - $location.path('/bar/123').search('x=abc'); - $rootScope.$digest(); - expect($routeParams).toEqual({barId:'123', x:'abc'}); - }); - }); -}); diff --git a/test/service/routeSpec.js b/test/service/routeSpec.js deleted file mode 100644 index 88e54b9a..00000000 --- a/test/service/routeSpec.js +++ /dev/null @@ -1,471 +0,0 @@ -'use strict'; - -describe('$route', function() { - - it('should route and fire change event', function() { - var log = '', - lastRoute, - nextRoute; - - module(function($routeProvider) { - $routeProvider.when('/Book/:book/Chapter/:chapter', - {controller: noop, template: 'Chapter.html'}); - $routeProvider.when('/Blank'); - }); - inject(function($route, $location, $rootScope) { - $rootScope.$on('$beforeRouteChange', function(event, next, current) { - log += 'before();'; - expect(current).toBe($route.current); - lastRoute = current; - nextRoute = next; - }); - $rootScope.$on('$afterRouteChange', function(event, current, last) { - log += 'after();'; - expect(current).toBe($route.current); - expect(lastRoute).toBe(last); - expect(nextRoute).toBe(current); - }); - - $location.path('/Book/Moby/Chapter/Intro').search('p=123'); - $rootScope.$digest(); - expect(log).toEqual('before();after();'); - expect($route.current.params).toEqual({book:'Moby', chapter:'Intro', p:'123'}); - - log = ''; - $location.path('/Blank').search('ignore'); - $rootScope.$digest(); - expect(log).toEqual('before();after();'); - expect($route.current.params).toEqual({ignore:true}); - - log = ''; - $location.path('/NONE'); - $rootScope.$digest(); - expect(log).toEqual('before();after();'); - expect($route.current).toEqual(null); - }); - }); - - - it('should match a route that contains special chars in the path', function() { - module(function($routeProvider) { - $routeProvider.when('/$test.23/foo(bar)/:baz', {template: 'test.html'}); - }); - inject(function($route, $location, $rootScope) { - - $location.path('/test'); - $rootScope.$digest(); - expect($route.current).toBeUndefined(); - - $location.path('/$testX23/foo(bar)/222'); - $rootScope.$digest(); - expect($route.current).toBeUndefined(); - - $location.path('/$test.23/foo(bar)/222'); - $rootScope.$digest(); - expect($route.current).toBeDefined(); - - $location.path('/$test.23/foo\\(bar)/222'); - $rootScope.$digest(); - expect($route.current).toBeUndefined(); - }); - }); - - - it('should change route even when only search param changes', function() { - module(function($routeProvider) { - $routeProvider.when('/test', {template: 'test.html'}); - }); - - inject(function($route, $location, $rootScope) { - var callback = jasmine.createSpy('onRouteChange'); - - $rootScope.$on('$beforeRouteChange', callback); - $location.path('/test'); - $rootScope.$digest(); - callback.reset(); - - $location.search({any: true}); - $rootScope.$digest(); - - expect(callback).toHaveBeenCalled(); - }); - }); - - - it('should allow routes to be defined with just templates without controllers', function() { - module(function($routeProvider) { - $routeProvider.when('/foo', {template: 'foo.html'}); - }); - - inject(function($route, $location, $rootScope) { - var onChangeSpy = jasmine.createSpy('onChange'); - - $rootScope.$on('$beforeRouteChange', onChangeSpy); - expect($route.current).toBeUndefined(); - expect(onChangeSpy).not.toHaveBeenCalled(); - - $location.path('/foo'); - $rootScope.$digest(); - - expect($route.current.template).toEqual('foo.html'); - expect($route.current.controller).toBeUndefined(); - expect(onChangeSpy).toHaveBeenCalled(); - }); - }); - - - it('should handle unknown routes with "otherwise" route definition', function() { - function NotFoundCtrl() {} - - module(function($routeProvider){ - $routeProvider.when('/foo', {template: 'foo.html'}); - $routeProvider.otherwise({template: '404.html', controller: NotFoundCtrl}); - }); - - inject(function($route, $location, $rootScope) { - var onChangeSpy = jasmine.createSpy('onChange'); - - $rootScope.$on('$beforeRouteChange', onChangeSpy); - expect($route.current).toBeUndefined(); - expect(onChangeSpy).not.toHaveBeenCalled(); - - $location.path('/unknownRoute'); - $rootScope.$digest(); - - expect($route.current.template).toBe('404.html'); - expect($route.current.controller).toBe(NotFoundCtrl); - expect(onChangeSpy).toHaveBeenCalled(); - - onChangeSpy.reset(); - $location.path('/foo'); - $rootScope.$digest(); - - expect($route.current.template).toEqual('foo.html'); - expect($route.current.controller).toBeUndefined(); - expect(onChangeSpy).toHaveBeenCalled(); - }); - }); - - - it('should not fire $after/beforeRouteChange during bootstrap (if no route)', function() { - var routeChangeSpy = jasmine.createSpy('route change'); - - module(function($routeProvider) { - $routeProvider.when('/one', {}); // no otherwise defined - }); - - inject(function($rootScope, $route, $location) { - $rootScope.$on('$beforeRouteChange', routeChangeSpy); - $rootScope.$on('$afterRouteChange', routeChangeSpy); - - $rootScope.$digest(); - expect(routeChangeSpy).not.toHaveBeenCalled(); - - $location.path('/no-route-here'); - $rootScope.$digest(); - expect(routeChangeSpy).not.toHaveBeenCalled(); - }); - }); - - - it('should match route with and without trailing slash', function() { - module(function($routeProvider){ - $routeProvider.when('/foo', {template: 'foo.html'}); - $routeProvider.when('/bar/', {template: 'bar.html'}); - }); - - inject(function($route, $location, $rootScope) { - $location.path('/foo'); - $rootScope.$digest(); - expect($location.path()).toBe('/foo'); - expect($route.current.template).toBe('foo.html'); - - $location.path('/foo/'); - $rootScope.$digest(); - expect($location.path()).toBe('/foo'); - expect($route.current.template).toBe('foo.html'); - - $location.path('/bar'); - $rootScope.$digest(); - expect($location.path()).toBe('/bar/'); - expect($route.current.template).toBe('bar.html'); - - $location.path('/bar/'); - $rootScope.$digest(); - expect($location.path()).toBe('/bar/'); - expect($route.current.template).toBe('bar.html'); - }); - }); - - - describe('redirection', function() { - it('should support redirection via redirectTo property by updating $location', function() { - module(function($routeProvider) { - $routeProvider.when('/', {redirectTo: '/foo'}); - $routeProvider.when('/foo', {template: 'foo.html'}); - $routeProvider.when('/bar', {template: 'bar.html'}); - $routeProvider.when('/baz', {redirectTo: '/bar'}); - $routeProvider.otherwise({template: '404.html'}); - }); - - inject(function($route, $location, $rootScope) { - var onChangeSpy = jasmine.createSpy('onChange'); - - $rootScope.$on('$beforeRouteChange', onChangeSpy); - expect($route.current).toBeUndefined(); - expect(onChangeSpy).not.toHaveBeenCalled(); - - $location.path('/'); - $rootScope.$digest(); - expect($location.path()).toBe('/foo'); - expect($route.current.template).toBe('foo.html'); - expect(onChangeSpy.callCount).toBe(2); - - onChangeSpy.reset(); - $location.path('/baz'); - $rootScope.$digest(); - expect($location.path()).toBe('/bar'); - expect($route.current.template).toBe('bar.html'); - expect(onChangeSpy.callCount).toBe(2); - }); - }); - - - it('should interpolate route vars in the redirected path from original path', function() { - module(function($routeProvider) { - $routeProvider.when('/foo/:id/foo/:subid/:extraId', {redirectTo: '/bar/:id/:subid/23'}); - $routeProvider.when('/bar/:id/:subid/:subsubid', {template: 'bar.html'}); - }); - - inject(function($route, $location, $rootScope) { - $location.path('/foo/id1/foo/subid3/gah'); - $rootScope.$digest(); - - expect($location.path()).toEqual('/bar/id1/subid3/23'); - expect($location.search()).toEqual({extraId: 'gah'}); - expect($route.current.template).toEqual('bar.html'); - }); - }); - - - it('should interpolate route vars in the redirected path from original search', function() { - module(function($routeProvider) { - $routeProvider.when('/bar/:id/:subid/:subsubid', {template: 'bar.html'}); - $routeProvider.when('/foo/:id/:extra', {redirectTo: '/bar/:id/:subid/99'}); - }); - - inject(function($route, $location, $rootScope) { - $location.path('/foo/id3/eId').search('subid=sid1&appended=true'); - $rootScope.$digest(); - - expect($location.path()).toEqual('/bar/id3/sid1/99'); - expect($location.search()).toEqual({appended: 'true', extra: 'eId'}); - expect($route.current.template).toEqual('bar.html'); - }); - }); - - - it('should allow custom redirectTo function to be used', function() { - function customRedirectFn(routePathParams, path, search) { - expect(routePathParams).toEqual({id: 'id3'}); - expect(path).toEqual('/foo/id3'); - expect(search).toEqual({ subid: 'sid1', appended: 'true' }); - return '/custom'; - } - - module(function($routeProvider){ - $routeProvider.when('/bar/:id/:subid/:subsubid', {template: 'bar.html'}); - $routeProvider.when('/foo/:id', {redirectTo: customRedirectFn}); - }); - - inject(function($route, $location, $rootScope) { - $location.path('/foo/id3').search('subid=sid1&appended=true'); - $rootScope.$digest(); - - expect($location.path()).toEqual('/custom'); - }); - }); - - - it('should replace the url when redirecting', function() { - module(function($routeProvider) { - $routeProvider.when('/bar/:id', {template: 'bar.html'}); - $routeProvider.when('/foo/:id/:extra', {redirectTo: '/bar/:id'}); - }); - inject(function($route, $location, $rootScope) { - var replace; - $rootScope.$watch(function() { - if (isUndefined(replace)) replace = $location.$$replace; - }); - - $location.path('/foo/id3/eId'); - $rootScope.$digest(); - - expect($location.path()).toEqual('/bar/id3'); - expect(replace).toBe(true); - }); - }); - }); - - - describe('reloadOnSearch', function() { - it('should reload a route when reloadOnSearch is enabled and .search() changes', function() { - var reloaded = jasmine.createSpy('route reload'); - - module(function($routeProvider) { - $routeProvider.when('/foo', {controller: noop}); - }); - - inject(function($route, $location, $rootScope, $routeParams) { - $rootScope.$on('$beforeRouteChange', reloaded); - $location.path('/foo'); - $rootScope.$digest(); - expect(reloaded).toHaveBeenCalled(); - expect($routeParams).toEqual({}); - reloaded.reset(); - - // trigger reload - $location.search({foo: 'bar'}); - $rootScope.$digest(); - expect(reloaded).toHaveBeenCalled(); - expect($routeParams).toEqual({foo:'bar'}); - }); - }); - - - it('should not reload a route when reloadOnSearch is disabled and only .search() changes', function() { - var routeChange = jasmine.createSpy('route change'), - routeUpdate = jasmine.createSpy('route update'); - - module(function($routeProvider) { - $routeProvider.when('/foo', {controller: noop, reloadOnSearch: false}); - }); - - inject(function($route, $location, $rootScope) { - $rootScope.$on('$beforeRouteChange', routeChange); - $rootScope.$on('$afterRouteChange', routeChange); - $rootScope.$on('$routeUpdate', routeUpdate); - - expect(routeChange).not.toHaveBeenCalled(); - - $location.path('/foo'); - $rootScope.$digest(); - expect(routeChange).toHaveBeenCalled(); - expect(routeChange.callCount).toBe(2); - expect(routeUpdate).not.toHaveBeenCalled(); - routeChange.reset(); - - // don't trigger reload - $location.search({foo: 'bar'}); - $rootScope.$digest(); - expect(routeChange).not.toHaveBeenCalled(); - expect(routeUpdate).toHaveBeenCalled(); - }); - }); - - - it('should reload reloadOnSearch route when url differs only in route path param', function() { - var routeChange = jasmine.createSpy('route change'); - - module(function($routeProvider) { - $routeProvider.when('/foo/:fooId', {controller: noop, reloadOnSearch: false}); - }); - - inject(function($route, $location, $rootScope) { - $rootScope.$on('$beforeRouteChange', routeChange); - $rootScope.$on('$afterRouteChange', routeChange); - - expect(routeChange).not.toHaveBeenCalled(); - - $location.path('/foo/aaa'); - $rootScope.$digest(); - expect(routeChange).toHaveBeenCalled(); - expect(routeChange.callCount).toBe(2); - routeChange.reset(); - - $location.path('/foo/bbb'); - $rootScope.$digest(); - expect(routeChange).toHaveBeenCalled(); - expect(routeChange.callCount).toBe(2); - routeChange.reset(); - - $location.search({foo: 'bar'}); - $rootScope.$digest(); - expect(routeChange).not.toHaveBeenCalled(); - }); - }); - - - it('should update params when reloadOnSearch is disabled and .search() changes', function() { - var routeParamsWatcher = jasmine.createSpy('routeParamsWatcher'); - - module(function($routeProvider) { - $routeProvider.when('/foo', {controller: noop}); - $routeProvider.when('/bar/:barId', {controller: noop, reloadOnSearch: false}); - }); - - inject(function($route, $location, $rootScope, $routeParams) { - $rootScope.$watch(function() { - return $routeParams; - }, function(value) { - routeParamsWatcher(value); - }, true); - - expect(routeParamsWatcher).not.toHaveBeenCalled(); - - $location.path('/foo'); - $rootScope.$digest(); - expect(routeParamsWatcher).toHaveBeenCalledWith({}); - routeParamsWatcher.reset(); - - // trigger reload - $location.search({foo: 'bar'}); - $rootScope.$digest(); - expect(routeParamsWatcher).toHaveBeenCalledWith({foo: 'bar'}); - routeParamsWatcher.reset(); - - $location.path('/bar/123').search({}); - $rootScope.$digest(); - expect(routeParamsWatcher).toHaveBeenCalledWith({barId: '123'}); - routeParamsWatcher.reset(); - - // don't trigger reload - $location.search({foo: 'bar'}); - $rootScope.$digest(); - expect(routeParamsWatcher).toHaveBeenCalledWith({barId: '123', foo: 'bar'}); - }); - }); - - - describe('reload', function() { - - it('should reload even if reloadOnSearch is false', function() { - var routeChangeSpy = jasmine.createSpy('route change'); - - module(function($routeProvider) { - $routeProvider.when('/bar/:barId', {controller: noop, reloadOnSearch: false}); - }); - - inject(function($route, $location, $rootScope, $routeParams) { - $rootScope.$on('$afterRouteChange', routeChangeSpy); - - $location.path('/bar/123'); - $rootScope.$digest(); - expect($routeParams).toEqual({barId:'123'}); - expect(routeChangeSpy).toHaveBeenCalledOnce(); - routeChangeSpy.reset(); - - $location.path('/bar/123').search('a=b'); - $rootScope.$digest(); - expect($routeParams).toEqual({barId:'123', a:'b'}); - expect(routeChangeSpy).not.toHaveBeenCalled(); - - $route.reload(); - $rootScope.$digest(); - expect($routeParams).toEqual({barId:'123', a:'b'}); - expect(routeChangeSpy).toHaveBeenCalledOnce(); - }); - }); - }); - }); -}); diff --git a/test/service/scopeSpec.js b/test/service/scopeSpec.js deleted file mode 100644 index 35be7a2f..00000000 --- a/test/service/scopeSpec.js +++ /dev/null @@ -1,838 +0,0 @@ -'use strict'; - -describe('Scope', function() { - - beforeEach(module(provideLog)); - - - describe('$root', function() { - it('should point to itself', inject(function($rootScope) { - expect($rootScope.$root).toEqual($rootScope); - expect($rootScope.hasOwnProperty('$root')).toBeTruthy(); - })); - - - it('should not have $root on children, but should inherit', inject(function($rootScope) { - var child = $rootScope.$new(); - expect(child.$root).toEqual($rootScope); - expect(child.hasOwnProperty('$root')).toBeFalsy(); - })); - - }); - - - describe('$parent', function() { - it('should point to itself in root', inject(function($rootScope) { - expect($rootScope.$root).toEqual($rootScope); - })); - - - it('should point to parent', inject(function($rootScope) { - var child = $rootScope.$new(); - expect($rootScope.$parent).toEqual(null); - expect(child.$parent).toEqual($rootScope); - expect(child.$new().$parent).toEqual(child); - })); - }); - - - describe('$id', function() { - it('should have a unique id', inject(function($rootScope) { - expect($rootScope.$id < $rootScope.$new().$id).toBeTruthy(); - })); - }); - - - describe('this', function() { - it('should have a \'this\'', inject(function($rootScope) { - expect($rootScope['this']).toEqual($rootScope); - })); - }); - - - describe('$new()', function() { - it('should create a child scope', inject(function($rootScope) { - var child = $rootScope.$new(); - $rootScope.a = 123; - expect(child.a).toEqual(123); - })); - - it('should create a non prototypically inherited child scope', inject(function($rootScope) { - var child = $rootScope.$new(true); - $rootScope.a = 123; - expect(child.a).toBeUndefined(); - expect(child.$parent).toEqual($rootScope); - expect(child.$new).toBe($rootScope.$new); - expect(child.$root).toBe($rootScope); - })); - }); - - - describe('$watch/$digest', function() { - it('should watch and fire on simple property change', inject(function($rootScope) { - var spy = jasmine.createSpy(); - $rootScope.$watch('name', spy); - $rootScope.$digest(); - spy.reset(); - - expect(spy).not.wasCalled(); - $rootScope.$digest(); - expect(spy).not.wasCalled(); - $rootScope.name = 'misko'; - $rootScope.$digest(); - expect(spy).wasCalledWith('misko', undefined, $rootScope); - })); - - - it('should watch and fire on expression change', inject(function($rootScope) { - var spy = jasmine.createSpy(); - $rootScope.$watch('name.first', spy); - $rootScope.$digest(); - spy.reset(); - - $rootScope.name = {}; - expect(spy).not.wasCalled(); - $rootScope.$digest(); - expect(spy).not.wasCalled(); - $rootScope.name.first = 'misko'; - $rootScope.$digest(); - expect(spy).wasCalled(); - })); - - - it('should delegate exceptions', function() { - module(function($exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - }); - inject(function($rootScope, $exceptionHandler, $log) { - $rootScope.$watch('a', function() {throw new Error('abc');}); - $rootScope.a = 1; - $rootScope.$digest(); - expect($exceptionHandler.errors[0].message).toEqual('abc'); - $log.assertEmpty(); - }); - }); - - - it('should fire watches in order of addition', inject(function($rootScope) { - // this is not an external guarantee, just our own sanity - var log = ''; - $rootScope.$watch('a', function() { log += 'a'; }); - $rootScope.$watch('b', function() { log += 'b'; }); - $rootScope.$watch('c', function() { log += 'c'; }); - $rootScope.a = $rootScope.b = $rootScope.c = 1; - $rootScope.$digest(); - expect(log).toEqual('abc'); - })); - - - it('should call child $watchers in addition order', inject(function($rootScope) { - // this is not an external guarantee, just our own sanity - var log = ''; - var childA = $rootScope.$new(); - var childB = $rootScope.$new(); - var childC = $rootScope.$new(); - childA.$watch('a', function() { log += 'a'; }); - childB.$watch('b', function() { log += 'b'; }); - childC.$watch('c', function() { log += 'c'; }); - childA.a = childB.b = childC.c = 1; - $rootScope.$digest(); - expect(log).toEqual('abc'); - })); - - - it('should allow $digest on a child scope with and without a right sibling', inject( - function($rootScope) { - // tests a traversal edge case which we originally missed - var log = '', - childA = $rootScope.$new(), - childB = $rootScope.$new(); - - $rootScope.$watch(function() { log += 'r'; }); - childA.$watch(function() { log += 'a'; }); - childB.$watch(function() { log += 'b'; }); - - // init - $rootScope.$digest(); - expect(log).toBe('rabrab'); - - log = ''; - childA.$digest(); - expect(log).toBe('a'); - - log = ''; - childB.$digest(); - expect(log).toBe('b'); - })); - - - it('should repeat watch cycle while model changes are identified', inject(function($rootScope) { - var log = ''; - $rootScope.$watch('c', function(v) {$rootScope.d = v; log+='c'; }); - $rootScope.$watch('b', function(v) {$rootScope.c = v; log+='b'; }); - $rootScope.$watch('a', function(v) {$rootScope.b = v; log+='a'; }); - $rootScope.$digest(); - log = ''; - $rootScope.a = 1; - $rootScope.$digest(); - expect($rootScope.b).toEqual(1); - expect($rootScope.c).toEqual(1); - expect($rootScope.d).toEqual(1); - expect(log).toEqual('abc'); - })); - - - it('should repeat watch cycle from the root elemnt', inject(function($rootScope) { - var log = ''; - var child = $rootScope.$new(); - $rootScope.$watch(function() { log += 'a'; }); - child.$watch(function() { log += 'b'; }); - $rootScope.$digest(); - expect(log).toEqual('abab'); - })); - - - it('should prevent infinite recursion and print watcher expression',function() { - module(function($rootScopeProvider) { - $rootScopeProvider.digestTtl(100); - }); - inject(function($rootScope) { - $rootScope.$watch('a', function() {$rootScope.b++;}); - $rootScope.$watch('b', function() {$rootScope.a++;}); - $rootScope.a = $rootScope.b = 0; - - expect(function() { - $rootScope.$digest(); - }).toThrow('100 $digest() iterations reached. Aborting!\n'+ - 'Watchers fired in the last 5 iterations: ' + - '[["a; newVal: 96; oldVal: 95","b; newVal: 97; oldVal: 96"],' + - '["a; newVal: 97; oldVal: 96","b; newVal: 98; oldVal: 97"],' + - '["a; newVal: 98; oldVal: 97","b; newVal: 99; oldVal: 98"],' + - '["a; newVal: 99; oldVal: 98","b; newVal: 100; oldVal: 99"],' + - '["a; newVal: 100; oldVal: 99","b; newVal: 101; oldVal: 100"]]'); - }); - }); - - - it('should prevent infinite recursion and print print watcher function name or body', - inject(function($rootScope) { - $rootScope.$watch(function watcherA() {return $rootScope.a;}, function() {$rootScope.b++;}); - $rootScope.$watch(function() {return $rootScope.b;}, function() {$rootScope.a++;}); - $rootScope.a = $rootScope.b = 0; - - try { - $rootScope.$digest(); - throw Error('Should have thrown exception'); - } catch(e) { - expect(e.message.match(/"fn: (watcherA|function)/g).length).toBe(10); - } - })); - - - it('should not fire upon $watch registration on initial $digest', inject(function($rootScope) { - var log = ''; - $rootScope.a = 1; - $rootScope.$watch('a', function() { log += 'a'; }); - $rootScope.$watch('b', function() { log += 'b'; }); - $rootScope.$digest(); - log = ''; - $rootScope.$digest(); - expect(log).toEqual(''); - })); - - - it('should watch objects', inject(function($rootScope) { - var log = ''; - $rootScope.a = []; - $rootScope.b = {}; - $rootScope.$watch('a', function(value) { - log +='.'; - expect(value).toBe($rootScope.a); - }, true); - $rootScope.$watch('b', function(value) { - log +='!'; - expect(value).toBe($rootScope.b); - }, true); - $rootScope.$digest(); - log = ''; - - $rootScope.a.push({}); - $rootScope.b.name = ''; - - $rootScope.$digest(); - expect(log).toEqual('.!'); - })); - - - it('should watch functions', function() { - module(provideLog); - inject(function($rootScope, log) { - $rootScope.fn = function() {return 'a'}; - $rootScope.$watch('fn', function(fn) { - log(fn()); - }); - $rootScope.$digest(); - expect(log).toEqual('a'); - $rootScope.fn = function() {return 'b'}; - $rootScope.$digest(); - expect(log).toEqual('a; b'); - }) - }); - - - it('should prevent $digest recursion', inject(function($rootScope) { - var callCount = 0; - $rootScope.$watch('name', function() { - expect(function() { - $rootScope.$digest(); - }).toThrow('$digest already in progress'); - callCount++; - }); - $rootScope.name = 'a'; - $rootScope.$digest(); - expect(callCount).toEqual(1); - })); - - - it('should return a function that allows listeners to be unregistered', inject( - function($rootScope) { - var listener = jasmine.createSpy('watch listener'), - listenerRemove; - - listenerRemove = $rootScope.$watch('foo', listener); - $rootScope.$digest(); //init - expect(listener).toHaveBeenCalled(); - expect(listenerRemove).toBeDefined(); - - listener.reset(); - $rootScope.foo = 'bar'; - $rootScope.$digest(); //triger - expect(listener).toHaveBeenCalledOnce(); - - listener.reset(); - $rootScope.foo = 'baz'; - listenerRemove(); - $rootScope.$digest(); //trigger - expect(listener).not.toHaveBeenCalled(); - })); - - - it('should not infinitely digest when current value is NaN', inject(function($rootScope) { - $rootScope.$watch(function() { return NaN;}); - - expect(function() { - $rootScope.$digest(); - }).not.toThrow(); - })); - - - it('should always call the watchr with newVal and oldVal equal on the first run', - inject(function($rootScope) { - var log = []; - function logger(scope, newVal, oldVal) { - var val = (newVal === oldVal || (newVal !== oldVal && oldVal !== newVal)) ? newVal : 'xxx'; - log.push(val); - } - - $rootScope.$watch(function() { return NaN;}, logger); - $rootScope.$watch(function() { return undefined;}, logger); - $rootScope.$watch(function() { return '';}, logger); - $rootScope.$watch(function() { return false;}, logger); - $rootScope.$watch(function() { return {};}, logger, true); - $rootScope.$watch(function() { return 23;}, logger); - - $rootScope.$digest(); - expect(isNaN(log.shift())).toBe(true); //jasmine's toBe and toEqual don't work well with NaNs - expect(log).toEqual([undefined, '', false, {}, 23]); - log = []; - $rootScope.$digest(); - expect(log).toEqual([]); - })); - }); - - - describe('$destroy', function() { - var first = null, middle = null, last = null, log = null; - - beforeEach(inject(function($rootScope) { - log = ''; - - first = $rootScope.$new(); - middle = $rootScope.$new(); - last = $rootScope.$new(); - - first.$watch(function() { log += '1';}); - middle.$watch(function() { log += '2';}); - last.$watch(function() { log += '3';}); - - $rootScope.$digest(); - log = ''; - })); - - - it('should ignore remove on root', inject(function($rootScope) { - $rootScope.$destroy(); - $rootScope.$digest(); - expect(log).toEqual('123'); - })); - - - it('should remove first', inject(function($rootScope) { - first.$destroy(); - $rootScope.$digest(); - expect(log).toEqual('23'); - })); - - - it('should remove middle', inject(function($rootScope) { - middle.$destroy(); - $rootScope.$digest(); - expect(log).toEqual('13'); - })); - - - it('should remove last', inject(function($rootScope) { - last.$destroy(); - $rootScope.$digest(); - expect(log).toEqual('12'); - })); - - - it('should broadcast the $destroy event', inject(function($rootScope, log) { - first.$on('$destroy', log.fn('first')); - first.$new().$on('$destroy', log.fn('first-child')); - - first.$destroy(); - expect(log).toEqual('first; first-child'); - })); - }); - - - describe('$eval', function() { - it('should eval an expression', inject(function($rootScope) { - expect($rootScope.$eval('a=1')).toEqual(1); - expect($rootScope.a).toEqual(1); - - $rootScope.$eval(function(self) {self.b=2;}); - expect($rootScope.b).toEqual(2); - })); - - - it('should allow passing locals to the expression', inject(function($rootScope) { - expect($rootScope.$eval('a+1', {a: 2})).toBe(3); - - $rootScope.$eval(function(scope, locals) { - scope.c = locals.b + 4; - }, {b: 3}); - expect($rootScope.c).toBe(7); - })); - }); - - - describe('$evalAsync', function() { - - it('should run callback before $watch', inject(function($rootScope) { - var log = ''; - var child = $rootScope.$new(); - $rootScope.$evalAsync(function(scope) { log += 'parent.async;'; }); - $rootScope.$watch('value', function() { log += 'parent.$digest;'; }); - child.$evalAsync(function(scope) { log += 'child.async;'; }); - child.$watch('value', function() { log += 'child.$digest;'; }); - $rootScope.$digest(); - expect(log).toEqual('parent.async;parent.$digest;child.async;child.$digest;'); - })); - - it('should cause a $digest rerun', inject(function($rootScope) { - $rootScope.log = ''; - $rootScope.value = 0; - $rootScope.$watch('value', 'log = log + ".";'); - $rootScope.$watch('init', function() { - $rootScope.$evalAsync('value = 123; log = log + "=" '); - expect($rootScope.value).toEqual(0); - }); - $rootScope.$digest(); - expect($rootScope.log).toEqual('.=.'); - })); - - it('should run async in the same order as added', inject(function($rootScope) { - $rootScope.log = ''; - $rootScope.$evalAsync("log = log + 1"); - $rootScope.$evalAsync("log = log + 2"); - $rootScope.$digest(); - expect($rootScope.log).toBe('12'); - })); - - }); - - - describe('$apply', function() { - it('should apply expression with full lifecycle', inject(function($rootScope) { - var log = ''; - var child = $rootScope.$new(); - $rootScope.$watch('a', function(a) { log += '1'; }); - child.$apply('$parent.a=0'); - expect(log).toEqual('1'); - })); - - - it('should catch exceptions', function() { - module(function($exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - }); - inject(function($rootScope, $exceptionHandler, $log) { - var log = ''; - var child = $rootScope.$new(); - $rootScope.$watch('a', function(a) { log += '1'; }); - $rootScope.a = 0; - child.$apply(function() { throw new Error('MyError'); }); - expect(log).toEqual('1'); - expect($exceptionHandler.errors[0].message).toEqual('MyError'); - $log.error.logs.shift(); - }); - }); - - - describe('exceptions', function() { - var log; - beforeEach(module(function($exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - })); - beforeEach(inject(function($rootScope) { - log = ''; - $rootScope.$watch(function() { log += '$digest;'; }); - $rootScope.$digest(); - log = ''; - })); - - - it('should execute and return value and update', inject( - function($rootScope, $exceptionHandler) { - $rootScope.name = 'abc'; - expect($rootScope.$apply(function(scope) { - return scope.name; - })).toEqual('abc'); - expect(log).toEqual('$digest;'); - expect($exceptionHandler.errors).toEqual([]); - })); - - - it('should catch exception and update', inject(function($rootScope, $exceptionHandler) { - var error = new Error('MyError'); - $rootScope.$apply(function() { throw error; }); - expect(log).toEqual('$digest;'); - expect($exceptionHandler.errors).toEqual([error]); - })); - }); - - - describe('recursive $apply protection', function() { - it('should throw an exception if $apply is called while an $apply is in progress', inject( - function($rootScope) { - expect(function() { - $rootScope.$apply(function() { - $rootScope.$apply(); - }); - }).toThrow('$apply already in progress'); - })); - - - it('should throw an exception if $apply is called while flushing evalAsync queue', inject( - function($rootScope) { - expect(function() { - $rootScope.$apply(function() { - $rootScope.$evalAsync(function() { - $rootScope.$apply(); - }); - }); - }).toThrow('$digest already in progress'); - })); - - - it('should throw an exception if $apply is called while a watch is being initialized', inject( - function($rootScope) { - var childScope1 = $rootScope.$new(); - childScope1.$watch('x', function() { - childScope1.$apply(); - }); - expect(function() { childScope1.$apply(); }).toThrow('$digest already in progress'); - })); - - - it('should thrown an exception if $apply in called from a watch fn (after init)', inject( - function($rootScope) { - var childScope2 = $rootScope.$new(); - childScope2.$apply(function() { - childScope2.$watch('x', function(newVal, oldVal) { - if (newVal !== oldVal) { - childScope2.$apply(); - } - }); - }); - - expect(function() { childScope2.$apply(function() { - childScope2.x = 'something'; - }); }).toThrow('$digest already in progress'); - })); - }); - }); - - - describe('events', function() { - - describe('$on', function() { - - it('should add listener for both $emit and $broadcast events', inject(function($rootScope) { - var log = '', - child = $rootScope.$new(); - - function eventFn() { - log += 'X'; - } - - child.$on('abc', eventFn); - expect(log).toEqual(''); - - child.$emit('abc'); - expect(log).toEqual('X'); - - child.$broadcast('abc'); - expect(log).toEqual('XX'); - })); - - - it('should return a function that deregisters the listener', inject(function($rootScope) { - var log = '', - child = $rootScope.$new(), - listenerRemove; - - function eventFn() { - log += 'X'; - } - - listenerRemove = child.$on('abc', eventFn); - expect(log).toEqual(''); - expect(listenerRemove).toBeDefined(); - - child.$emit('abc'); - child.$broadcast('abc'); - expect(log).toEqual('XX'); - - log = ''; - listenerRemove(); - child.$emit('abc'); - child.$broadcast('abc'); - expect(log).toEqual(''); - })); - }); - - - describe('$emit', function() { - var log, child, grandChild, greatGrandChild; - - function logger(event) { - log += event.currentScope.id + '>'; - } - - beforeEach(module(function($exceptionHandlerProvider) { - $exceptionHandlerProvider.mode('log'); - })); - beforeEach(inject(function($rootScope) { - log = ''; - child = $rootScope.$new(); - grandChild = child.$new(); - greatGrandChild = grandChild.$new(); - - $rootScope.id = 0; - child.id = 1; - grandChild.id = 2; - greatGrandChild.id = 3; - - $rootScope.$on('myEvent', logger); - child.$on('myEvent', logger); - grandChild.$on('myEvent', logger); - greatGrandChild.$on('myEvent', logger); - })); - - it('should bubble event up to the root scope', function() { - grandChild.$emit('myEvent'); - expect(log).toEqual('2>1>0>'); - }); - - - it('should dispatch exceptions to the $exceptionHandler', - inject(function($exceptionHandler) { - child.$on('myEvent', function() { throw 'bubbleException'; }); - grandChild.$emit('myEvent'); - expect(log).toEqual('2>1>0>'); - expect($exceptionHandler.errors).toEqual(['bubbleException']); - })); - - - it('should allow cancelation of event propagation', function() { - child.$on('myEvent', function(event) { event.cancel(); }); - grandChild.$emit('myEvent'); - expect(log).toEqual('2>1>'); - }); - - - it('should forward method arguments', function() { - child.$on('abc', function(event, arg1, arg2) { - expect(event.name).toBe('abc'); - expect(arg1).toBe('arg1'); - expect(arg2).toBe('arg2'); - }); - child.$emit('abc', 'arg1', 'arg2'); - }); - - - it('should return event object with cancelled property', function() { - child.$on('some', function(event) { - event.cancel(); - }); - - var result = grandChild.$emit('some'); - expect(result).toBeDefined(); - expect(result.cancelled).toBe(true); - }); - - - describe('event object', function() { - it('should have methods/properties', function() { - var event; - child.$on('myEvent', function(e) { - expect(e.targetScope).toBe(grandChild); - expect(e.currentScope).toBe(child); - expect(e.name).toBe('myEvent'); - event = e; - }); - grandChild.$emit('myEvent'); - expect(event).toBeDefined(); - }); - }); - }); - - - describe('$broadcast', function() { - describe('event propagation', function() { - var log, child1, child2, child3, grandChild11, grandChild21, grandChild22, grandChild23, - greatGrandChild211; - - function logger(event) { - log += event.currentScope.id + '>'; - } - - beforeEach(inject(function($rootScope) { - log = ''; - child1 = $rootScope.$new(); - child2 = $rootScope.$new(); - child3 = $rootScope.$new(); - grandChild11 = child1.$new(); - grandChild21 = child2.$new(); - grandChild22 = child2.$new(); - grandChild23 = child2.$new(); - greatGrandChild211 = grandChild21.$new(); - - $rootScope.id = 0; - child1.id = 1; - child2.id = 2; - child3.id = 3; - grandChild11.id = 11; - grandChild21.id = 21; - grandChild22.id = 22; - grandChild23.id = 23; - greatGrandChild211.id = 211; - - $rootScope.$on('myEvent', logger); - child1.$on('myEvent', logger); - child2.$on('myEvent', logger); - child3.$on('myEvent', logger); - grandChild11.$on('myEvent', logger); - grandChild21.$on('myEvent', logger); - grandChild22.$on('myEvent', logger); - grandChild23.$on('myEvent', logger); - greatGrandChild211.$on('myEvent', logger); - - // R - // / | \ - // 1 2 3 - // / / | \ - // 11 21 22 23 - // | - // 211 - })); - - - it('should broadcast an event from the root scope', inject(function($rootScope) { - $rootScope.$broadcast('myEvent'); - expect(log).toBe('0>1>11>2>21>211>22>23>3>'); - })); - - - it('should broadcast an event from a child scope', function() { - child2.$broadcast('myEvent'); - expect(log).toBe('2>21>211>22>23>'); - }); - - - it('should broadcast an event from a leaf scope with a sibling', function() { - grandChild22.$broadcast('myEvent'); - expect(log).toBe('22>'); - }); - - - it('should broadcast an event from a leaf scope without a sibling', function() { - grandChild23.$broadcast('myEvent'); - expect(log).toBe('23>'); - }); - - - it('should not not fire any listeners for other events', inject(function($rootScope) { - $rootScope.$broadcast('fooEvent'); - expect(log).toBe(''); - })); - - - it('should return event object', function() { - var result = child1.$broadcast('some'); - - expect(result).toBeDefined(); - expect(result.name).toBe('some'); - expect(result.targetScope).toBe(child1); - }); - }); - - - describe('listener', function() { - it('should receive event object', inject(function($rootScope) { - var scope = $rootScope, - child = scope.$new(), - event; - - child.$on('fooEvent', function(e) { - event = e; - }); - scope.$broadcast('fooEvent'); - - expect(event.name).toBe('fooEvent'); - expect(event.targetScope).toBe(scope); - expect(event.currentScope).toBe(child); - })); - - - it('should support passing messages as varargs', inject(function($rootScope) { - var scope = $rootScope, - child = scope.$new(), - args; - - child.$on('fooEvent', function() { - args = arguments; - }); - scope.$broadcast('fooEvent', 'do', 're', 'me', 'fa'); - - expect(args.length).toBe(5); - expect(sliceArgs(args, 1)).toEqual(['do', 're', 'me', 'fa']); - })); - }); - }); - }); -}); diff --git a/test/service/snifferSpec.js b/test/service/snifferSpec.js deleted file mode 100644 index b359e118..00000000 --- a/test/service/snifferSpec.js +++ /dev/null @@ -1,33 +0,0 @@ -'use strict'; - -describe('$sniffer', function() { - - function sniffer($window) { - return new $SnifferProvider().$get[1]($window); - } - - describe('history', function() { - it('should be true if history.pushState defined', function() { - expect(sniffer({history: {pushState: noop, replaceState: noop}}).history).toBe(true); - }); - - it('should be false if history or pushState not defined', function() { - expect(sniffer({history: {}}).history).toBe(false); - expect(sniffer({}).history).toBe(false); - }); - }); - - describe('hashchange', function() { - it('should be true if onhashchange property defined', function() { - expect(sniffer({onhashchange: true, document: {}}).hashchange).toBe(true); - }); - - it('should be false if onhashchange property not defined', function() { - expect(sniffer({document: {}}).hashchange).toBe(false); - }); - - it('should be false if documentMode is 7 (IE8 comp mode)', function() { - expect(sniffer({onhashchange: true, document: {documentMode: 7}}).hashchange).toBe(false); - }); - }); -}); diff --git a/test/service/windowSpec.js b/test/service/windowSpec.js deleted file mode 100644 index 3b847146..00000000 --- a/test/service/windowSpec.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -describe('$window', function() { - it("should inject $window", inject(function($window) { - expect($window).toBe(window); - })); -}); |
