Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jasmine spies callThrough and callFake

I have a scenario whereby I want to call done() on a beforeEach after a callback has been invoked.

I tried to do this as follows :

spyOn(scope, 'onAdmin').and.callThrough().and.callFake(function(){done()})

But I'm not sure I get the right behaviour. Essentially what I want to achieve is to be able to call done() after each callback is done doing what it does.

UPDATE: workaround solution

scope.onAdminBackup = scope.onAdmin;
spyOn(scope, 'onAdmin').and.callFake(function(admin)  {

 scope.onAdminBackup();
 done() ;

})  
like image 359
kkudi Avatar asked Jul 28 '14 14:07

kkudi


People also ask

What is the use of callThrough in Jasmine?

callThrough spy. This spy will track calls to the function it is spying on, but it will also pass through to the function and allow it to run. This means that when we use this spy, the function being spied on will still do what it is written to do, but we can track the calls to it.

What does callFake do in Jasmine?

callFake() Test doubles like mocks, spies, and stubs are integral part of unit testing. In Jasmine, there are few such functions which can stub any function and track calls to it and all its arguments.

What are spies in Jasmine testing?

Jasmine spies are used to track or stub functions or methods. Spies are a way to check if a function was called or to provide a custom return value. We can use spies to test components that depend on service and avoid actually calling the service's methods to get a value.


3 Answers

I found a work around way to do this. Jasmine has a method called addSpyStategy where you can add a custom strategy like callThrough or callFake. It would look something like this:

jasmine.addSpyStrategy('callThroughAndThen', (spy, fn) => {
  return function() {
    spy.and.callThrough();
    setTimeout(() => fn(...arguments), 0);
  }
});

the timeout makes sure the real function finishes before executing the custom function. Then for your spy, you can do this:

const spy = spyOn(scope, 'onAdmin')
 spy.and.callThroughAndThen(spy, () => {
  // your custom callback
  done();
});

note: make sure to put custom strategy in a beforeEach block

like image 145
Max Litvak Avatar answered Oct 19 '22 11:10

Max Litvak


I have never chained these kinds of functions together cuz in my mind they seem to do the opposite. You are saying when I call this method -onAdmin - in the scope call it as normal. Which is what the callThrough method jasmine provides for us does.

But then you are chaining along a callFake method as well so then you say but dont actually call it call this fake function instead - very conflicting.

If you want to call spy on the method onAdmin and instead of it being fired you want it to do something else - something mocked - then use the .and.callFake(fn). Also take into account like @stefan above said - dont invoke the function - callFake is simply wanting a function as a parameter it will take care of calling it itself.

This might be more along the lines of what you are looking for, if not show us some more code.

spyOn(scope, 'onAdmin')and.callFake(done)
like image 28
Sten Muchow Avatar answered Oct 19 '22 13:10

Sten Muchow


you are calling done right-away when you write done() try passing in done as a value:

spyOn(scope, 'onAdmin').and.callThrough().and.callFake(done)
like image 40
stefan Avatar answered Oct 19 '22 13:10

stefan