This is my controller:
angular.module("AuthenticationApp", ["BaseApp"])
.controller("AuthCtrl", ["$http", "BaseService", function($http, BaseService) {
var self = this;
BaseService.fetch.stuffs()
.then(function(data) {
self.stuffs = data;
});
}]);
This my BaseService
(the factory I need to mock):
angular.module("BaseApp", ["ngRoute"])
.factory("BaseService", ["$http", "$q", function($http, $q) {
var self = this;
self.fetch = {
stuffs: function() {
return $http.get("/api/stuffs/")
.then(function(response) {
return response.data;
});
}
};
return self;
}]);
I have no idea where to start. What I tried was this:
describe('Controller: AuthCtrl', function() {
var ctrl, mockBaseService;
beforeEach(function() {
mockBaseService = {
stuffs: 'test',
fetch: {
stuffs: function() {
return {
then: function() {
return {stuffs: "stuffs"};
},
}
},
},
};
spyOn(mockBaseService.fetch, 'stuffs');
module('BaseApp', function($provide) {
$provide.value('BaseService', mockBaseService);
});
module('AuthenticationApp');
inject(function($controller) {
ctrl = $controller('AuthCtrl', {
});
});
});
it('BaseService.fetch.stuffs should be called on page load', function() {
expect(mockBaseService.fetch.stuffs).toHaveBeenCalled();
expect(ctrl.stuffs).toBe({stuffs: "stuffs"});
});
});
But when I test this code, I get an error saying:
TypeError: Cannot read property 'then' of undefined
at new <anonymous> (/home/user/Documents/ebdjango/ebdjangoapp/static/js/home.js:15:11)
home.js
line 15 is this line in the controller:
return $http.get("/api/stuffs/")
.then(function(response) { // line 15
return response.data;
});
How do I mock this correctly?
Edit: I read the documentation mentioned in the comments and and changed up mockBaseService
to this:
describe('Controller: AuthCtrl', function() {
var ctrl, mockBaseService;
beforeEach(function() {
// create promise
var deferred = $q.defer();
var promise = deferred.promise;
// make promise.then return {stuffs: "stuffs"}
promise.then(function(value) { return {stuffs: "stuffs" }; });
mockBaseService = {
stuffs: 'stuffs',
fetch: {
stuffs: function() {
return promise;
},
},
};
spyOn(mockBaseService.fetch, 'stuffs');
module('BaseApp', function($provide) {
$provide.value('BaseService', mockBaseService);
});
module('AuthenticationApp');
inject(function($controller) {
ctrl = $controller('AuthCtrl', {
});
});
});
it('BaseService.fetch.stuffs should be called on page load', inject(function($rootScope) {
deferred.resolve('test');
$rootScope.$apply();
expect(mockBaseService.fetch.stuffs).toHaveBeenCalled();
expect(ctrl.stuffs).toBe({stuffs: "stuffs"});
}));
});
But this returns a ReferenceError: $q is not defined
error. I tried injecting _$q_
like so:
beforeEach(inject(function(_$q_) {
$q = _$q_;
// ... everything else goes here... //
But then I get an error saying Error: Injector already created, can not register a module!
. Here: injector already created. can not register a module it says this issue can be solved if we do module('someApp')
before inject($someDependency)
. But I can't do
module('BaseApp', function($provide) {
$provide.value('BaseService', mockBaseService);
});
before injecting _$q_
since $q
is used for mockBaseService
. Where do I go from here?