diff options
| -rw-r--r-- | src/Browser.js | 35 | ||||
| -rw-r--r-- | src/Resource.js | 4 | ||||
| -rw-r--r-- | src/angular-mocks.js | 35 | ||||
| -rw-r--r-- | src/service/resource.js | 10 | ||||
| -rw-r--r-- | src/service/xhr.bulk.js | 11 | ||||
| -rw-r--r-- | src/service/xhr.cache.js | 18 | ||||
| -rw-r--r-- | src/service/xhr.js | 11 | ||||
| -rw-r--r-- | test/BrowserSpecs.js | 42 | ||||
| -rw-r--r-- | test/ResourceSpec.js | 42 | ||||
| -rw-r--r-- | test/service/xhr.bulkSpec.js | 7 | ||||
| -rw-r--r-- | test/service/xhr.cacheSpec.js | 35 | ||||
| -rw-r--r-- | test/service/xhrSpec.js | 37 | 
12 files changed, 215 insertions, 72 deletions
| diff --git a/src/Browser.js b/src/Browser.js index 2b2170e2..65d27448 100644 --- a/src/Browser.js +++ b/src/Browser.js @@ -84,7 +84,9 @@ function Browser(window, document, body, XHR, $log) {     * @param {string} method Requested method (get|post|put|delete|head|json)     * @param {string} url Requested url     * @param {?string} post Post data to send (null if nothing to post) -   * @param {function(number, string)} callback Function that will be called on response +   * @param {function(number, string, function([string]))} callback Function that will be called on +   *   response. The third argument is a function that can be called to return a specified response +   *   header or an Object containing all headers (when called with no arguments).     * @param {object=} header additional HTTP headers to send with XHR.     *   Standard headers are:     *   <ul> @@ -97,6 +99,8 @@ function Browser(window, document, body, XHR, $log) {     * Send ajax request     */    self.xhr = function(method, url, post, callback, headers) { +    var parsedHeaders; +      outstandingRequestCount ++;      if (lowercase(method) == 'json') {        var callbackId = ("angular_" + Math.random() + '_' + (idCounter++)).replace(/\d\./, ''); @@ -123,7 +127,34 @@ function Browser(window, document, body, XHR, $log) {          if (xhr.readyState == 4) {            // normalize IE bug (http://bugs.jquery.com/ticket/1450)            var status = xhr.status == 1223 ? 204 : xhr.status || 200; -          completeOutstandingRequest(callback, status, xhr.responseText); +          completeOutstandingRequest(callback, status, xhr.responseText, function(header) { +            header = lowercase(header); + +            if (header) { +              return parsedHeaders +                ? parsedHeaders[header] || null +                : xhr.getResponseHeader(header); +            } else { +              // Return an object containing each response header +              parsedHeaders = {}; + +              forEach(xhr.getAllResponseHeaders().split('\n'), function(line) { +                var i = line.indexOf(':'), +                    key = lowercase(trim(line.substr(0, i))), +                    value = trim(line.substr(i + 1)); + +                if (parsedHeaders[key]) { +                  // Combine repeated headers +                  // http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 +                  parsedHeaders[key] += ', ' + value; +                } else { +                  parsedHeaders[key] = value; +                } +              }); + +              return parsedHeaders; +            } +          });          }        };        xhr.send(post || ''); diff --git a/src/Resource.js b/src/Resource.js index 74d952ed..4bf5cf65 100644 --- a/src/Resource.js +++ b/src/Resource.js @@ -111,7 +111,7 @@ ResourceFactory.prototype = {            action.method,            route.url(extend({}, action.params || {}, extractParams(data), params)),            data, -          function(status, response) { +          function(status, response, responseHeaders) {              if (response) {                if (action.isArray) {                  value.length = 0; @@ -122,7 +122,7 @@ ResourceFactory.prototype = {                  copy(response, value);                }              } -            (success||noop)(value); +            (success||noop)(value, responseHeaders);            },            error || action.verifyCache,            action.verifyCache); diff --git a/src/angular-mocks.js b/src/angular-mocks.js index 5d56ae27..d793f511 100644 --- a/src/angular-mocks.js +++ b/src/angular-mocks.js @@ -152,7 +152,14 @@ function MockBrowser() {            throw new Error("Missing HTTP request header: " + key + ": " + value);          }        }); -      callback(expectation.code, expectation.response); +      callback(expectation.code, expectation.response, function(header) { +        if (header) { +          header = header.toLowerCase(); +          return expectation.responseHeaders && expectation.responseHeaders[header] || null; +        } else { +          return expectation.responseHeaders || {}; +        } +      });      });    };    self.xhr.expectations = expectations; @@ -162,12 +169,22 @@ function MockBrowser() {      if (data && angular.isString(data)) url += "|" + data;      var expect = expectations[method] || (expectations[method] = {});      return { -      respond: function(code, response) { +      respond: function(code, response, responseHeaders) {          if (!angular.isNumber(code)) { +          responseHeaders = response;            response = code;            code = 200;          } -        expect[url] = {code:code, response:response, headers: headers || {}}; +        angular.forEach(responseHeaders, function(value, key) { +          delete responseHeaders[key]; +          responseHeaders[key.toLowerCase()] = value; +        }); +        expect[url] = { +          code: code, +          response: response, +          headers: headers || {}, +          responseHeaders: responseHeaders || {} +        };        }      };    }; @@ -268,7 +285,7 @@ function MockBrowser() {    self.defer = function(fn, delay) {      delay = delay || 0;      self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId}); -    self.deferredFns.sort(function(a,b){ return a.time - b.time;}); +    self.deferredFns.sort(function(a,b){return a.time - b.time;});      return self.deferredNextId++;    }; @@ -374,7 +391,7 @@ angular.service('$browser', function(){   * See {@link angular.mock} for more info on angular mocks.   */  angular.service('$exceptionHandler', function() { -  return function(e) { throw e;}; +  return function(e) {throw e;};  }); @@ -394,10 +411,10 @@ angular.service('$log', MockLogFactory);  function MockLogFactory() {    var $log = { -    log: function(){ $log.log.logs.push(arguments); }, -    warn: function(){ $log.warn.logs.push(arguments); }, -    info: function(){ $log.info.logs.push(arguments); }, -    error: function(){ $log.error.logs.push(arguments); } +    log: function(){$log.log.logs.push(arguments);}, +    warn: function(){$log.warn.logs.push(arguments);}, +    info: function(){$log.info.logs.push(arguments);}, +    error: function(){$log.error.logs.push(arguments);}    };    $log.log.logs = []; diff --git a/src/service/resource.js b/src/service/resource.js index f6e0be18..47b57645 100644 --- a/src/service/resource.js +++ b/src/service/resource.js @@ -147,9 +147,15 @@   *     <pre>       var User = $resource('/user/:userId', {userId:'@id'}); -     User.get({userId:123}, function(u){ +     User.get({userId:123}, function(u, responseHeaders){         u.abc = true; -       u.$save(); +       u.$save(function(u, responseHeaders) { +         // Get an Object containing all response headers +         var allHeaders = responseHeaders(); + +         // Get a specific response header +         u.newId = responseHeaders('Location'); +       });       });     </pre> diff --git a/src/service/xhr.bulk.js b/src/service/xhr.bulk.js index d7fc7990..8d9e7a72 100644 --- a/src/service/xhr.bulk.js +++ b/src/service/xhr.bulk.js @@ -48,13 +48,14 @@ angularServiceInject('$xhr.bulk', function($xhr, $error, $log){          queue.requests = [];          queue.callbacks = [];          $xhr('POST', url, {requests: currentRequests}, -          function(code, response) { +          function(code, response, responseHeaders) {              forEach(response, function(response, i) {                try {                  if (response.status == 200) { -                  (currentRequests[i].success || noop)(response.status, response.response); +                  (currentRequests[i].success || noop) +                      (response.status, response.response, responseHeaders);                  } else if (isFunction(currentRequests[i].error)) { -                    currentRequests[i].error(response.status, response.response); +                    currentRequests[i].error(response.status, response.response, responseHeaders);                  } else {                    $error(currentRequests[i], response);                  } @@ -64,11 +65,11 @@ angularServiceInject('$xhr.bulk', function($xhr, $error, $log){              });              (success || noop)();            }, -          function(code, response) { +          function(code, response, responseHeaders) {              forEach(currentRequests, function(request, i) {                try {                  if (isFunction(request.error)) { -                  request.error(code, response); +                  request.error(code, response, responseHeaders);                  } else {                    $error(request, response);                  } diff --git a/src/service/xhr.cache.js b/src/service/xhr.cache.js index 256b936e..b3280101 100644 --- a/src/service/xhr.cache.js +++ b/src/service/xhr.cache.js @@ -22,8 +22,8 @@   * @param {string} method HTTP method.   * @param {string} url Destination URL.   * @param {(string|Object)=} post Request body. - * @param {function(number, (string|Object))} success Response success callback. - * @param {function(number, (string|Object))=} error Response error callback. + * @param {function(number, (string|Object), Function)} success Response success callback. + * @param {function(number, (string|Object), Function)} error Response error callback.   * @param {boolean=} [verifyCache=false] If `true` then a result is immediately returned from cache   *   (if present) while a request is sent to the server for a fresh response that will update the   *   cached entry. The `success` function will be called when the response is received. @@ -55,9 +55,9 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $error, $log) {        if (dataCached = cache.data[url]) {          if (sync) { -          success(200, copy(dataCached.value)); +          success(200, copy(dataCached.value), copy(dataCached.headers));          } else { -          $defer(function() { success(200, copy(dataCached.value)); }); +          $defer(function() { success(200, copy(dataCached.value), copy(dataCached.headers)); });          }          if (!verifyCache) @@ -70,20 +70,20 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $error, $log) {        } else {          inflight[url] = {successes: [success], errors: [error]};          cache.delegate(method, url, post, -          function(status, response) { +          function(status, response, responseHeaders) {              if (status == 200) -              cache.data[url] = {value: response}; +              cache.data[url] = {value: response, headers: responseHeaders};              var successes = inflight[url].successes;              delete inflight[url];              forEach(successes, function(success) {                try { -                (success||noop)(status, copy(response)); +                (success||noop)(status, copy(response), responseHeaders);                } catch(e) {                  $log.error(e);                }              });            }, -          function(status, response) { +          function(status, response, responseHeaders) {              var errors = inflight[url].errors,                  successes = inflight[url].successes;              delete inflight[url]; @@ -91,7 +91,7 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $error, $log) {              forEach(errors, function(error, i) {                try {                  if (isFunction(error)) { -                  error(status, copy(response)); +                  error(status, copy(response), copy(responseHeaders));                  } else {                    $error(                      {method: method, url: url, data: post, success: successes[i]}, diff --git a/src/service/xhr.js b/src/service/xhr.js index 70fcd067..6bff6f04 100644 --- a/src/service/xhr.js +++ b/src/service/xhr.js @@ -96,7 +96,7 @@   *   angular generated callback function.   * @param {(string|Object)=} post Request content as either a string or an object to be stringified   *   as JSON before sent to the server. - * @param {function(number, (string|Object))} success A function to be called when the response is + * @param {function(number, (string|Object), Function)} success A function to be called when the response is   *   received. The success function will be called with:   *   *   - {number} code [HTTP status code](http://en.wikipedia.org/wiki/List_of_HTTP_status_codes) of @@ -104,6 +104,9 @@   *     {@link angular.service.$xhr.error} service (or custom error callback).   *   - {string|Object} response Response object as string or an Object if the response was in JSON   *     format. + *   - {function(string=)} responseHeaders A function that when called with a {string} header name, + *     returns the value of that header or null if it does not exist; when called without + *     arguments, returns an object containing every response header   * @param {function(number, (string|Object))} error A function to be called if the response code is   *   not 2xx.. Accepts the same arguments as success, above.   * @@ -198,7 +201,7 @@ angularServiceInject('$xhr', function($browser, $error, $log, $updateView){        post = toJson(post);      } -    $browser.xhr(method, url, post, function(code, response){ +    $browser.xhr(method, url, post, function(code, response, responseHeaders){        try {          if (isString(response)) {            if (response.match(/^\)\]\}',\n/)) response=response.substr(6); @@ -207,9 +210,9 @@ angularServiceInject('$xhr', function($browser, $error, $log, $updateView){            }          }          if (200 <= code && code < 300) { -          success(code, response); +          success(code, response, responseHeaders);          } else if (isFunction(error)) { -          error(code, response); +          error(code, response, responseHeaders);          } else {            $error(              {method: method, url: url, data: post, success: success}, diff --git a/test/BrowserSpecs.js b/test/BrowserSpecs.js index 92e4e501..93882c1a 100644 --- a/test/BrowserSpecs.js +++ b/test/BrowserSpecs.js @@ -49,6 +49,13 @@ describe('browser', function(){        this.send = function(post){          xhr.post = post;        }; +      this.getResponseHeader = function(header) { +        return header; +      }; +      this.getAllResponseHeaders = function() { +        return 'Content-Type: application/json\n\rContent-Encoding: gzip\n\rContent-Type: text/json'; +      } +      };      logs = {log:[], warn:[], info:[], error:[]}; @@ -198,6 +205,41 @@ describe('browser', function(){        expect(code).toEqual(202);        expect(response).toEqual('RESPONSE');      }); + +    describe('response headers', function() { +      it('should return a single response header', function() { +        var headerA; + +        browser.xhr('GET', 'URL', null, function(code, resp, headers) { +          headerA = headers('A-Header'); +        }); + +        xhr.status = 200; +        xhr.responseText = 'RESPONSE'; +        xhr.readyState = 4; +        xhr.onreadystatechange(); + +        expect(headerA).toEqual('a-header'); +      }); + +      it('should return an object containing all response headers', function() { +        var allHeaders; + +        browser.xhr('GET', 'URL', null, function(code, resp, headers) { +          allHeaders = headers(); +        }); + +        xhr.status = 200; +        xhr.responseText = 'RESPONSE'; +        xhr.readyState = 4; +        xhr.onreadystatechange(); + +        expect(allHeaders).toEqual({ +          'content-type': 'application/json, text/json', +          'content-encoding': 'gzip' +        }); +      }); +    });    });    describe('defer', function() { diff --git a/test/ResourceSpec.js b/test/ResourceSpec.js index 7bba9357..a143fc0e 100644 --- a/test/ResourceSpec.js +++ b/test/ResourceSpec.js @@ -83,7 +83,8 @@ describe("resource", function() {      expect(callback).not.toHaveBeenCalled();      xhr.flush();      nakedExpect(cc).toEqual({id:123, name:'misko'}); -    expect(callback).toHaveBeenCalledWith(cc); +    expect(callback.mostRecentCall.args[0]).toEqual(cc); +    expect(callback.mostRecentCall.args[1]()).toEqual({});    });    it("should read resource", function(){ @@ -94,7 +95,8 @@ describe("resource", function() {      expect(callback).not.toHaveBeenCalled();      xhr.flush();      nakedExpect(cc).toEqual({id:123, number:'9876'}); -    expect(callback).toHaveBeenCalledWith(cc); +    expect(callback.mostRecentCall.args[0]).toEqual(cc); +    expect(callback.mostRecentCall.args[1]()).toEqual({});    });    it("should read partial resource", function(){ @@ -108,7 +110,8 @@ describe("resource", function() {      expect(cc.number).not.toBeDefined();      cc.$get(callback);      xhr.flush(); -    expect(callback).toHaveBeenCalledWith(cc); +    expect(callback.mostRecentCall.args[0]).toEqual(cc); +    expect(callback.mostRecentCall.args[1]()).toEqual({});      expect(cc.number).toEqual('9876');    }); @@ -129,7 +132,8 @@ describe("resource", function() {      expect(callback).not.toHaveBeenCalled();      xhr.flush();      nakedExpect(ccs).toEqual([{id:1}, {id:2}]); -    expect(callback).toHaveBeenCalledWith(ccs); +    expect(callback.mostRecentCall.args[0]).toEqual(ccs); +    expect(callback.mostRecentCall.args[1]()).toEqual({});    });    it("should have all arguments optional", function(){ @@ -147,14 +151,16 @@ describe("resource", function() {      CreditCard.remove({id:123}, callback);      expect(callback).not.toHaveBeenCalled();      xhr.flush(); -    nakedExpect(callback.mostRecentCall.args).toEqual([{}]); +    nakedExpect(callback.mostRecentCall.args[0]).toEqual({}); +    nakedExpect(callback.mostRecentCall.args[1]()).toEqual({});      callback.reset();      xhr.expectDELETE("/CreditCard/333").respond(204, null);      CreditCard.remove({id:333}, callback);      expect(callback).not.toHaveBeenCalled();      xhr.flush(); -    nakedExpect(callback.mostRecentCall.args).toEqual([{}]); +    nakedExpect(callback.mostRecentCall.args[0]).toEqual({}); +    nakedExpect(callback.mostRecentCall.args[1]()).toEqual({});    });    it('should post charge verb', function(){ @@ -171,7 +177,7 @@ describe("resource", function() {    });    it('should create on save', function(){ -    xhr.expectPOST('/CreditCard', {name:'misko'}).respond({id:123}); +    xhr.expectPOST('/CreditCard', {name:'misko'}).respond({id: 123}, {foo: 'bar'});      var cc = new CreditCard();      expect(cc.$get).toBeDefined();      expect(cc.$query).toBeDefined(); @@ -183,7 +189,9 @@ describe("resource", function() {      nakedExpect(cc).toEqual({name:'misko'});      xhr.flush();      nakedExpect(cc).toEqual({id:123}); -    expect(callback).toHaveBeenCalledWith(cc); +    expect(callback.mostRecentCall.args[0]).toEqual(cc); +    expect(callback.mostRecentCall.args[1]('foo')).toEqual('bar'); +    expect(callback.mostRecentCall.args[1]()).toEqual({foo: 'bar'});    });    it('should not mutate the resource object if response contains no body', function(){ @@ -245,10 +253,15 @@ describe("resource", function() {    describe('failure mode', function() {      var ERROR_CODE = 500,          ERROR_RESPONSE = 'Server Error', -        errorCB; +        errorCB, +        headersFn;      beforeEach(function() { -      errorCB = jasmine.createSpy(); +      errorCB = jasmine.createSpy().andCallFake(function(code, response, headers) { +        headersFn = headers; +      }); + +      xhr.expectGET('/CreditCard/123').respond(ERROR_CODE, ERROR_RESPONSE, {foo: 'bar'});      });      it('should report error when non 2xx if error callback is not provided', function() { @@ -262,16 +275,19 @@ describe("resource", function() {        xhr.expectGET('/CreditCard/123').respond(ERROR_CODE, ERROR_RESPONSE);        CreditCard.get({id:123}, callback, errorCB);        xhr.flush(); -      expect(errorCB).toHaveBeenCalledWith(500, ERROR_RESPONSE); +      expect(errorCB).toHaveBeenCalledWith(500, ERROR_RESPONSE, headersFn);        expect(callback).not.toHaveBeenCalled();        expect($xhrErr).not.toHaveBeenCalled();      });      it('should call the error callback if provided on non 2xx response', function() { -      xhr.expectGET('/CreditCard').respond(ERROR_CODE, ERROR_RESPONSE); +      xhr.expectGET('/CreditCard').respond(ERROR_CODE, ERROR_RESPONSE, {foo: 'bar'});        CreditCard.get(callback, errorCB);        xhr.flush(); -      expect(errorCB).toHaveBeenCalledWith(500, ERROR_RESPONSE); +      expect(errorCB).toHaveBeenCalledWith(500, ERROR_RESPONSE, headersFn); +      expect(headersFn('foo')).toBe('bar'); +      expect(headersFn()).toEqual({'foo': 'bar'}); +        expect(callback).not.toHaveBeenCalled();        expect($xhrErr).not.toHaveBeenCalled();      }); diff --git a/test/service/xhr.bulkSpec.js b/test/service/xhr.bulkSpec.js index adcb61fa..c278fa50 100644 --- a/test/service/xhr.bulkSpec.js +++ b/test/service/xhr.bulkSpec.js @@ -18,8 +18,9 @@ describe('$xhr.bulk', function() {    }); -  function callback(code, response) { +  function callback(code, response, responseHeaders) {      expect(code).toEqual(200); +    expect(responseHeaders()).toEqual({});      log = log + toJson(response) + ';';    } @@ -81,6 +82,8 @@ describe('$xhr.bulk', function() {      $browserXhr.flush();      expect($xhrError).not.toHaveBeenCalled(); -    expect(callback).toHaveBeenCalledWith(404, 'NotFound'); +    expect(callback.mostRecentCall.args[0]).toEqual(404); +    expect(callback.mostRecentCall.args[1]).toEqual('NotFound'); +    expect(callback.mostRecentCall.args[2]()).toEqual({});    });  }); diff --git a/test/service/xhr.cacheSpec.js b/test/service/xhr.cacheSpec.js index f4654cd4..cd42153f 100644 --- a/test/service/xhr.cacheSpec.js +++ b/test/service/xhr.cacheSpec.js @@ -1,7 +1,7 @@  'use strict';  describe('$xhr.cache', function() { -  var scope, $browser, $browserXhr, $xhrErr, cache, log; +  var scope, $browser, $browserXhr, $xhrErr, cache, log, rHeaders;    beforeEach(function() {      scope = angular.scope({}, null, {'$xhr.error': $xhrErr = jasmine.createSpy('$xhr.error')}); @@ -9,6 +9,7 @@ describe('$xhr.cache', function() {      $browserXhr = $browser.xhr;      cache = scope.$service('$xhr.cache');      log = ''; +    rHeaders = {};    }); @@ -17,18 +18,21 @@ describe('$xhr.cache', function() {    }); -  function callback(code, response) { +  function callback(code, response, responseHeaders) {      expect(code).toEqual(200); +    expect(responseHeaders()).toEqual(rHeaders);      log = log + toJson(response) + ';';    }    it('should cache requests', function(){ -    $browserXhr.expectGET('/url').respond('first'); +    rHeaders = {foo: 'bar'}; + +    $browserXhr.expectGET('/url').respond('first', rHeaders);      cache('GET', '/url', null, callback);      $browserXhr.flush(); -    $browserXhr.expectGET('/url').respond('ERROR'); +    $browserXhr.expectGET('/url').respond('ERROR', rHeaders);      cache('GET', '/url', null, callback);      $browser.defer.flush();      expect(log).toEqual('"first";"first";'); @@ -40,11 +44,13 @@ describe('$xhr.cache', function() {    it('should first return cache request, then return server request', function(){ -    $browserXhr.expectGET('/url').respond('first'); +    rHeaders = {foo: 'bar'}; + +    $browserXhr.expectGET('/url').respond('first', rHeaders);      cache('GET', '/url', null, callback, true);      $browserXhr.flush(); -    $browserXhr.expectGET('/url').respond('ERROR'); +    $browserXhr.expectGET('/url').respond('ERROR', rHeaders);      cache('GET', '/url', null, callback, true);      $browser.defer.flush();      expect(log).toEqual('"first";"first";'); @@ -55,7 +61,14 @@ describe('$xhr.cache', function() {    it('should serve requests from cache', function(){ -    cache.data.url = {value:'123'}; +    rHeaders = {foo: 'bar'}; + +    cache.data.url = { +      value: '123', +      headers: function() { +        return rHeaders; +      } +    };      cache('GET', 'url', null, callback);      $browser.defer.flush();      expect(log).toEqual('"123";'); @@ -152,13 +165,17 @@ describe('$xhr.cache', function() {      cache('GET', '/url', null, successSpy, errorSpy, false, true);      $browserXhr.flush(); -    expect(errorSpy).toHaveBeenCalledWith(500, 'error'); +    expect(errorSpy.mostRecentCall.args[0]).toEqual(500); +    expect(errorSpy.mostRecentCall.args[1]).toEqual('error'); +    expect(errorSpy.mostRecentCall.args[2]()).toEqual({});      expect(successSpy).not.toHaveBeenCalled();      errorSpy.reset();      cache('GET', '/url', successSpy, errorSpy, false, true);      $browserXhr.flush(); -    expect(errorSpy).toHaveBeenCalledWith(500, 'error'); +    expect(errorSpy.mostRecentCall.args[0]).toEqual(500); +    expect(errorSpy.mostRecentCall.args[1]).toEqual('error'); +    expect(errorSpy.mostRecentCall.args[2]()).toEqual({});      expect(successSpy).not.toHaveBeenCalled();    }); diff --git a/test/service/xhrSpec.js b/test/service/xhrSpec.js index 9f496535..12ee614d 100644 --- a/test/service/xhrSpec.js +++ b/test/service/xhrSpec.js @@ -18,15 +18,16 @@ describe('$xhr', function() {    }); -  function callback(code, response) { -    log = log + '{code=' + code + '; response=' + toJson(response) + '}'; +  function callback(code, response, responseHeader) { +    log = log + '{code=' + code + '; response=' + toJson(response) + '; responseHeaders=' + +        toJson(responseHeader()) + '}';    }    it('should forward the request to $browser and decode JSON', function(){ -    $browserXhr.expectGET('/reqGET').respond('first'); -    $browserXhr.expectGET('/reqGETjson').respond('["second"]'); -    $browserXhr.expectPOST('/reqPOST', {post:'data'}).respond('third'); +    $browserXhr.expectGET('/reqGET').respond('first', {h: 'first'}); +    $browserXhr.expectGET('/reqGETjson').respond('["second"]', {h: 'second'}); +    $browserXhr.expectPOST('/reqPOST', {post:'data'}).respond('third', {h: 'third'});      $xhr('GET', '/reqGET', null, callback);      $xhr('GET', '/reqGETjson', null, callback); @@ -35,23 +36,23 @@ describe('$xhr', function() {      $browserXhr.flush();      expect(log).toEqual( -        '{code=200; response="third"}' + -        '{code=200; response=["second"]}' + -        '{code=200; response="first"}'); +        '{code=200; response="third"; responseHeaders={"h":"third"}}' + +        '{code=200; response=["second"]; responseHeaders={"h":"second"}}' + +        '{code=200; response="first"; responseHeaders={"h":"first"}}');    });    it('should allow all 2xx requests', function(){ -    $browserXhr.expectGET('/req1').respond(200, '1'); +    $browserXhr.expectGET('/req1').respond(200, '1', {h: '1'});      $xhr('GET', '/req1', null, callback);      $browserXhr.flush(); -    $browserXhr.expectGET('/req2').respond(299, '2'); +    $browserXhr.expectGET('/req2').respond(299, '2', {h: '2'});      $xhr('GET', '/req2', null, callback);      $browserXhr.flush();      expect(log).toEqual( -        '{code=200; response="1"}' + -        '{code=299; response="2"}'); +        '{code=200; response="1"; responseHeaders={"h":"1"}}' + +        '{code=299; response="2"; responseHeaders={"h":"2"}}');    }); @@ -120,18 +121,24 @@ describe('$xhr', function() {      var errorSpy = jasmine.createSpy('error'),          successSpy = jasmine.createSpy('success'); -    $browserXhr.expectGET('/url').respond(500, 'error'); +    $browserXhr.expectGET('/url').respond(500, 'error', {foo: 'bar'});      $xhr('GET', '/url', null, successSpy, errorSpy);      $browserXhr.flush(); -    expect(errorSpy).toHaveBeenCalledWith(500, 'error'); +    expect(errorSpy.mostRecentCall.args[0]).toEqual(500); +    expect(errorSpy.mostRecentCall.args[1]).toEqual('error'); +    expect(errorSpy.mostRecentCall.args[2]('foo')).toEqual('bar'); +    expect(errorSpy.mostRecentCall.args[2]()).toEqual({foo: 'bar'});      expect(successSpy).not.toHaveBeenCalled();      errorSpy.reset();      $xhr('GET', '/url', successSpy, errorSpy);      $browserXhr.flush(); -    expect(errorSpy).toHaveBeenCalledWith(500, 'error'); +    expect(errorSpy.mostRecentCall.args[0]).toEqual(500); +    expect(errorSpy.mostRecentCall.args[1]).toEqual('error'); +    expect(errorSpy.mostRecentCall.args[2]('foo')).toEqual('bar'); +    expect(errorSpy.mostRecentCall.args[2]()).toEqual({foo: 'bar'});      expect(successSpy).not.toHaveBeenCalled();    }); | 
