How to have different return values for multiple calls on a Jasmine spy

70,971

Solution 1

You can use spy.and.returnValues (as Jasmine 2.4).

for example

describe("A spy, when configured to fake a series of return values", function() {
  beforeEach(function() {
    spyOn(util, "foo").and.returnValues(true, false);
  });

  it("when called multiple times returns the requested values in order", function() {
    expect(util.foo()).toBeTruthy();
    expect(util.foo()).toBeFalsy();
    expect(util.foo()).toBeUndefined();
  });
});

There is some thing you must be careful about, there is another function will similar spell returnValue without s, if you use that, jasmine will not warn you.

Solution 2

For older versions of Jasmine, you can use spy.andCallFake for Jasmine 1.3 or spy.and.callFake for Jasmine 2.0, and you'll have to keep track of the 'called' state, either through a simple closure, or object property, etc.

var alreadyCalled = false;
spyOn(util, "foo").andCallFake(function() {
    if (alreadyCalled) return false;
    alreadyCalled = true;
    return true;
});
Share:
70,971
mikhail
Author by

mikhail

Software Engineer Spent a few years doing embedded work, but currently developing my JavaScript skills.

Updated on July 08, 2022

Comments

  • mikhail
    mikhail about 2 years

    Say I'm spying on a method like this:

    spyOn(util, "foo").andReturn(true);
    

    The function under test calls util.foo multiple times.

    Is it possible to have the spy return true the first time it's called, but return false the second time? Or is there a different way to go about this?

  • Jack
    Jack about 8 years
    We can extend this for more than 2 calls like so: var results = [true, false, "foo"]; var callCount = 0; spyOn(util, "foo").and.callFake(function() { return results[callCount++]; });
  • The DIMM Reaper
    The DIMM Reaper about 8 years
    +1: this is an excellent feature. A word of warning, though - be careful not to forget the 's' in .returnValues - the two functions are obviously different, but passing multiple arguments to .returnValue doesn't throw an error. I don't want to admit how much time I wasted due to that one character.
  • Tomas Lieberkind
    Tomas Lieberkind almost 8 years
    This can be extended into a generic function like so: function returnValues() { var args = arguments; var callCount = 0; return function() { return args[callCount++]; }; }
  • Ocean
    Ocean over 7 years
    @TheDIMMReaper, Thank you. I mention it now.
  • ThaFog
    ThaFog over 5 years
    Why whole this code when you can just return results.shift() ?
  • Ian
    Ian over 5 years
    Doing it in the beforeEach was important for me, not in the test (it)
  • Lijo
    Lijo about 5 years
    how about when we return observabvles
  • Elliott Beach
    Elliott Beach almost 5 years
    No need to worry about spelling errors when using jasmine in TypeScript, of course.
  • 0bj3ct
    0bj3ct about 4 years
    this option is more flexible, as we can throw error or return value depending on the call order.