jeudi 22 janvier 2015

angular-mocks.js v1.3.6 - Can't get $htttpBackend to mock my service call

(Thanks in advance if you have time to look at this, I might have to give up on using the nice unit test features in Angular if I can't resolve it :( )


I'm learning angularjs ("on the job") and am quite pleased with it so far.


I am now looking at writing unit tests for a controller we have developed using Jasmine and Karma.


I have managed to write some basic tests (that do not use $httpBackend) successfully.


I have looked at loads of examples on the net and on this site, but I just can't work out what I am doing wrong.


My controller will perform a JSON search when a button is clicked...



app.controller('PriceSearchCtrl', function ($scope, $http, $window) {
...
// Do the search
$scope.performSearch = function() {
var response = $http({
method: 'POST',
url: 'performSearch.json',
data: $scope.search,
headers: {
'Content-Type': 'application/json'
}
});
response.success(function (data) {
$scope.response = data;
$scope.currentTab = 'response';
$window.scrollTo(0,0);
});
response.error(function() {
$scope.response = "REQUEST FAILED";
$scope.currentTab = 'response';
$window.scrollTo(0,0);
});
}
...
}));


This works fine when running for real, now I wanted to test it so I added this test to my currently passing spec...



...<other tests that are running fine>...

describe('Price Search', function() {
afterEach(function() {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});

it('should POST search to backend service and set the result', function() {
var expectedResponse = {
"success": true,
"searchResults": { hello: 'world'}
};

$httpBackend.when('POST', 'performSearch.json', $scope.search, { 'Content-Type': 'application/json'}).respond(function() { return expectedResponse; });

$scope.performSearch();

$httpBackend.flush();
expect($scope.response).toEqual(expectedResponse);
});
});


(The reason I am having to set request headers is because elsewhere we have set $httpProvider.defaults.headers.post['Content-Type'] to something else for other controllers)


When run, I get an error like this...



Error: Unexpected request: [object Object] undefined
No more request expected in C:/dev/web/src/test/angularjs/angular-mocks.js (line 1253)
$httpBackend@C:/dev/web/src/test/angularjs/angular-mocks.js:1253:1
$scope.performSearch@C:/dev/web/src/main/webapp/js/controllers.js:9:7746
@C:/dev/web/src/test/angularjs/unit/search.test.js:130:4


I wanted to try and find out myself what is going on, so I added some "console.log" lines to the following place in "angular-mocks.js"...


(start line = 1156)



// TODO(vojta): change params to: method, url, data, headers, callback
function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
// BEGIN STUFF I ADDED
console.log("DUMP-PARAMS");
console.log(method);
console.log(url);
console.log(data);
console.log(callback);
console.log(headers);
console.log(timeout);
console.log(withCredentials);
console.log("END-DUMP-PARAMS");
// END STUFF I ADDED


Now when I run, I see that the following is logged...



LOG: Object{method: 'POST', url: 'performSearch.json', data: Object{searchType: 'PAX', effectiveDate: '22/1/2015', checkIn: '29/1/2015', checkOut: '1/2/2015', country: 'GB', currency: 'GBP', language: 'en', siteId: 1, clientId: 1, includeCancellationConditions: true, includePriceBreakdown: true, includeLog: true, roomRequirements: [...]}, headers: Object{Content-Type: 'application/json'}}
LOG: undefined
LOG: undefined
LOG: undefined
LOG: undefined
LOG: undefined
LOG: undefined
LOG: 'END-DUMP-PARAMS'


So it looks like all of the information ends up as an object in the "method" field (!!???!)


Out of pure frustration, I altered the method signature and added another block...



// TODO(vojta): change params to: method, url, data, headers, callback
// BAC: CHANGED PARAMS FROM (method, url, data, callback, headers, timeout, withCredentials) {
function $httpBackend(obj) {
// STUFF I ADDED
var method = obj.method;
var url = obj.url;
var data = obj.data;
var callback = obj.callback;
var headers = obj.headers;
var timeout = obj.timeout;
var withCredentials = obj.withCredentials;

console.log("DUMP-PARAMS");
console.log(method);
console.log(url);
console.log(data);
console.log(callback);
console.log(headers);
console.log(timeout);
console.log(withCredentials);
console.log("END-DUMP-PARAMS");
// END STUFF I ADDED


Now I get...



LOG: 'DUMP-PARAMS'
LOG: 'POST'
LOG: 'performSearch.json'
LOG: Object{searchType: 'PAX', effectiveDate: '22/1/2015', checkIn: '29/1/2015', checkOut: '1/2/2015', country: 'GB', currency: 'GBP', language: 'en', siteId: 1, clientId: 1, includeCancellationConditions: true, includePriceBreakdown: true, includeLog: true, roomRequirements: [Object{requestIndex: ..., occupancy: ...}]}
LOG: undefined
LOG: Object{Content-Type: 'application/json'}
LOG: undefined
LOG: undefined
LOG: 'END-DUMP-PARAMS'

TypeError: response is undefined in /.../controllers.js (line 9)


It looks to me like angular-mocks.js V1.3.6 is wrong, but this is probably just me going mad...


I can confirm that I do not have any version mismatches of angular + angualr-mock.. . Help!!


Aucun commentaire:

Enregistrer un commentaire