I am researching how to use Jasmine with Karma. I am trying to inject a scope into my controller and from somewhere I have picked up this code...
var scope = { message: 'hello' };
beforeEach(angular.mock.module('myApp'));
beforeEach(angular.mock.inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
$controller('myController', { $scope: scope });
}));
The problem is that the scope is being wiped out with the line...
scope = $rootScope.$new();
So I can comment it out but I am wondering what the use of this line is for? When would I want to call $rootscope.$new()
? I understand it is to do with isolation but I don't really get the practical applications of it.
UPDATE : As Tim points out below it is a problem because I have declared my own scope. So I can modify the code to be ....
var scope;
beforeEach(angular.mock.module('myApp'));
beforeEach(angular.mock.inject(function ($rootScope, $controller) {
scope = $rootScope.$new();
scope.message = 'hello';
$controller('myController', { $scope: scope });
}));
And that works more like expected, but I am still wondering what the best approach is? What is $rootscope.$new()
even for?
Root Scope All applications have a $rootScope which is the scope created on the HTML element that contains the ng-app directive. The rootScope is available in the entire application. If a variable has the same name in both the current scope and in the rootScope, the application uses the one in the current scope.
In similar way, you can use use the sharedService inside any component & fetch the returing output and used inside your view. That's it. I found this solution as a good alternative of rootScope. You can use this inside your angular 2/4 application.
$rootscope is available globally (for all Controllers), whereas $scope is available only to the Controller that has created it.
Each AngularJS application has exactly one root scope, but may have any number of child scopes.
$rootScope.$new
creates a new instance of $rootScope.Scope
that inherits from $rootScope
. In other words, it creates a new child scope of $rootScope
.
The reason you might use it in tests (such as the one you posted), is because your other alternative is to use $rootScope
itself. Doing so might create a mess since it might be used all over the place.
I consider as best practice to create (and destroy afterwards) a new scope for each test case.
Here's your example rewritten to what I consider a best practice:
describe('myModule', function() {
var $rootScope;
beforeEach(module('myModule'));
beforeEach(function() {
inject(function(_$rootScope_) {
$rootScope = _$rootScope_;
});
});
describe('myController', function() {
var $scope;
beforeEach(function createChildScopeForTheTest() {
$scope = $rootScope.$new();
});
afterEach(function disposeOfCreatedChildScope() {
$scope.$destroy();
});
it('tests something', function() {
$scope.message = 'hello';
$controller('myController', { $scope: $scope });
expect($scope.something).toEqual('world');
});
});
});
Scopes in angular are nested in parent child relationships, all deriving from a single parent $rootScope
This is how angular creates the $scope
that gets injected into your controller so it creates the same experience when you are unit testing your controller.
This is especially useful if you are doing anything in your controller which requires you to call $apply rather than you having to mock that out as well.
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