1

I'm having trouble testing my directive which enables cross-document messaging by registering a message handler:

.directive('messaging', function ($window, MyService) {
    return {
        link: function () {
            angular.element($window).on('message', MyService.handleMessage);
        }
    };
})

All I want to unit test is that when this directive is compiled, and window.postMessage('message','*') is called, my message handler should be called:

http://jsfiddle.net/mhu23/L27wqn14/ (including jasmine test)

I'd appreciate your help! Michael

Itai Bar-Haim
  • 1,686
  • 16
  • 40
Michael Hunziker
  • 2,659
  • 3
  • 22
  • 26

1 Answers1

1

Your are using original window API, you are not mocking it, so the method postMessage will keep it's asynchronous behavior. Knowing that, tests should be written in an asynchronous way. In JSFiddle you have Jasmine 1.3, so test should look kinda like this:

it('should ....', function () {

    var done = false;

    spyOn(MyService,'handleMessage').andCallFake(function () {
        // set the flag, let Jasmine know when callback was called
        done = true; 
    });

    runs(function () {
        // trigger async call
        $window.postMessage('message','*');    
    });

    waitsFor(function () {
        // Jasmine waits until done becomes true i.e. when callback be called
        return done; 
    });

    runs(function () {
        expect(MyService.handleMessage).toHaveBeenCalled();
    });

});

Check the docs about testing async with Jasmine 1.3. And here is a working JSFiddle.

It would be a bit easier in Jasmine 2.x:

it('should ....', function (done) {

    spyOn(MyService,'handleMessage').and.callFake(function () {
      expect(MyService.handleMessage).toHaveBeenCalled();
      done();
    });

    $window.postMessage('message','*');
});

Also, I have to mention, that you have to change how you add a listener from this

angular.element($window).on('message', MyService.handleMessage);

to that

angular.element($window).on('message', function (e) {
    MyService.handleMessage(e);
});

because .on registers a function itself, it won't be used as a method attached to the MyService, so you won't be able to spy on it.

Michael Radionov
  • 12,859
  • 1
  • 55
  • 72