I have the following situation:
controller.js
controller('PublishersCtrl',['$scope','APIService','$timeout', function($scope,APIService,$timeout) {
APIService.get_publisher_list().then(function(data){
});
}));
controllerSpec.js
'use strict';
describe('controllers', function(){
var scope, ctrl, timeout;
beforeEach(module('controllers'));
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new(); // this is what you missed out
timeout = {};
controller = $controller('PublishersCtrl', {
$scope: scope,
APIService: APIService,
$timeout: timeout
});
}));
it('should have scope variable equals number', function() {
expect(scope.number).toBe(3);
});
});
Error:
TypeError: Object #<Object> has no method 'get_publisher_list'
I also tried something like this, and it didn't work:
describe('controllers', function(){
var scope, ctrl, timeout,APIService;
beforeEach(module('controllers'));
beforeEach(module(function($provide) {
var service = {
get_publisher_list: function () {
return true;
}
};
$provide.value('APIService', service);
}));
beforeEach(inject(function($rootScope, $controller) {
scope = $rootScope.$new();
timeout = {};
controller = $controller('PublishersCtrl', {
$scope: scope,
APIService: APIService,
$timeout: timeout
}
);
}));
it('should have scope variable equals number', function() {
spyOn(service, 'APIService');
scope.get_publisher_list();
expect(scope.number).toBe(3);
});
});
How can i solve this? any suggestions?
A mock component in Angular tests can be created by MockComponent function. The mock component respects the interface of its original component, but all its methods are dummies. To create a mock component, simply pass its class into MockComponent function.
The HttpClientTestingModule allows you to easily mock HTTP requests by providing you with the HttpTestingController service.
There are two ways (or more for sure).
Imagining this kind of service (doesn't matter if it is a factory):
app.service('foo', function() {
this.fn = function() {
return "Foo";
};
});
With this controller:
app.controller('MainCtrl', function($scope, foo) {
$scope.bar = foo.fn();
});
One way is just creating an object with the methods you will use and spy them:
foo = {
fn: function() {}
};
spyOn(foo, 'fn').andReturn("Foo");
Then you pass that foo
as a dep to the controller. No need to inject the service. That will work.
The other way is to mock the service and inject the mocked one:
beforeEach(module('app', function($provide) {
var foo = {
fn: function() {}
};
spyOn(foo, 'fn').andReturn('Foo');
$provide.value('foo', foo);
}));
When you inject then foo
it will inject this one.
See it here: http://plnkr.co/edit/WvUIrtqMDvy1nMtCYAfo?p=preview
For those that struggle with making the answer work,
as of Jasmine 2.0 andReturn()
became and.returnValue()
So for example in the 1st test from the plunker above:
describe('controller: MainCtrl', function() {
var ctrl, foo, $scope;
beforeEach(module('app'));
beforeEach(inject(function($rootScope, $controller) {
foo = {
fn: function() {}
};
spyOn(foo, 'fn').and.returnValue("Foo"); // <----------- HERE
$scope = $rootScope.$new();
ctrl = $controller('MainCtrl', {$scope: $scope , foo: foo });
}));
it('Should call foo fn', function() {
expect($scope.bar).toBe('Foo');
});
});
(Source: Rvandersteen)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With