Reputation: 1025
I tried to mocking angular promises but I got some errors like undefined is not a function evaluating 'spyOn' fileUploadService
My controller code is
$scope.getUserFiles = function() {
fileUploadService.retrieveUserFileNames('')
.then(function(data) {
$scope.userFiles = data;
});
};
service code, I call this method from my controller
this.retrieveUserFileNames= function(userId) {
var deferred = $q.defer();
$http({
method : "GET",
url : "/retrieveExcelSheetNames",
params : {
"userId" : userId
}
}).success(function(data) {
deferred.resolve(data);
}).error(function(data, status) {
deferred.reject(data);
});
return deferred.promise;
};
test controller code
beforeEach(function() {
inject(function(_fileUploadService_ , _$q_) {
spyOn(scope, '$on');
var deferred = _$q_.defer();
fileUploadService = _fileUploadService_;
deferred.resolve('resolveData');
spyOn(fileUploadService, 'retrieveUserFileNames').andReturn(deferred.promise);
});
});
it('is now a lot easier', function() {
scope.getUserFiles();
rootScope.$apply();
expect(scope.userFiles).toBe('resolveData');
});
Thanks
Upvotes: 1
Views: 1102
Reputation: 1423
As you're asynchronously set $scope.userFiles
in your controller so you need to wait for the $apply
from $http
that resolved your promise.
Assuming you're using Jasmine you could use the asynchronous spec notation and register a $watch
function to test your controller (Didn't test the code so you might need to tune it and it also depends on other modifications of the scope variable).
it('is now a lot easier', function(done) {
scope.$watch('userFiles', function() {
expect(scope.userFiles).toBe('resolveData');
// Call done function to tell Jasmine that the spec has completed
done();
});
scope.getUserFiles();
});
However, I think you should rather test your service and you can use $httpBackend from ngMock which is overriding $http and enables you to test much more in-depth. There you can test / spy the calls to the mock backend and also use Jasmines done()
function to wait for the promise.
Here is a simple exmaple:
angular.module('mainApp', [])
// Simple factory that uses $http for later use of $httpBackend mocking structure
.factory('userManager', function($http, $q) {
return $http.get('/api/users');
});
And the specs:
describe('Simple factory that uses $http for later use of $httpBackend mocking structure', function() {
// We need to use the module mainApp for all our tests
beforeEach(module('mainApp'));
// We use $httpBackend from ngMock module to mock our webservice call ($http will be overriden)
// Also we need to inject inside of spec function as we need to use the async spec form with
// a done function and this is not available using the inject to proxy the spec function
it('should return desired user list', function(done) {
inject(function($httpBackend, userManager) {
$httpBackend.when('GET', '/api/users').respond({
userList: [
{user: 'User A'},
{user: 'User B'},
{user: 'User C'},
{user: 'User D'},
]
});
$httpBackend.expectGET('/api/users');
// userManager is returning a promise so we need to check asynchronously
userManager.getUserList().then(function(result) {
expect(result.data.userList).toContain(
{user: 'User A'},
{user: 'User B'},
{user: 'User C'},
{user: 'User D'}
);
// This call to the Jasmine done function is very important for asynchronous
// unit tests as Jasmine is determining if the test is done by this call
done();
});
$httpBackend.flush();
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
});
});
Upvotes: 2