问题
I am testing a controller using a combination of angular and jasmine, and am not completely sure about using deffered promises.
This is my spec code.
describe('Controller Tests', function(){
var scope, searchAPI;
beforeEach(function(){
var mockSearchAPI = {};
module('myApp', function($provide){
$provide.value('searchAPI', mockSearchAPI);
});
});
inject(function($q){
var testData = {"message":"hi"};
mockSearchAPI.executeSearch = function(){
var defer = $q.defer();
defer.resolve(testData);
return defer.promise;
};
});
beforeEach('Main Search Controller Tests', function(){
function($controller, $rootScope, _searchAPI_){
scope = $rootScope.$new();
searchAPI = _searchAPI_;
$controller('MainSearchCtrl', function(){
$scope: scope,
searchAPI: searchAPI
});
scope.$digest();
}
});
it('should return a promise correctly', function(){
var field = "testfield";
var value = "testvalue";
var pageNumber = 1;
var promise = scope.processQueryByField(field, value, pageNumber);
//THIS LINE IS GIVING ME '{}'
alert(promise);
});
});
I am unsure why the line that I am "alerting" is giving me output of '{}'. Shouldn't it be the data struct that I defined as "testData" in the inject function? I am not sure what is going on here. I have tried numerous solutions.
My controller code is basically a wrapper for the service
$scope.processQueryByField = function(field, value, pageNumber){
return searchAPI.executeSearch(field, value, pageNumber);
}
Shouldn't I just be receiving the value that I defined inside the injector code?
回答1:
I am not exactly sure what expectation you want to set with the promise object, You do not need to test if a promise is resolved, instead you need to test what happens to the data when a promise is resolved.
Example:-
Change your mock to simplify:-
inject(function($q){
var testData = {"message":"hi"};
mockSearchAPI.executeSearch = function(){
return $q.when(testData);
};
});
Just for a demo i have added one more method in your controller which resolved to a data:-
.controller('MainSearchCtrl', ['$scope','searchAPI', function ($scope, searchAPI) {
//At this point placing this method on scope is useless
$scope.processQueryByField = function(field, value, pageNumber){
return searchAPI.executeSearch(field, value, pageNumber);
}
//This when invoked will update the searchResults in the model.
$scope.populateData = function(){
$scope.processQueryByField(1,1,1).then(function(data){
$scope.searchResults = data;
})
}
}]);
Expectation #1:- Test whether when the method is invoked the api method is getting invoked with the expected arguments.
it('should invoke execute search', function(){
//Set up a spy on your mock api method
spyOn(mockSearchAPI,'executeSearch');
var field = "testfield";
var value = "testvalue";
var pageNumber = 1;
scope.processQueryByField(field, value, pageNumber); //invoke scope method with args
//Test if the mock api method has been called
expect(mockSearchAPI.executeSearch).toHaveBeenCalled();
//test if it has been called with expected arguments.
expect(mockSearchAPI.executeSearch).toHaveBeenCalledWith(field, value, pageNumber);
});
Expectation #2:- Test whether data is populated properly when the promise is resolved.
it('should return a promise correctly', function(){
var field = "testfield";
var value = "testvalue";
var pageNumber = 1;
var promise = scope.processQueryByField(field, value, pageNumber);
//This is a useless expectation
expect(promise).toBeDefined();
scope.populateData();
$rootScope.$digest(); //<-- Apply digest cycle, so the promise is resolved
expect(scope.searchResults).toBeDefined();
expect(scope.searchResults.message).toEqual("hi");
});
Test Demo
来源:https://stackoverflow.com/questions/25983466/angular-jasmine-testing-with-deffered-promises