flanger001 flanger001 - 5 months ago 30
AngularJS Question

Does Angular $httpBackend whenPUT() behave differently than whenGET()?

I am writing the beginning of an Angular service that will consume an API, and I started with stubbing out all the request actions. Nothing actually happens with this service yet; it's basically a wrapper for

$http
. I'm running into an interesting problem with the tests for this: I have mocked out a
PUT
request that doesn't seem to work as I expect it to, and I'm wondering where my understanding has failed.

Essentially, when I check for
observation.get(1)
, the request is mocked correctly and the test passes. But if I do
observation.update({'some_key': 'some_value'})
, I get this error:

Chrome 51.0.2704 (Mac OS X 10.11.5) Observation responds to #save FAILED
Error: No response defined !


I think I have defined a response in the beforeEach() function body, yet the spec still fails. It seems strange that every other test for this passes using the exact same syntax. What am I doing wrong?

Class (yay for ES6)



class Observation {
constructor($http, AppSettings) {
'ngInject';
Object.assign(this, {$http, AppSettings});
this.headers = {
'Authorization': 'Token token=myfancytoken'
};
this.endpoint = `${this.AppSettings.API_URL}/api/${this.AppSettings.API_VERSION}/observations`;
}

get(id) {
this.id = id;
let params = {
url: `${this.endpoint}/${this.id}.json`,
method: 'GET'
};
return this.request(params);
}

save(data) {
if (typeof this.id === 'undefined') {
throw {message: 'Cannot save object without an id'};
}
let params = {
url: `${this.endpoint}/${this.id}.json`,
method: 'PUT',
data: data
};
return this.request(params);
}

request(params) {
Object.assign(params, {headers: this.headers});
return this.$http(params)
.then((response) => { return response.data; })
.catch((response) => { return response.status; });
}

/*
* Other actions omitted for brevity
*/
}

export default Observation;


Spec



import Observation from './observation';

describe('Observation', () => {
let $httpBackend, AppSettings, observation, $http, obj, successResponse;

beforeEach(() => {
AppSettings = {
"API_URL": 'http://localhost:3000',
'API_VERSION': 'v1'
};

inject(($injector) => {
$httpBackend = $injector.get('$httpBackend');
$http = $injector.get('$http');
});

observation = new Observation($http, AppSettings);

successResponse = (response) => {
obj = response.data;
};

/* Mock the backend */

// GET #show
$httpBackend
.when('GET', `${observation.endpoint}/1.json`)
.respond(200, {data: {}});

// PUT #save
// FIXME: Not working for some reason and needs to be defined in the test itself?
$httpBackend
.when('PUT', `${observation.endpoint}/${observation.id}.json`)
.respond(200, {data: {'id': 1}});
});

afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});


it('responds to #get', () => {
observation
.get(1)
.then(successResponse);

$httpBackend.expect('GET', `${observation.endpoint}/1.json`)
$httpBackend.flush();

expect(obj).toEqual({});
});

/* Other test cases omitted for brevity */

it('responds to #save', () => {
observation.id = 1;
observation
.save({'first_name': 'Lisa'})
.then(successResponse);

// FIXME: Why doesn't this work?
$httpBackend
.expect('PUT', `${observation.endpoint}/${observation.id}.json`);
// .respond(200, {data: {'id': 1}});
$httpBackend.flush();

expect(obj.id).toBe(1);
});

it('throws an error if #save is called without an id on the object', () => {
expect(() => {observation.save()}).toThrowError(Error, 'Cannot save object without an id');
});

});

Answer
$httpBackend
  .when('PUT', `${observation.endpoint}/${observation.id}.json`)

At this point observation has no id.