How to inject dependencies in jasmine test for an angular item
Solution 1
The main problem with your test code is that it tries to create a controller's instance "by hand" using the new operator. When doing so AngularJS has no chance to inject dependencies. What you should be doing is to allow AngularJS inject dependencies:
var $scope, ctrl;
//you need to inject dependencies first
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new();
}));
it('Should initialize value to Loading', inject(function($controller) {
ctrl = $controller('MainNavController', {
$scope: $scope
});
expect($scope.wksp_name).toBe('Loading...');
}));
Here is the link to a complete jsFiddle: http://jsfiddle.net/pkozlowski_opensource/7a7KR/3/
There are 2 things worth noting in the above example:
- You can use the inject() method from the ngMock module to inject dependencies: https://docs.angularjs.org/api/ngMock/function/angular.mock.inject
- To create a controller instance (that supports dependency injection) you would use the $controller service: http://docs.angularjs.org/api/ng.$controller
As the last remark: I would advise naming controllers starting with an uppercase letter - this way we won't confuse them with variable names.
Solution 2
Great answer by @pkozlowski.opensource. To elaborate a bit more... Sometimes it could be also handy to assert that $scope.$on
was really called by your controller. In this case you can spy on $scope.$on
as pointed out below:
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new();
spyOn($scope, '$on').andCallThrough();
}));
And then you can assert that $on
was called with your event name and some function as arguments:
it('Should bind to "broadCastWkspNameEvent"', inject(function($controller) {
ctrl = $controller('MainNavController', {
$scope: $scope
});
expect($scope.$on).toHaveBeenCalledWith('broadCastWkspNameEvent', jasmine.any(Function));
}));
Solution 3
I agree with pkozowski's response, but to answer your question more directly, you need to stub out '$on'
Your example would pass if your $scope looked like:
$scope = {
$on: function() {}
}
Ranjith Ramachandra
Updated on February 16, 2020Comments
-
Ranjith Ramachandra over 4 years
Here is the test spec file:
describe('Test main controller', function(){ it('Should initialize value to Loading', function(){ $scope = {} ctrl = new mainNavController($scope) expect($scope.wksp_name).toBe('Loading') }) })
Here is the controller file
function mainNavController($scope) { $scope.wksp_name = 'Loading...' $scope.$on('broadCastWkspNameEvent', function (e, args) { $scope.wksp_name = args }) } mainNavController.$inject=['$scope']
But my test fails saying
Object #<Object> has no method '$on'
I am using the basic setup of jasmine.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Jasmine Spec Runner</title> <link rel="shortcut icon" type="image/png" href="testlib/jasmine-1.2.0/jasmine_favicon.png"> <link rel="stylesheet" type="text/css" href="testlib/jasmine-1.2.0/jasmine.css"> <script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine.js"></script> <script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine-html.js"></script> <!-- include source files here... --> <script type="text/javascript" src="/static_files/js/test-specs/main-nav-spec.js"></script> <!-- include spec files here... --> <script type="text/javascript" src="/static_files/js/common/jquery/latest.js"></script> <script type="text/javascript" src="/static_files/js/common/angular/angular-1.0.1.min.js"></script> <script type="text/javascript" src="/static_files/js/common/angular/angular-resource-1.0.1.min.js"></script> <script type="text/javascript" src="/static_files/js/section/main-nav-controller.js"></script> <script type="text/javascript"> (function() { var jasmineEnv = jasmine.getEnv(); jasmineEnv.updateInterval = 1000; var htmlReporter = new jasmine.HtmlReporter(); jasmineEnv.addReporter(htmlReporter); jasmineEnv.specFilter = function(spec) { return htmlReporter.specFilter(spec); }; var currentWindowOnload = window.onload; window.onload = function() { if (currentWindowOnload) { currentWindowOnload(); } execJasmine(); }; function execJasmine() { jasmineEnv.execute(); } })(); </script> </head> <body> </body> </html>
What is it that I am doing wrong? I am not able to understand how this thing is supposed to work :)