Skip to content

Commit

Permalink
test(HttpResponseMessage) add testing for HttpResponseMessage
Browse files Browse the repository at this point in the history
Also seperated out header parsing to a static method of headers.
This makes testing slightly easier and it also feels like it belongs to headers.
  • Loading branch information
andrew-w-ross committed Feb 24, 2015
1 parent 91dda8a commit 01afa7a
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 61 deletions.
6 changes: 5 additions & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ module.exports = function(config) {

jspm: {
// Edit this to your needs
loadFiles: ['src/**/*.js', 'test/**/*.js']
loadFiles: ['test/**/*.js'],
serveFiles : ['src/**/*.js']
},


Expand All @@ -38,6 +39,9 @@ module.exports = function(config) {
sourceMap: 'inline',
modules: 'system',
moduleIds: false
},
sourceFileName : function(file){
return file.path.replace(/.+\//,'');
}
},

Expand Down
28 changes: 28 additions & 0 deletions src/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,32 @@ export class Headers {
xhr.setRequestHeader(key, headers[key]);
}
}

/**
* XmlHttpRequest's getAllResponseHeaders() method returns a string of response
* headers according to the format described here:
* http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-method
* This method parses that string into a user-friendly key/value pair object.
*/
static parse(headerStr){
var headers = new Headers();
if (!headerStr) {
return headers;
}

var headerPairs = headerStr.split('\u000d\u000a');
for (var i = 0; i < headerPairs.length; i++) {
var headerPair = headerPairs[i];
// Can't use split() here because it does the wrong thing
// if the header value has the string ": " in it.
var index = headerPair.indexOf('\u003a\u0020');
if (index > 0) {
var key = headerPair.substring(0, index);
var val = headerPair.substring(index + 2);
headers.add(key,val);
}
}

return headers;
}
}
30 changes: 1 addition & 29 deletions src/http-response-message.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,5 @@
import {Headers} from './headers';

/**
* XmlHttpRequest's getAllResponseHeaders() method returns a string of response
* headers according to the format described here:
* http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-method
* This method parses that string into a user-friendly key/value pair object.
*/
function parseResponseHeaders(headerStr) {
var headers = {};
if (!headerStr) {
return headers;
}

var headerPairs = headerStr.split('\u000d\u000a');
for (var i = 0; i < headerPairs.length; i++) {
var headerPair = headerPairs[i];
// Can't use split() here because it does the wrong thing
// if the header value has the string ": " in it.
var index = headerPair.indexOf('\u003a\u0020');
if (index > 0) {
var key = headerPair.substring(0, index);
var val = headerPair.substring(index + 2);
headers[key] = val;
}
}

return headers;
}

