Exitos
Exitos

Reputation: 29720

Why does this have $rootscope.$new()?

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?

Upvotes: 14

Views: 16372

Answers (2)

ethanfar
ethanfar

Reputation: 3778

$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');
        });
    }); 
});

Upvotes: 14

Brocco
Brocco

Reputation: 64883

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.

Upvotes: 3

Related Questions