Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jasmine + AngularJS: How to test $rootScope.$broadcast being called with arguments?

I am trying to write a unit test that verifies that $rootScope.$broadcast('myApiPlay', { action : 'play' }); is called.

Here is the myapi.js

angular.module('myApp').factory('MyApi', function ($rootScope) {
    var api = {};
    api.play = function() {
        $rootScope.$broadcast('myApiPlay', { action : 'play' });
    }
    return api;
});

And here is my Unit Test:

describe('Service: MyApi', function () {

    // load the service's module
    beforeEach(module('myApp'));

    // instantiate service
    var MyApi;
    var rootScope;

    beforeEach(function () {
        inject(function ($rootScope, _MyApi_) {
            MyApi = _MyApi_;
            rootScope = $rootScope.$new();
        })
    });
    it('should broadcast to play', function () {
        spyOn(rootScope, '$broadcast').andCallThrough();
        rootScope.$on('myApiPlay', function (event, data) {
            expect(data.action).toBe('play');
        });
        MyApi.play();
        expect(rootScope.$broadcast).toHaveBeenCalledWith('myApiPlay');
    });
});

Here is the error i'm getting while running grunt test:

PhantomJS 1.9.7 (Windows 7) Service: MyApi should broadcast to pause FAILED
        Expected spy $broadcast to have been called with [ 'myApiPlay' ] but it was never called.

I have also tried with expect(rootScope.$broadcast).toHaveBeenCalled() and I am having a similar error: Expected spy $broadcast to have been called..

I would like to verify that that method has actually been called with the right parameters.

Thank you!

like image 366
Andrea Avatar asked Sep 12 '14 22:09

Andrea


People also ask

How to use rootScope in AngularJS?

Root ScopeAll 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.

What is rootScope broadcast in AngularJS?

$broadcast in AngularJS? The $rootScope. $broadcast is used to broadcast a “global” event that can be caught by any listener of that particular scope. The descendant scopes can catch and handle this event by using $scope.

How to write unit test cases for Angular js?

Testing in AngularJS is achieved by using the karma framework, a framework which has been developed by Google itself. The karma framework is installed using the node package manager. The key modules which are required to be installed for basic testing are karma, karma-chrome-launcher ,karma-jasmine, and karma-cli.


1 Answers

The reason your tests are not passing is because you are spying on the wrong $broadcast function. In your beforeEach setup, you ask to have the $rootScope injected and then you create a child scope by calling $rootScope.$new().

The return value from $rootScope.$new() is no longer the rootScope but a child of the root scope.

beforeEach(function () {
    //inject $rootScope
    inject(function ($rootScope, _MyApi_) {
        MyApi = _MyApi_;
        //create a new child scope and call it root scope
        rootScope = $rootScope.$new();
        //instead don't create a child scope and keep a reference to the actual rootScope
        rootScope = $rootScope;
    })
});

In your play function, you are calling $broadcast on the $rootScope but in your test you are spying on a child of $rootScope.

$rootScope.$broadcast('myApiPlay', { action : 'play' });

So to wrap it up, remove the call to $rootScope.$new() and just spy on the $rootScope the injector has given you. The $rootScope provided to your unit test is the same $rootScope provided to your API service so you should be spying directly on the $rootScope.

Check out the plunkr http://plnkr.co/edit/wN0m8no2FlKf3BZKjC4k?p=preview

like image 158
jcruz Avatar answered Nov 15 '22 17:11

jcruz