How to spy on anonymous function using Jasmine

All we need is an easy explanation of the problem, so here it is.

I’m using Jasmine to test my angular application and want to spy on an anonymous function.
Using angular-notify service https://github.com/cgross/angular-notify, I want to know whether notify function have been called or not.

Here is my controller:

angular.module('module').controller('MyCtrl', function($scope, MyService, notify) {

  $scope.isValid = function(obj) {
    if (!MyService.isNameValid(obj.name)) {
      notify({ message:'Name not valid', classes: ['alert'] });
      return false;
    }
  }
});

And here is my test:

'use strict';

describe('Test MyCtrl', function () {
  var scope, $location, createController, controller, notify;

  beforeEach(module('module'));

  beforeEach(inject(function ($rootScope, $controller, _$location_, _notify_) {
    $location = _$location_;
    scope = $rootScope.$new();
    notify = _notify_;

    notify = jasmine.createSpy('spy').andReturn('test');

    createController = function() {
      return $controller('MyCtrl', {
        '$scope': scope
      });
    };
  }));

  it('should call notify', function() {
    spyOn(notify);
    controller = createController();
    scope.isValid('name');
    expect(notify).toHaveBeenCalled();
  });
});

An obviously return :

Error: No method name supplied on 'spyOn(notify)'

Because it should be something like spyOn(notify, ‘method’), but as it’s an anonymous function, it doesn’t have any method.

Thanks for your help.

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Daniel Smink’s answer is correct, but note that the syntax has changed for Jasmine 2.0.

notify = jasmine.createSpy().and.callFake(function() {
  return false;
});

I also found it useful to just directly return a response if you only need a simple implementation

notify = jasmine.createSpy().and.returnValue(false);

Method 2

You could chain your spy with andCallFake see:

http://jasmine.github.io/1.3/introduction.html#section-Spies:_andCallFake

    //create a spy and define it to change notify
    notify = jasmine.createSpy().andCallFake(function() {
      return false;
    });

    it('should be a function', function() {
        expect(typeof notify).toBe('function');             
    });

    controller = createController();
    scope.isValid('name');
    expect(notify).toHaveBeenCalled();

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply