23

I'm using a Jasmine (2.2.0) spy to see if a certain callback is called.

Test code:

it('tests', function(done) {
  var spy = jasmine.createSpy('mySpy');
  objectUnderTest.someFunction(spy).then(function() {
    expect(spy).toHaveBeenCalled();
    done();
  });
});

This works as expected. But now, I'm adding a second level:

it('tests deeper', function(done) {
  var spy = jasmine.createSpy('mySpy');
  objectUnderTest.someFunction(spy).then(function() {
    expect(spy).toHaveBeenCalled();
    spy.reset();
    return objectUnderTest.someFunction(spy);
  }).then(function() {
    expect(spy.toHaveBeenCalled());
    expect(spy.callCount).toBe(1);
    done();
  });
});

This test never returns, because apparently the done callback is never called. If I remove the line spy.reset(), the test does finish, but obviously fails on the last expectation. However, the callCount field seems to be undefined, rather than 2.

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
Jorn
  • 20,612
  • 18
  • 79
  • 126
  • Try adding rejection handlers for your promises. – robertklep Jul 21 '15 at 13:07
  • added `.catch(done)` to the end of the chain, same problem occurs. So @Daniel, if it's throwing I can't detect it. – Jorn Jul 21 '15 at 14:05
  • Adding a `try/catch` does reveal the exception: `'undefined' is not a function (evaluating 'spy.reset()')`. I'm not sure why this isn't correctly handled by Q / Jasmine. I'm also not sure why my spy is missing several properties it normally should have. – Jorn Jul 21 '15 at 14:11

2 Answers2

40

The syntax for Jasmine 2 is different than 1.3 with respect to spy functions. See Jasmine docs here.

Specifically you reset a spy with spy.calls.reset();

This is how the test should look like:

// Source
var objectUnderTest = {
    someFunction: function (cb) {
        var promise = new Promise(function (resolve, reject) {
            if (true) {
                cb();
                resolve();
            } else {
                reject(new Error("something bad happened"));
            }
        });
        return promise;
    }
}

// Test
describe('foo', function () {
    it('tests', function (done) {
        var spy = jasmine.createSpy('mySpy');
        objectUnderTest.someFunction(spy).then(function () {
            expect(spy).toHaveBeenCalled();
            done();
        });
    });
    it('tests deeper', function (done) {
        var spy = jasmine.createSpy('mySpy');
        objectUnderTest.someFunction(spy).then(function () {
            expect(spy).toHaveBeenCalled();
            spy.calls.reset();
            return objectUnderTest.someFunction(spy);
        }).then(function () {
            expect(spy).toHaveBeenCalled();
            expect(spy.calls.count()).toBe(1);
            done();
        });
    });
});

See fiddle here

Eitan Peer
  • 4,335
  • 27
  • 29
4

Another way to write it:

const spy = spyOn(foo, 'bar');
expect(spy).toHaveBeenCalled();
spy.calls.reset();
Steve Brush
  • 2,911
  • 1
  • 23
  • 15