1

I am new to unit testing and I am getting these errors even though I though my test was correct, I just cannot figure out what these errors mean and I have tried several things

 Can't find variable: $rootScope
 Error: Injector already created, can not register a module!

spec.js

   describe('test broadcast', function () {
    var $controller;

    beforeEach(function() {
        module('test');
        inject(function (_$rootScope_, _$controller_) {
            $rootScope = _$rootScope_;
            spyOn($rootScope, '$broadcast');

            // Notice how inject $controller here.
            $controller = _$controller_;
        });
    });

    it("should broadcast something", function ($rootScope) {
        $controller('myCtrl', {
            // Pass in the $rootScope dependency.
            $rootScope: $rootScope.$new()
        })
        // Here we actually run the controller.
        expect($rootScope.$broadcast).toHaveBeenCalledWith('update');
        //someObj = { data: testData};
        //expect($rootScope.$broadcast).toHaveBeenCalledWith('update', someObj);
    });
})

controller

(function () {

    var test= angular.module('test');

    test.controller('myCtrl',
        function($rootScope, $scope, $resource, $location, $route, $routeParams, $log, catalogData) {

            $log.debug("myCtrl");
            $log.debug(myCtrl);

            $rootScope.$broadcast("update", {
                data: testData
            });
        }); // catalogCtrl
})();
user2402107
  • 913
  • 5
  • 22
  • 43

2 Answers2

3

You have a variable called rootScope defined, not $rootScope - change your definition:

rootScope.$apply();

Though I personally like to define them like so:

var $rootScope;
beforeEach(inject(function(_$rootScope_) {
    $rootScope = _$rootScope_;
}));
Katana24
  • 8,706
  • 19
  • 76
  • 118
  • I just updated my code up top to what you said but its still not working, its saying "Expected spy $broadcast to have been called with [ 'update' ] but it was never called" and " Error: Injector already created, can not register a module!" – user2402107 Feb 02 '16 at 13:32
  • and when I run Karma it says TypeError: rootScope is undefined, Unable to get property '$apply' of undefined or null reference – user2402107 Feb 02 '16 at 13:37
1

EDIT 2:

You cannot access $rootScope in your it function because it is not in the current javascript scope (not angular $scope, don't get confused).

You need to define it alongside your controller at the top.

var $controller, $rootScope

And remove $rootScope from your it function so you don't overwrite it.

// Notice there is no $rootScope parameter.
it("should broadcast something", function () {
    //Code
}

You will also have to pass in your other dependencies. After a discussion with the OP, the whole code should look like this:

describe('test broadcast', function () { 
    var $controller, $rootScope; 

    beforeEach(function() { 
        module('test'); 
        inject(function (_$rootScope_, _ $controller_) { 
        $rootScope = _$rootScope_; 
        spyOn($rootScope, '$broadcast'); 
        $controller = _$controller_; 
     }); 
}); 

it("should broadcast something", function () { 
    $controller('myCtrl', { 

        $scope: $rootScope.$new(), 

         catalogData: {} 
    }) 
    expect($rootScope.$broadcast).toHaveBeenCalledWith('update', {catalog:{}})}); 
})

EDIT 1:

You are passing in the $scope dependency. $broadcast is called on the $rootScope so you need to pass that in. Like this:

var testScope = $rootScope.$new()
$controller('myCtrl', {
    // Pass in the $rootScope dependency.
    $rootScope: testScope
}

Original post (in case it's still useful to anyone)

You aren't actually calling your controller anywhere in your test suite.

You need to have something like

var $controller
beforeEach(inject(function (_$rootScope_, _$controller_) {
    $rootScope = _$rootScope_;
    spyOn($rootScope, '$broadcast'); 

    // Notice how inject $controller here.
    $controller = _$controller_;
}));

Then initialise it in your test:

it("should broadcast something", function () {
    // Here we actually run the controller.
    $controller('myCtrl', {
        // Pass in the $rootScope dependency.
        $rootScope: $rootScope.$new()
    }
    expect($rootScope.$broadcast).toHaveBeenCalledWith('catalogUpdate');
    someObj = { catalog: catalogData};
    expect($rootScope.$broadcast).toHaveBeenCalledWith('catalogUpdate', someObj);
});  

This will remove the error about $rootScope.broadcast not being called.

Take a look at the "Testing Controllers" section here: https://docs.angularjs.org/guide/controller

As for not being able to register a module, this normally happens if you have an inject() before a beforeEach(module('abc')). As the error says, you cannot register another module after inject has been called.

Community
  • 1
  • 1
Matt Lishman
  • 1,817
  • 2
  • 22
  • 34
  • i rewrote the spec.js again because it was not working still, and now it just says undefined... I updated it up top – user2402107 Feb 02 '16 at 14:14
  • What says undefined? – Matt Lishman Feb 02 '16 at 14:38
  • with new code up top I get Expected spy $broadcast to have been called with [ 'update' ] but it was never called. – user2402107 Feb 02 '16 at 14:42
  • Do you get any javascript errors? For example, is $log undefined? Have you tried it without the two $log lines? – Matt Lishman Feb 02 '16 at 14:46
  • You are passing `testScope` into `$scope`. You need to do `$rootScope: testScope` because $broadcast is called on `$rootScope` not `$scope`. Refer to my answer above for how to do that. – Matt Lishman Feb 02 '16 at 14:48
  • okay but now I am getting": undefined is not a constructor (evaluating '$rootScope.$new()') " – user2402107 Feb 02 '16 at 15:14
  • I just used your complete code and it says " Error: [$injector:unpr] Unknown provider: $scopeProvider <- $scope <- MyCtrl " – user2402107 Feb 02 '16 at 15:27
  • Sorry, updated again. You need to pass in all your dependencies. Obviously your `testData` and `myCtrl` variables won't be defined in your controller. – Matt Lishman Feb 02 '16 at 15:37
  • Expected spy $broadcast to have been called with [ 'update' ] but actual calls were [ 'update', Object({ catalog: Object({ }) }) ]. – user2402107 Feb 02 '16 at 16:01
  • Well, read the error. It is telling you that you have expected it to be called with one parameter 'update'. But, if you look at your code, it is actually calling with two, update and a blank object. Your expect should be `.toHaveBeenCalledWith('update', {catalog: {}});` Or something similar. – Matt Lishman Feb 02 '16 at 16:11
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102378/discussion-between-matt-lishman-and-user2402107). – Matt Lishman Feb 02 '16 at 16:11