diff options
Diffstat (limited to 'test/servicesSpec.js')
| -rw-r--r-- | test/servicesSpec.js | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/test/servicesSpec.js b/test/servicesSpec.js new file mode 100644 index 00000000..f679a39b --- /dev/null +++ b/test/servicesSpec.js @@ -0,0 +1,362 @@ +describe("service", function(){ + var scope, $xhrError, $log; + + beforeEach(function(){ + $xhrError = jasmine.createSpy('$xhr.error'); + $log = {}; + scope = createScope(null, angularService, { + '$xhr.error': $xhrError, + '$log': $log + }); + }); + + afterEach(function(){ + if (scope && scope.$element) + scope.$element.remove(); + }); + + + + it("should inject $window", function(){ + expect(scope.$window).toEqual(window); + }); + + xit('should add stylesheets', function(){ + scope.$document = { + getElementsByTagName: function(name){ + expect(name).toEqual('LINK'); + return []; + } + }; + scope.$document.addStyleSheet('css/angular.css'); + }); + + describe("$log", function(){ + it('should use console if present', function(){ + function log(){}; + function warn(){}; + function info(){}; + function error(){}; + var scope = createScope(null, angularService, {$window: {console:{log:log, warn:warn, info:info, error:error}}}); + expect(scope.$log.log).toEqual(log); + expect(scope.$log.warn).toEqual(warn); + expect(scope.$log.info).toEqual(info); + expect(scope.$log.error).toEqual(error); + }); + + it('should use console.log if other not present', function(){ + function log(){}; + var scope = createScope(null, angularService, {$window: {console:{log:log}}}); + expect(scope.$log.log).toEqual(log); + expect(scope.$log.warn).toEqual(log); + expect(scope.$log.info).toEqual(log); + expect(scope.$log.error).toEqual(log); + }); + + it('should use noop if no console', function(){ + var scope = createScope(null, angularService, {$window: {}}); + expect(scope.$log.log).toEqual(noop); + expect(scope.$log.warn).toEqual(noop); + expect(scope.$log.info).toEqual(noop); + expect(scope.$log.error).toEqual(noop); + }); + }); + + describe("$location", function(){ + it("should inject $location", function(){ + scope.$location.parse('http://host:123/p/a/t/h.html?query=value#path?key=value'); + expect(scope.$location.href).toEqual("http://host:123/p/a/t/h.html?query=value#path?key=value"); + expect(scope.$location.protocol).toEqual("http"); + expect(scope.$location.host).toEqual("host"); + expect(scope.$location.port).toEqual("123"); + expect(scope.$location.path).toEqual("/p/a/t/h.html"); + expect(scope.$location.search).toEqual({query:'value'}); + expect(scope.$location.hash).toEqual('path?key=value'); + expect(scope.$location.hashPath).toEqual('path'); + expect(scope.$location.hashSearch).toEqual({key:'value'}); + + scope.$location.hashPath = 'page=http://path'; + scope.$location.hashSearch = {k:'a=b'}; + + expect(scope.$location.toString()).toEqual('http://host:123/p/a/t/h.html?query=value#page=http://path?k=a%3Db'); + }); + + it('should parse file://', function(){ + scope.$location.parse('file:///Users/Shared/misko/work/angular.js/scenario/widgets.html'); + expect(scope.$location.href).toEqual("file:///Users/Shared/misko/work/angular.js/scenario/widgets.html"); + expect(scope.$location.protocol).toEqual("file"); + expect(scope.$location.host).toEqual(""); + expect(scope.$location.port).toEqual(null); + expect(scope.$location.path).toEqual("/Users/Shared/misko/work/angular.js/scenario/widgets.html"); + expect(scope.$location.search).toEqual({}); + expect(scope.$location.hash).toEqual(''); + expect(scope.$location.hashPath).toEqual(''); + expect(scope.$location.hashSearch).toEqual({}); + + expect(scope.$location.toString()).toEqual('file:///Users/Shared/misko/work/angular.js/scenario/widgets.html#'); + }); + + it('should update url on hash change', function(){ + scope.$location.parse('http://server/#path?a=b'); + scope.$location.hash = ''; + expect(scope.$location.toString()).toEqual('http://server/#'); + expect(scope.$location.hashPath).toEqual(''); + }); + + it('should update url on hashPath change', function(){ + scope.$location.parse('http://server/#path?a=b'); + scope.$location.hashPath = ''; + expect(scope.$location.toString()).toEqual('http://server/#?a=b'); + expect(scope.$location.hash).toEqual('?a=b'); + }); + + it('should update hash before any processing', function(){ + var scope = compile('<div>'); + var log = ''; + scope.$watch('$location.hash', function(){ + log += this.$location.hashPath + ';'; + }); + expect(log).toEqual(';'); + + log = ''; + scope.$location.hash = '/abc'; + scope.$eval(); + expect(log).toEqual('/abc;'); + }); + + it("should parse url which contains - in host", function(){ + scope.$location.parse('http://a-b1.c-d.09/path'); + expect(scope.$location.href).toEqual('http://a-b1.c-d.09/path'); + expect(scope.$location.protocol).toEqual('http'); + expect(scope.$location.host).toEqual('a-b1.c-d.09'); + expect(scope.$location.path).toEqual('/path'); + }); + + }); + + describe("$invalidWidgets", function(){ + it("should count number of invalid widgets", function(){ + var scope = compile('<input name="price" ng-required ng-validate="number"></input>').$init(); + expect(scope.$invalidWidgets.length).toEqual(1); + scope.price = 123; + scope.$eval(); + expect(scope.$invalidWidgets.length).toEqual(0); + scope.$element.remove(); + scope.price = 'abc'; + scope.$eval(); + expect(scope.$invalidWidgets.length).toEqual(1); + + jqLite(document.body).append(scope.$element); + scope.$invalidWidgets.clearOrphans(); + expect(scope.$invalidWidgets.length).toEqual(1); + + jqLite(document.body).html(''); + scope.$invalidWidgets.clearOrphans(); + expect(scope.$invalidWidgets.length).toEqual(0); + }); + }); + + + describe("$route", function(){ + it('should route and fire change event', function(){ + var log = ''; + function BookChapter() { + this.log = '<init>'; + } + BookChapter.prototype.init = function(){ + log += 'init();'; + }; + var scope = compile('<div></div>').$init(); + scope.$route.when('/Book/:book/Chapter/:chapter', {controller: BookChapter, template:'Chapter.html'}); + scope.$route.when('/Blank'); + scope.$route.onChange(function(){ + log += 'onChange();'; + }); + scope.$location.parse('http://server#/Book/Moby/Chapter/Intro?p=123'); + scope.$eval(); + expect(log).toEqual('onChange();init();'); + expect(scope.$route.current.params).toEqual({book:'Moby', chapter:'Intro', p:'123'}); + expect(scope.$route.current.scope.log).toEqual('<init>'); + var lastId = scope.$route.current.scope.$id; + + log = ''; + scope.$location.parse('http://server#/Blank?ignore'); + scope.$eval(); + expect(log).toEqual('onChange();'); + expect(scope.$route.current.params).toEqual({ignore:true}); + expect(scope.$route.current.scope.$id).not.toEqual(lastId); + + log = ''; + scope.$location.parse('http://server#/NONE'); + scope.$eval(); + expect(log).toEqual('onChange();'); + expect(scope.$route.current).toEqual(null); + + scope.$route.when('/NONE', {template:'instant update'}); + scope.$eval(); + expect(scope.$route.current.template).toEqual('instant update'); + }); + }); + + describe('$resource', function(){ + it('should publish to root scope', function(){ + expect(scope.$resource).toBeTruthy(); + }); + }); + + describe('$xhr', function(){ + var log, xhr; + function callback(code, response) { + expect(code).toEqual(200); + log = log + toJson(response) + ';'; + } + + beforeEach(function(){ + log = ''; + xhr = scope.$browser.xhr; + }); + + it('should forward the request to $browser and decode JSON', function(){ + xhr.expectGET('/reqGET').respond('first'); + xhr.expectGET('/reqGETjson').respond('["second"]'); + xhr.expectPOST('/reqPOST', {post:'data'}).respond('third'); + + scope.$xhr('GET', '/reqGET', null, callback); + scope.$xhr('GET', '/reqGETjson', null, callback); + scope.$xhr('POST', '/reqPOST', {post:'data'}, callback); + + xhr.flush(); + + expect(log).toEqual('"third";["second"];"first";'); + }); + + it('should handle non 200 status codes by forwarding to error handler', function(){ + xhr.expectPOST('/req', 'MyData').respond(500, 'MyError'); + scope.$xhr('POST', '/req', 'MyData', callback); + xhr.flush(); + var cb = $xhrError.mostRecentCall.args[0].callback; + expect(typeof cb).toEqual('function'); + expect($xhrError).wasCalledWith( + {url:'/req', method:'POST', data:'MyData', callback:cb}, + {status:500, body:'MyError'}); + }); + + it('should handle exceptions in callback', function(){ + $log.error = jasmine.createSpy('$log.error'); + xhr.expectGET('/reqGET').respond('first'); + scope.$xhr('GET', '/reqGET', null, function(){ throw "MyException"; }); + xhr.flush(); + + expect($log.error).wasCalledWith("MyException"); + }); + + describe('bulk', function(){ + it('should collect requests', function(){ + scope.$xhr.bulk.urls["/"] = {match:/.*/}; + scope.$xhr.bulk('GET', '/req1', null, callback); + scope.$xhr.bulk('POST', '/req2', {post:'data'}, callback); + + xhr.expectPOST('/', { + requests:[{method:'GET', url:'/req1', data: null}, + {method:'POST', url:'/req2', data:{post:'data'} }] + }).respond([ + {status:200, response:'first'}, + {status:200, response:'second'} + ]); + scope.$xhr.bulk.flush(function(){ log += 'DONE';}); + xhr.flush(); + expect(log).toEqual('"first";"second";DONE'); + }); + + it('should handle non 200 status code by forwarding to error handler', function(){ + scope.$xhr.bulk.urls['/'] = {match:/.*/}; + scope.$xhr.bulk('GET', '/req1', null, callback); + scope.$xhr.bulk('POST', '/req2', {post:'data'}, callback); + + xhr.expectPOST('/', { + requests:[{method:'GET', url:'/req1', data: null}, + {method:'POST', url:'/req2', data:{post:'data'} }] + }).respond([ + {status:404, response:'NotFound'}, + {status:200, response:'second'} + ]); + scope.$xhr.bulk.flush(function(){ log += 'DONE';}); + xhr.flush(); + + expect($xhrError).wasCalled(); + var cb = $xhrError.mostRecentCall.args[0].callback; + expect(typeof cb).toEqual('function'); + expect($xhrError).wasCalledWith( + {url:'/req1', method:'GET', data:null, callback:cb}, + {status:404, response:'NotFound'}); + + expect(log).toEqual('"second";DONE'); + }); + }); + + describe('cache', function(){ + var cache; + beforeEach(function(){ cache = scope.$xhr.cache; }); + + it('should cache requests', function(){ + xhr.expectGET('/url').respond('first'); + cache('GET', '/url', null, callback); + xhr.flush(); + xhr.expectGET('/url').respond('ERROR'); + cache('GET', '/url', null, callback); + xhr.flush(); + expect(log).toEqual('"first";"first";'); + cache('GET', '/url', null, callback, false); + xhr.flush(); + expect(log).toEqual('"first";"first";"first";'); + }); + + it('should first return cache request, then return server request', function(){ + xhr.expectGET('/url').respond('first'); + cache('GET', '/url', null, callback, true); + xhr.flush(); + xhr.expectGET('/url').respond('ERROR'); + cache('GET', '/url', null, callback, true); + expect(log).toEqual('"first";"first";'); + xhr.flush(); + expect(log).toEqual('"first";"first";"ERROR";'); + }); + + it('should serve requests from cache', function(){ + cache.data.url = {value:'123'}; + cache('GET', 'url', null, callback); + expect(log).toEqual('"123";'); + cache('GET', 'url', null, callback, false); + expect(log).toEqual('"123";"123";'); + }); + + it('should keep track of in flight requests and request only once', function(){ + scope.$xhr.bulk.urls['/bulk'] = { + match:function(url){ + return url == '/url'; + } + }; + xhr.expectPOST('/bulk', { + requests:[{method:'GET', url:'/url', data: null}] + }).respond([ + {status:200, response:'123'} + ]); + cache('GET', '/url', null, callback); + cache('GET', '/url', null, callback); + cache.delegate.flush(); + xhr.flush(); + expect(log).toEqual('"123";"123";'); + }); + + it('should clear cache on non GET', function(){ + xhr.expectPOST('abc', {}).respond({}); + cache.data.url = {value:123}; + cache('POST', 'abc', {}); + expect(cache.data.url).toBeUndefined(); + }); + }); + + }); + + +}); |