export class HttpResponseMessage {
constructor(requestMessage, xhr, responseType, reviver){
this.requestMessage = requestMessage;
Expand All @@ -39,7 +11,7 @@ export class HttpResponseMessage {
this.reviver = reviver;

if(xhr.getAllResponseHeaders){
this.headers = new Headers(parseResponseHeaders(xhr.getAllResponseHeaders()));
this.headers = Headers.parse(xhr.getAllResponseHeaders());
}else {
this.headers = new Headers();
}
Expand Down
86 changes: 55 additions & 31 deletions test/headers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,69 @@ import {Headers} from '../src/index';

describe('headers', () => {

it('can add header value', () => {
var headers = new Headers();
headers.add('Authorization', '123');
it('can add header value', () => {
var headers = new Headers();
headers.add('Authorization', '123');

expect(headers.headers['Authorization']).toBe('123');
});
expect(headers.headers['Authorization']).toBe('123');
});

it('can get header value', () => {
var headers = new Headers();
headers.add('Authorization', '123');
it('can get header value', () => {
var headers = new Headers();
headers.add('Authorization', '123');

expect(headers.get('Authorization')).toBe('123');
});

it('will clear headers on clear', () => {
var headers = new Headers();
headers.add('Authorization', '123');
expect(headers.get('Authorization')).toBe('123');
});

expect(headers.get('Authorization')).toBe('123');
it('will clear headers on clear', () => {
var headers = new Headers();
headers.add('Authorization', '123');

headers.clear();
expect(headers.get('Authorization')).toBe('123');

expect(headers.get('Authorization')).toBeUndefined();
expect(headers.headers).toEqual({});
});
headers.clear();

it('configureXHR should add the headers', () =>{
var headers = new Headers();
headers.add('Authorization', '123');
headers.add('Content-Type', 'application/json');
expect(headers.get('Authorization')).toBeUndefined();
expect(headers.headers).toEqual({});
});

jasmine.Ajax.withMock(() => {
var xhr = new XMLHttpRequest();
it('configureXHR should add the headers', () => {
var headers = new Headers();
headers.add('Authorization', '123');
headers.add('Content-Type', 'application/json');

headers.configureXHR(xhr);
jasmine.Ajax.withMock(() => {
var xhr = new XMLHttpRequest();

expect(xhr.requestHeaders['Authorization']).toBe('123');
expect(xhr.requestHeaders['Content-Type']).toBe('application/json');
});
});
headers.configureXHR(xhr);

});
expect(xhr.requestHeaders['Authorization']).toBe('123');
expect(xhr.requestHeaders['Content-Type']).toBe('application/json');
});


});

describe("parse()", () => {
it("should return a new instance on undefined, null or empty string", () => {
expect(Headers.parse()).toEqual(jasmine.any(Headers));
expect(Headers.parse(null)).toEqual(jasmine.any(Headers));
expect(Headers.parse("")).toEqual(jasmine.any(Headers));
});

it("should parse header strings", () => {
let headers = Headers.parse('key1: value1\u000d\u000akey2: value2');

expect(headers.get('key1')).toBe('value1');
expect(headers.get('key2')).toBe('value2');
});

it("should parse headers with values of ': '", () => {
let headers = Headers.parse('key1: value1\u000d\u000akey2: key: value');

expect(headers.get('key1')).toBe('value1');
expect(headers.get('key2')).toBe('key: value');
});
});

});
115 changes: 115 additions & 0 deletions test/http-response-message.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import {HttpResponseMessage} from '../src/http-response-message';
import {Headers} from '../src/headers';

describe("HttpResponseMessage", () => {

describe("constructor", () => {
it("should have a isSuccess defined by the xhr.status", () => {
//1xx informal
expect(new HttpResponseMessage({}, {status: 100}).isSuccess).toBeFalsy();
expect(new HttpResponseMessage({}, {status: 199}).isSuccess).toBeFalsy();

//2xx success
expect(new HttpResponseMessage({}, {status: 200}).isSuccess).toBeTruthy();
expect(new HttpResponseMessage({}, {status: 299}).isSuccess).toBeTruthy();

//3xx redirection
expect(new HttpResponseMessage({}, {status: 300}).isSuccess).toBeTruthy();
expect(new HttpResponseMessage({}, {status: 399}).isSuccess).toBeTruthy();

//4xx client error
expect(new HttpResponseMessage({}, {status: 400}).isSuccess).toBeFalsy();
expect(new HttpResponseMessage({}, {status: 499}).isSuccess).toBeFalsy();

//5xx server error
expect(new HttpResponseMessage({}, {status: 400}).isSuccess).toBeFalsy();
expect(new HttpResponseMessage({}, {status: 499}).isSuccess).toBeFalsy();
});

//This may seem superfluous but it's surprising how many bugs stem from constructors no longer working as expected
it("have the xhr.status, xhr.response, xhr.statusText, responseType, reviver and headers as fields", () => {
//Everything that can be an object is set to one for reference checking
let xhr = {status: 200, response: {}, statusText: {}};
let responseType = {}, reviver = {}, requestMessage = {};
let httpResponse = new HttpResponseMessage(requestMessage, xhr, responseType, reviver);

expect(httpResponse.requestMessage).toBe(requestMessage);
expect(httpResponse.statusCode).toBe(xhr.status);
expect(httpResponse.response).toBe(xhr.response);
expect(httpResponse.statusText).toBe(xhr.statusText);
expect(httpResponse.responseType).toBe(responseType);
expect(httpResponse.reviver).toBe(reviver);
expect(httpResponse.headers).toEqual(jasmine.any(Headers));
});

it("will call the Headers.parse() if xhr.getAllResponseHeaders() is defined", () => {
let parseSpy = spyOn(Headers, 'parse');
let xhrMock = jasmine.createSpyObj("xhr", ["getAllResponseHeaders"]);
xhrMock.getAllResponseHeaders.and.returnValue("");

let httpResponse = new HttpResponseMessage({}, xhrMock);
expect(xhrMock.getAllResponseHeaders).toHaveBeenCalled();
expect(parseSpy).toHaveBeenCalledWith("");
});
});

describe("content", () => {
it("will return _content if defined", () => {
let httpResponse = new HttpResponseMessage(null,{});
let _content = httpResponse._content = {};

expect(httpResponse.content).toBe(_content);
});

it("will return undefined if response is undefined", () => {
let httpResponse = new HttpResponseMessage(null, {});
expect(httpResponse.content).toBeUndefined();
});

it("will return null if response is null", () => {
let httpResponse = new HttpResponseMessage(null, {response: null});
expect(httpResponse.content).toBeNull();
});

it("will JSON.parse if the response type is 'json'", () => {
let response = {}, reviver = {}, content = {};
let parseSpy = spyOn(JSON, 'parse').and.returnValue(content);
let httpResponse = new HttpResponseMessage(null, {response: response}, 'json', reviver);

expect(httpResponse.content).toBe(content);
expect(parseSpy).toHaveBeenCalledWith(response, reviver);
});

it("will call the reviver if the response type is not 'json' and the reviver is defined", () => {
let response = {};
let reviverSpy = jasmine.createSpy("reviver").and.returnValue(response);
let httpResponse = new HttpResponseMessage(null, {response: response}, 'notJson', reviverSpy);

expect(httpResponse.content).toBe(response);
expect(reviverSpy).toHaveBeenCalledWith(response);
});

it("will return the response if the reviver is not set and the response type is not json", () => {
let response = {};
let httpResponse = new HttpResponseMessage(null, {response: response}, 'notJson');

expect(httpResponse.content).toBe(response);
});

it("will catch expections on content if the response was not successful", () => {
let reviverSpy = jasmine.createSpy("reviver").and.throwError();
let httpResponse = new HttpResponseMessage(null, {status : 404, response : {}}, 'notJson', reviverSpy);

expect(httpResponse.content).toBeNull();
expect(reviverSpy).toHaveBeenCalled();
});

it("will throw on content if the response was successful", () => {
let reviverSpy = jasmine.createSpy("reviver").and.throwError();
let httpResponse = new HttpResponseMessage(null, {status : 200, response : {}}, 'notJson', reviverSpy);

expect(() => httpResponse.content).toThrow();
expect(reviverSpy).toHaveBeenCalled();
});
});
});

0 comments on commit 01afa7a

Please sign in to comment.