Sinon: Fake timers do not work when asked to tick() too far ahead

Created on 9 May 2013  ·  5Comments  ·  Source: sinonjs/sinon

Taking a program that sets an interval x and then asks Sinon to tick() y milliseconds. It seems that if y is much greater than x (double or more), then the interval will never be called.

I have reproduced this problem with the small mocha/sinon test case below and with sinon 1.4 and 1.7.

var assert = require('assert'),
    sinon = require('sinon');

function testSinonFakeTimersWith(interval, ticks) {
    var clock = sinon.useFakeTimers();

    var spy = sinon.spy();
    setInterval(spy, interval);
    assert(! spy.calledOnce);
    clock.tick(ticks);
    assert(spy.calledOnce);

    clock.restore();
}

describe("Testing sinon useFakeTimers", function() {
  // FAILS
  it('10/101', function() {
    testSinonFakeTimersWith(10, 101);
  });
  // PASS
  it('99/101', function() {
    testSinonFakeTimersWith(99, 101);
  });

  // FAILS
  it('100/200', function() {
    testSinonFakeTimersWith(100, 200);
  });
  // PASS
  it('199/200', function() {
    testSinonFakeTimersWith(199, 200);
  });

  // FAILS
  it('500/1001', function() {
    testSinonFakeTimersWith(500, 1001);
  });
  // PASS
  it('1000/1001', function() {
    testSinonFakeTimersWith(1000, 1001);
  });
});
$ mocha -R spec test/sinon-test.js                                                                                   ±[●●][error-notopened]


  Testing sinon useFakeTimers
    1) 10/101
    ✓ 99/101
    2) 100/200
    ✓ 199/200
    3) 500/1001
    ✓ 1000/1001
1.x Bug Medium Help wanted

Most helpful comment

Hello everyone!
This is not a problem with sinon, it's a problem with the test written.
At this line you are expecting your spy to be called once, but it won't be called just once, it would be called multiple times, since it's a setInterval and not a setTimeout (that's why tests pass with setTimeout)

If you change your spy to a function with a console.log inside it you will be able to see it does get called multiple times (in this case the times it will be called will be ticks / interval).

SInce this is the desired behavior for calledOnce (at least I think so because, as you can see here, the calledOnce prop will only be true if the spy got called exactly once) I have just fixed your test.

Let me know if I had any misconception, but I thinks this pretty much explains the whole thing.

All 5 comments

Interesting. Seems to be interval specific. Your test cases all pass for setTimeout.

as a workaround you can call clock.tick multiple times with less ticks.

clock.tick(lessTicks);
clock.tick(lessTicks);
clock.tick(lessTicks);

Verified as a problem in master still as of 2016.

Hello everyone!
This is not a problem with sinon, it's a problem with the test written.
At this line you are expecting your spy to be called once, but it won't be called just once, it would be called multiple times, since it's a setInterval and not a setTimeout (that's why tests pass with setTimeout)

If you change your spy to a function with a console.log inside it you will be able to see it does get called multiple times (in this case the times it will be called will be ticks / interval).

SInce this is the desired behavior for calledOnce (at least I think so because, as you can see here, the calledOnce prop will only be true if the spy got called exactly once) I have just fixed your test.

Let me know if I had any misconception, but I thinks this pretty much explains the whole thing.

Thanks @lucasfcosta - You are of course right.

At this point I have no idea what I was working on when I opened this bug and I am very happy with your explanation :)

Was this page helpful?
0 / 5 - 0 ratings