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
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 :)
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
setIntervaland not asetTimeout(that's why tests pass withsetTimeout)If you change your
spyto a function with aconsole.loginside it you will be able to see it does get called multiple times (in this case the times it will be called will beticks / interval).SInce this is the desired behavior for
calledOnce(at least I think so because, as you can see here, thecalledOnceprop 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.