How do I inject $rootScope into an AngularJS unit test?

20,513

Solution 1

...
var $rootScope;
beforeEach(inject(function(_$rootScope_) {
  $rootScope = _$rootScope_;
}));
...

Solution 2

By using provide(), you can inject a new $rootScope:

describe('in rootValGetter', inject(function ($rootScope) {
    var scope;
    var testRootValGetter;

    beforeEach(function () {

        scope = $rootScope.$new();

        module(function ($provide) {
            $provide.value('$rootScope', scope);
        });

        inject(function ($injector) {
            testRootValGetterService = $injector.get('rootValGetterService');
        });
    });

    it('getVal returns the value from $rootScope', function() {
        var value = 12345;

        scope.specialValue = value;

        expect(testRootValGetterService.getVal()).toBe(value);
    }
}

Solution 3

Include angular-mocks.js, then use angular.mock.inject:

Solution 4

Instead of creating a new scope as you would if you were injecting $scope you can mock the properties you need directly into $rootScope.

Then $rootScope will be injected with those properties available in the code you are testing.

At least this is the way I solved the same problem.

The following code should work in your example.

beforeEach(inject(function($rootScope) {
    $rootScope.specialValue = 'whatever';
}));
Share:
20,513
Gregory Avery-Weir
Author by

Gregory Avery-Weir

I'm a game developer specializing in story-focused games. I made "The Majesty of Colors" and "How to Raise a Dragon." I'm co-founder of Future Proof Games. We've released the dialogue-based pixel-horror satire Ossuary and are currently in alpha on the social cyberpunk puzzle game Exploit: Zero Day.

Updated on April 26, 2020

Comments

  • Gregory Avery-Weir
    Gregory Avery-Weir about 4 years

    Suppose I have a service that depends on a value in $rootScope, as with the following (trivial) service:

    angular.module('myServices', [])
    .factory('rootValGetterService', function($rootScope) {
        return {
            getVal: function () {
                return $rootScope.specialValue;
            }
        };
    });
    

    If I want to unit test this by putting a value in $rootScope, what is the best way to go about it?

  • Chris Esplin
    Chris Esplin almost 11 years
    This pattern is not working for me. Angular keeps throwing this error: "Error: Injector already created, can not register a module!"
  • Tom Söderlund
    Tom Söderlund over 10 years
    Why do you need to use scope = $rootScope.$new();, instead of using $rootScope directly?
  • gentooboontoo
    gentooboontoo almost 10 years
    To have a clean $rootScope, you could try to inject it from beforeEach: beforeEach(inject(function($rootScope) {
  • Tamlyn
    Tamlyn almost 9 years
    Doesn't this give you the same scope for every test? How do you pass a fresh new scope to the service?
  • Markus Coetzee
    Markus Coetzee almost 9 years
    Hi Tamlyn, in what way is your root scope no longer fresh? I believe I've only ever used it to broadcast events.
  • Bart Verkoeijen
    Bart Verkoeijen almost 9 years
    The underscores are needed because there is otherwise a naming conflict between the $rootScope in the closure and $rootScope argument.
  • temporary_user_name
    temporary_user_name over 8 years
    Does anyone know why this happens if you put it on the top-level describe? Took awhile working backwards to figure out where I was getting this error from.
  • katsos
    katsos about 7 years
    @Tamlyn this one gives a new isolated $rootScope to each test. If anyone doesn't like the underscore convention can write it like this beforeEach(inject($injector => { $rootScope = $injector.get('$rootScope'); }))