diff options
| author | Igor Minar | 2011-12-28 09:26:22 -0800 | 
|---|---|---|
| committer | Vojta Jina | 2012-01-09 13:17:48 -0800 | 
| commit | a13b5ed3bc337a493029815c595b89c39eb95af6 (patch) | |
| tree | 2ca5380d5cf5aea68218280cccda5d0221517454 /test | |
| parent | 63cca9afbcf7a772086eb4582d2f409c39e0ed12 (diff) | |
| download | angular.js-a13b5ed3bc337a493029815c595b89c39eb95af6.tar.bz2 | |
fix($http): fix and cleanup $http and friends
$http:
- use promises internally
- get rid of XhrFuture that was previously used internally
- get rid of $browser.defer calls for async stuff (serving from cache),
  promises will take care of asynchronicity
- fix transformation bugs (when caching requested + multiple request
  pending + error is returned)
- get rid of native header parsing and instead just lazily parse the
  header string
$httpBackend:
- don't return raw/mock XMLHttpRequest object (we don't use it for
  anything anymore)
- call the callback with response headers string
mock $httpBackend:
- unify response api for expect and when
- call the callback with response headers string
- changed the expect/when failure error message so that EXPECTED and GOT
  values are aligned
Conflicts:
	src/service/http.js
	test/service/compilerSpec.js
	test/service/httpSpec.js
