Jasmine's spy throwing is not a function error

19,237

Seems like a typo if this is the real code. Change the appropriated part to:

shoppingData = {
  getAllItems: jasmine.createSpy('getAllItems'),
  addAnItem: jasmine.createSpy('addAnItem'),
  removeItem: jasmine.createSpy('removeItem')
};

Just changed the function to an object and changed the ; for ,.

UPDATE 1:

Consider only spying at the existing object:

var deferred, _shoppingData;

beforeEach(module('shopping'));

beforeEach(inject(function(shoppingData, $q) {
  _shoppingData = shoppingData;
  deferred = $q.defer();
  spyOn(shoppingData, 'getAllItems').andReturn(deferred.promise);
}));

it('should have called shoppingData.getAllItems', function() {
  expect(_shoppingData.getAllItems).toHaveBeenCalled();
});
Share:
19,237
S. Ravi Kiran
Author by

S. Ravi Kiran

Software developer. Very passionate about Microsoft Technologies and Web Programming

Updated on June 04, 2022

Comments

  • S. Ravi Kiran
    S. Ravi Kiran almost 2 years

    I have an Angular JS application with a module and some services in it. My controller uses these services. In Jasmine test cases, I created a mock of a service using Jasmine's createSpy. Following is the mocked service:

    beforeEach(module(function ($provide) {
        shoppingData = function () {
            getAllItems: jasmine.createSpy('getAllItems');
            addAnItem: jasmine.createSpy('addAnItem');
            removeItem: jasmine.createSpy('removeItem');
       };
       $provide.value('shoppingData', shoppingData);
    }));
    

    Controller calls the getAllItems function as soon as an object is created. I created another beforeEach block that creates an object of the controller. Following is the test block to check if getAllItems is called:

    it("Should call getAllItems function on creation of controller", function () {
        expect(shoppingData.getAllItems).toHaveBeenCalled();
    });
    

    When I run the spec runner page on browser, the test fails with following error: TypeError: 'shoppingData.getAllItems' is not a function

    I saw several similar example where this kind of test works without any issue. Can anyone point what is missing or what is going wrong here?

    Update: I created a plunker with the part that fails

  • S. Ravi Kiran
    S. Ravi Kiran about 11 years
    I had tried this approach too. But it throws an error saying: 'Cannot convert shoppingData.getAllItems' to an object
  • Caio Cunha
    Caio Cunha about 11 years
    Maybe you're doing something else wrong. I made a working Plnker here. Look at it. If you can't understand anything, let me know and I'll try to explain. Maybe you forgot to create the controller, or inject something. Only when you first inject something, the module will be created and shoppingData will be avaialable.
  • S. Ravi Kiran
    S. Ravi Kiran about 11 years
    Thanks for your effort. After tweaking your plunker a bit and analyzing my code I got to know that it is failing because the function inside which I am calling getAllItems uses the returned object to call then() function. I forked your plnkr and created a demo. You can access it from here: plnkr.co/edit/BenU8lJtICS2uNyrtjns?p=preview
  • Caio Cunha
    Caio Cunha about 11 years
    Then all you got to do is to mock the return value with andReturn, take a look at Jasmine docs. Add this line just after creating the shoppingData object: shoppingData.getAllItems.andReturn({then: function(){}});. But, looking at this new angle, you don't need to mock the entire object, just inject and spyOn it in beforeEach. Updated your Plunkr appSpec. Consider also reading $httpBackend mock.
  • S. Ravi Kiran
    S. Ravi Kiran about 11 years
    Thanks Caio. I know about $httpBackend. I placed the logic in a separate service to keep the controller free from data-access logic. I didn't check Jasmine's docs properly. Will go through it.