Diffstat (limited to 'test')
| -rw-r--r-- | test/angular-mocksSpec.js | 288 | ||||
| -rw-r--r-- | test/service/httpBackendSpec.js | 23 | ||||
| -rw-r--r-- | test/service/httpSpec.js | 53 | ||||
| -rw-r--r-- | test/widgetsSpec.js | 9 | 
4 files changed, 174 insertions, 199 deletions
diff --git a/test/angular-mocksSpec.js b/test/angular-mocksSpec.js index a8328f41..88e6a590 100644 --- a/test/angular-mocksSpec.js +++ b/test/angular-mocksSpec.js @@ -465,39 +465,6 @@ describe('mocks', function() {      }); -    it('should expose given headers', function() { -      hb.when('GET', '/u1').respond(200, null, {'X-Fake': 'Header', 'Content-Type': 'application/json'}); -      var xhr = hb('GET', '/u1', null, noop, {}); -      hb.flush(); -      expect(xhr.getResponseHeader('X-Fake')).toBe('Header'); -      expect(xhr.getAllResponseHeaders()).toBe('X-Fake: Header\nContent-Type: application/json'); -    }); - - -    it('should normalize when header name case when accessed via getResponseHeader', function() { -      hb.when('GET', '/u1').respond(200, null, {'X-Fake': 'Header', -                                                'Content-Type': 'application/json', -                                                'Location': '/foo'}); -      var xhr = hb('GET', '/u1', null, noop, {}); -      hb.flush(); -      expect(xhr.getResponseHeader('x-fAKE')).toBe('Header'); -      expect(xhr.getResponseHeader('content-type')).toBe('application/json'); -      expect(xhr.getResponseHeader('Location')).toBe('/foo'); -    }); - - -    it('should normalize expect header name case when accessed via getResponseHeader', function() { -      hb.expect('GET', '/u1').respond(200, null, {'X-Fake': 'Header', -                                                'Content-Type': 'application/json', -                                                'Location': '/foo'}); -      var xhr = hb('GET', '/u1', null, noop, {}); -      hb.flush(); -      expect(xhr.getResponseHeader('x-fAKE')).toBe('Header'); -      expect(xhr.getResponseHeader('content-type')).toBe('application/json'); -      expect(xhr.getResponseHeader('Location')).toBe('/foo'); -    }); - -      it('should preserve the order of requests', function() {        hb.when('GET', '/url1').respond(200, 'first');        hb.when('GET', '/url2').respond(201, 'second'); @@ -508,186 +475,179 @@ describe('mocks', function() {        hb.flush();        expect(callback.callCount).toBe(2); -      expect(callback.argsForCall[0]).toEqual([201, 'second']); -      expect(callback.argsForCall[1]).toEqual([200, 'first']); +      expect(callback.argsForCall[0]).toEqual([201, 'second', '']); +      expect(callback.argsForCall[1]).toEqual([200, 'first', '']);      }); -    it('respond() should take function', function() { -      hb.when('GET', '/some').respond(function(m, u, d, h) { -        return [301, m + u + ';' + d + ';a=' + h.a, {'Connection': 'keep-alive'}]; -      }); - -      var xhr = hb('GET', '/some', 'data', callback, {a: 'b'}); -      hb.flush(); +    describe('respond()', function() { +      it('should take values', function() { +        hb.expect('GET', '/url1').respond(200, 'first', {'header': 'val'}); +        hb('GET', '/url1', undefined, callback); +        hb.flush(); -      expect(callback).toHaveBeenCalledOnce(); -      expect(callback.mostRecentCall.args[0]).toBe(301); -      expect(callback.mostRecentCall.args[1]).toBe('GET/some;data;a=b'); -      expect(xhr.getResponseHeader('Connection')).toBe('keep-alive'); -    }); +        expect(callback).toHaveBeenCalledOnceWith(200, 'first', 'header: val'); +      }); +      it('should take function', function() { +        hb.expect('GET', '/some').respond(function(m, u, d, h) { +          return [301, m + u + ';' + d + ';a=' + h.a, {'Connection': 'keep-alive'}]; +        }); -    it('expect() should require specified order', function() { -      hb.expect('GET', '/url1').respond(200, ''); -      hb.expect('GET', '/url2').respond(200, ''); +        hb('GET', '/some', 'data', callback, {a: 'b'}); +        hb.flush(); -      expect(function() { -        hb('GET', '/url2', null, noop, {}); -      }).toThrow('Unexpected request: GET /url2\nExpected GET /url1'); -    }); +        expect(callback).toHaveBeenCalledOnceWith(301, 'GET/some;data;a=b', 'Connection: keep-alive'); +      }); +      it('should default status code to 200', function() { +        callback.andCallFake(function(status, response) { +          expect(status).toBe(200); +          expect(response).toBe('some-data'); +        }); -    it('expect() should have precendence over when()', function() { -      callback.andCallFake(function(status, response) { -        expect(status).toBe(300); -        expect(response).toBe('expect'); +        hb.expect('GET', '/url1').respond('some-data'); +        hb.expect('GET', '/url2').respond('some-data', {'X-Header': 'true'}); +        hb('GET', '/url1', null, callback); +        hb('GET', '/url2', null, callback); +        hb.flush(); +        expect(callback).toHaveBeenCalled(); +        expect(callback.callCount).toBe(2);        }); -      hb.when('GET', '/url').respond(200, 'when'); -      hb.expect('GET', '/url').respond(300, 'expect'); -      hb('GET', '/url', null, callback, {}); -      hb.flush(); -      expect(callback).toHaveBeenCalledOnce(); -    }); +      it('should default response headers to ""', function() { +        hb.expect('GET', '/url1').respond(200, 'first'); +        hb.expect('GET', '/url2').respond('second'); +        hb('GET', '/url1', null, callback); +        hb('GET', '/url2', null, callback); -    it ('should throw exception when only headers differes from expectation', function() { -      hb.when('GET').respond(200, '', {}); -      hb.expect('GET', '/match', undefined, {'Content-Type': 'application/json'}); +        hb.flush(); -      expect(function() { -        hb('GET', '/match', null, noop, {}); -      }).toThrow('Expected GET /match with different headers\n' + -                 'EXPECTED: {"Content-Type":"application/json"}\nGOT: {}'); +        expect(callback.callCount).toBe(2); +        expect(callback.argsForCall[0]).toEqual([200, 'first', '']); +        expect(callback.argsForCall[1]).toEqual([200, 'second', '']); +      });      }); -    it ('should throw exception when only data differes from expectation', function() { -      hb.when('GET').respond(200, '', {}); -      hb.expect('GET', '/match', 'some-data'); - -      expect(function() { -        hb('GET', '/match', 'different', noop, {}); -      }).toThrow('Expected GET /match with different data\n' + -                 'EXPECTED: some-data\nGOT: different'); -    }); - +    describe('expect()', function() { +      it('should require specified order', function() { +        hb.expect('GET', '/url1').respond(200, ''); +        hb.expect('GET', '/url2').respond(200, ''); -    it('expect() should without respond() and use respond()', function() { -      callback.andCallFake(function(status, response) { -        expect(status).toBe(201); -        expect(response).toBe('data'); +        expect(function() { +          hb('GET', '/url2', null, noop, {}); +        }).toThrow('Unexpected request: GET /url2\nExpected GET /url1');        }); -      hb.when('GET', '/some').respond(201, 'data'); -      hb.expect('GET', '/some'); -      hb('GET', '/some', null, callback); -      hb.flush(); -      expect(callback).toHaveBeenCalled(); -      expect(function() { hb.verifyNoOutstandingExpectation(); }).not.toThrow(); -    }); +      it('should have precedence over when()', function() { +        callback.andCallFake(function(status, response) { +          expect(status).toBe(300); +          expect(response).toBe('expect'); +        }); +        hb.when('GET', '/url').respond(200, 'when'); +        hb.expect('GET', '/url').respond(300, 'expect'); -    it('flush() should flush requests fired during callbacks', function() { -      hb.when('GET').respond(200, ''); -      hb('GET', '/some', null, function() { -        hb('GET', '/other', null, callback); +        hb('GET', '/url', null, callback, {}); +        hb.flush(); +        expect(callback).toHaveBeenCalledOnce();        }); -      hb.flush(); -      expect(callback).toHaveBeenCalled(); -    }); - -    it('flush() should flush given number of pending requests', function() { -      hb.when('GET').respond(200, ''); -      hb('GET', '/some', null, callback); -      hb('GET', '/some', null, callback); -      hb('GET', '/some', null, callback); +      it ('should throw exception when only headers differs from expectation', function() { +        hb.when('GET').respond(200, '', {}); +        hb.expect('GET', '/match', undefined, {'Content-Type': 'application/json'}); -      hb.flush(2); -      expect(callback).toHaveBeenCalled(); -      expect(callback.callCount).toBe(2); -    }); +        expect(function() { +          hb('GET', '/match', null, noop, {}); +        }).toThrow('Expected GET /match with different headers\n' + +                   'EXPECTED: {"Content-Type":"application/json"}\nGOT:      {}'); +      }); -    it('flush() should throw exception when flushing more requests than pending', function() { -      hb.when('GET').respond(200, ''); -      hb('GET', '/url', null, callback); +      it ('should throw exception when only data differs from expectation', function() { +        hb.when('GET').respond(200, '', {}); +        hb.expect('GET', '/match', 'some-data'); -      expect(function() {hb.flush(2);}).toThrow('No more pending request to flush !'); -      expect(callback).toHaveBeenCalledOnce(); -    }); +        expect(function() { +          hb('GET', '/match', 'different', noop, {}); +        }).toThrow('Expected GET /match with different data\n' + +                   'EXPECTED: some-data\nGOT:      different'); +      }); -    it('(flush) should throw exception when no request to flush', function() { -      expect(function() {hb.flush();}).toThrow('No pending request to flush !'); +      it("should use when's respond() when no expect() respond is defined", function() { +        callback.andCallFake(function(status, response) { +          expect(status).toBe(201); +          expect(response).toBe('data'); +        }); -      hb.when('GET').respond(200, ''); -      hb('GET', '/some', null, callback); -      hb.flush(); +        hb.when('GET', '/some').respond(201, 'data'); +        hb.expect('GET', '/some'); +        hb('GET', '/some', null, callback); +        hb.flush(); -      expect(function() {hb.flush();}).toThrow('No pending request to flush !'); +        expect(callback).toHaveBeenCalled(); +        expect(function() { hb.verifyNoOutstandingExpectation(); }).not.toThrow(); +      });      }); -    it('(flush) should throw exception if not all expectations satasfied', function() { -      hb.expect('GET', '/url1').respond(); -      hb.expect('GET', '/url2').respond(); +    describe('flush()', function() { +      it('flush() should flush requests fired during callbacks', function() { +        hb.when('GET').respond(200, ''); +        hb('GET', '/some', null, function() { +          hb('GET', '/other', null, callback); +        }); -      hb('GET', '/url1', null, angular.noop); -      expect(function() {hb.flush();}).toThrow('Unsatisfied requests: GET /url2'); -    }); +        hb.flush(); +        expect(callback).toHaveBeenCalled(); +      }); -    it('respond() should set default status 200 if not defined', function() { -      callback.andCallFake(function(status, response) { -        expect(status).toBe(200); -        expect(response).toBe('some-data'); +      it('should flush given number of pending requests', function() { +        hb.when('GET').respond(200, ''); +        hb('GET', '/some', null, callback); +        hb('GET', '/some', null, callback); +        hb('GET', '/some', null, callback); + +        hb.flush(2); +        expect(callback).toHaveBeenCalled(); +        expect(callback.callCount).toBe(2);        }); -      hb.expect('GET', '/url1').respond('some-data'); -      hb.expect('GET', '/url2').respond('some-data', {'X-Header': 'true'}); -      hb('GET', '/url1', null, callback); -      hb('GET', '/url2', null, callback); -      hb.flush(); -      expect(callback).toHaveBeenCalled(); -      expect(callback.callCount).toBe(2); -    }); +      it('should throw exception when flushing more requests than pending', function() { +        hb.when('GET').respond(200, ''); +        hb('GET', '/url', null, callback); -    it('respond() should set default status 200 if not defined', function() { -      callback.andCallFake(function(status, response) { -        expect(status).toBe(200); -        expect(response).toBe('some-data'); +        expect(function() {hb.flush(2);}).toThrow('No more pending request to flush !'); +        expect(callback).toHaveBeenCalledOnce();        }); -      hb.when('GET', '/url1').respond('some-data'); -      hb.when('GET', '/url2').respond('some-data', {'X-Header': 'true'}); -      hb('GET', '/url1', null, callback); -      hb('GET', '/url2', null, callback); -      hb.flush(); -      expect(callback).toHaveBeenCalled(); -      expect(callback.callCount).toBe(2); -    }); +      it('should throw exception when no request to flush', function() { +        expect(function() {hb.flush();}).toThrow('No pending request to flush !'); -    it('should respond with definition if no response for expectation', function() { -      callback.andCallFake(function(status, response) { -        expect(status).toBe(201); -        expect(response).toBe('def-response'); +        hb.when('GET').respond(200, ''); +        hb('GET', '/some', null, callback); +        hb.flush(); + +        expect(function() {hb.flush();}).toThrow('No pending request to flush !');        }); -      hb.when('GET').respond(201, 'def-response'); -      hb.expect('GET', '/some-url'); -      hb('GET', '/some-url', null, callback); -      hb.flush(); -      expect(callback).toHaveBeenCalledOnce(); -      hb.verifyNoOutstandingExpectation(); +      it('should throw exception if not all expectations satisfied', function() { +        hb.expect('GET', '/url1').respond(); +        hb.expect('GET', '/url2').respond(); + +        hb('GET', '/url1', null, angular.noop); +        expect(function() {hb.flush();}).toThrow('Unsatisfied requests: GET /url2'); +      });      }); @@ -699,7 +659,7 @@ describe('mocks', function() {      }); -    it('should throw an exception if no response for expection and no definition', function() { +    it('should throw an exception if no response for exception and no definition', function() {        hb.expect('GET', '/url');        expect(function() {          hb('GET', '/url', null, callback); @@ -762,7 +722,7 @@ describe('mocks', function() {      }); -    describe('reset', function() { +    describe('resetExpectations', function() {        it('should remove all expectations', function() {          hb.expect('GET', '/u2').respond(200, '', {}); @@ -773,7 +733,7 @@ describe('mocks', function() {        }); -      it('should remove all responses', function() { +      it('should remove all pending responses', function() {          var cancelledClb = jasmine.createSpy('cancelled');          hb.expect('GET', '/url').respond(200, ''); diff --git a/test/service/httpBackendSpec.js b/test/service/httpBackendSpec.js index b9bf2b18..1c6d3a51 100644 --- a/test/service/httpBackendSpec.js +++ b/test/service/httpBackendSpec.js @@ -58,18 +58,13 @@ describe('$httpBackend', function() {      $backend('POST', 'URL', null, noop, {'X-header1': 'value1', 'X-header2': 'value2'});      xhr = MockXhr.$$lastInstance; -    expect(xhr.$$headers).toEqual({ +    expect(xhr.$$reqHeaders).toEqual({        'X-header1': 'value1',        'X-header2': 'value2'      });    }); -  it('should return raw xhr object', function() { -    expect($backend('GET', '/url', null, noop)).toBe(MockXhr.$$lastInstance); -  }); - -    it('should abort request on timeout', function() {      callback.andCallFake(function(status, response) {        expect(status).toBe(-1); @@ -91,16 +86,20 @@ describe('$httpBackend', function() {    }); -  it('should be async even if xhr.send() is sync', function() { -    // IE6, IE7 is sync when serving from cache +  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) { @@ -108,14 +107,8 @@ describe('$httpBackend', function() {        expect(response).toBe('response');      }); -    $backend = createHttpBackend($browser, SyncXhr, fakeTimeout); +    $backend = createHttpBackend($browser, SyncXhr);      $backend('GET', '/url', null, callback); -    expect(callback).not.toHaveBeenCalled(); - -    fakeTimeout.flush(); -    expect(callback).toHaveBeenCalledOnce(); - -    (xhr.onreadystatechange || noop)();      expect(callback).toHaveBeenCalledOnce();    }); diff --git a/test/service/httpSpec.js b/test/service/httpSpec.js index 5b8f43f5..c1f8645e 100644 --- a/test/service/httpSpec.js +++ b/test/service/httpSpec.js @@ -66,7 +66,7 @@ describe('$http', function() {            expect(data).toBe('Hello!?');            expect(status).toBe(209);            callback(); -        }) +        });          $httpBackend.flush();          expect(callback).toHaveBeenCalledOnce();        })); @@ -550,7 +550,7 @@ describe('$http', function() {      }); -    describe('transform', function() { +    describe('transformData', function() {        describe('request', function() { @@ -648,17 +648,19 @@ describe('$http', function() {          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($browser) { + +      it('should cache GET request when cache is provided', inject(function($rootScope) {          doFirstCacheRequest();          $http({method: 'get', url: '/url', cache: cache}).success(callback); -        $browser.defer.flush(); +        $rootScope.$digest();          expect(callback).toHaveBeenCalledOnce();          expect(callback.mostRecentCall.args[0]).toBe('content'); @@ -737,7 +739,7 @@ describe('$http', function() {        }); -      it('should cache the headers as well', inject(function($browser) { +      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'}); @@ -745,24 +747,37 @@ describe('$http', function() {          });          $http({method: 'GET', url: '/url', cache: cache}).success(callback); -        $browser.defer.flush(); +        $rootScope.$digest();          expect(callback).toHaveBeenCalledOnce();        })); -      it('should cache status code as well', inject(function($browser) { +      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); -        $browser.defer.flush(); +        $rootScope.$digest();          expect(callback).toHaveBeenCalledOnce();        })); -      it('should use cache even if request fired before first response is back', function() { +      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) { @@ -777,6 +792,22 @@ describe('$http', function() {          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(); +          }) +      );      }); @@ -794,7 +825,7 @@ describe('$http', function() {        }); -      it('should update pending requests even when served from cache', inject(function($browser) { +      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}); @@ -807,7 +838,7 @@ describe('$http', function() {          $http({method: 'get', url: '/cached', cache: true});          expect($http.pendingRequests.length).toBe(1); -        $browser.defer.flush(); +        $rootScope.$apply();          expect($http.pendingRequests.length).toBe(0);        })); diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index e8ff4b27..09d807b5 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -72,7 +72,6 @@ describe('widget', function() {        $rootScope.childScope.name = 'misko';        $rootScope.url = 'myUrl';        $rootScope.$digest(); -      $browser.defer.flush();        expect(element.text()).toEqual('misko');      })); @@ -86,7 +85,6 @@ describe('widget', function() {        $rootScope.childScope.name = 'igor';        $rootScope.url = 'myUrl';        $rootScope.$digest(); -      $browser.defer.flush();        expect(element.text()).toEqual('igor'); @@ -103,7 +101,6 @@ describe('widget', function() {        element = $compile(element)($rootScope);        $rootScope.url = 'myUrl';        $rootScope.$digest(); -      $browser.defer.flush();        // TODO(misko): because we are using scope==this, the eval gets registered        // during the flush phase and hence does not get called. @@ -125,7 +122,6 @@ describe('widget', function() {        $rootScope.url = 'myUrl';        $rootScope.$digest(); -      $browser.defer.flush();        expect(element.text()).toEqual('my partial');        expect($rootScope.loaded).toBe(true); @@ -141,7 +137,6 @@ describe('widget', function() {        $rootScope.url = 'myUrl';        $rootScope.$digest(); -      $browser.defer.flush();        expect($rootScope.$$childHead).toBeTruthy();        $rootScope.url = null; @@ -166,7 +161,6 @@ describe('widget', function() {        $rootScope.url = 'myUrl';        $rootScope.$digest(); -      $browser.defer.flush();        expect(element.text()).toEqual('my partial');        dealoc($rootScope);      })); @@ -199,7 +193,6 @@ describe('widget', function() {        });        $rootScope.$digest(); -      $browser.defer.flush();        expect(element.text()).toBe('my partial');      })); @@ -746,7 +739,6 @@ describe('widget', function() {        $rootScope.log = [];        $location.path('/foo');        $rootScope.$apply(); -      $browser.defer.flush();        expect($rootScope.log).toEqual(['parent', 'init', 'child']);      })); @@ -801,7 +793,6 @@ describe('widget', function() {        });        $rootScope.$digest(); -      $browser.defer.flush();        expect(element.text()).toBe('my partial');      }));    });  | 
