I have some Ember code that sets a timeout:
var MyObject = Ember.Object.extend({
setFooToBarLater: function() {
Ember.run.later(this, 'set', 'foo', 'bar', 500);
}
});
I'd like to test that using Sinon's fake clock. Here's what I tried:
var clock = sinon.useFakeTimers();
var myObject = MyObject.create();
myObject.setFooToBarLater();
clock.tick(600);
expect(myObject.get('foo')).to.be('bar');
But the expect
always runs before the set
. I also tried wrapping the clock.tick
in a run-loop:
Ember.run(clock, 'tick', 600);
Beware that sinon.useFakeTimers (by default on) overrides the window.Date. That becomes an issue once you already have a scheduled Ember runloop and the useFakeTimers() is turned on. This is because Backburner (the Ember.js runloop implementation) setTimeout /core scheduling method/ tries hard to optimize calling window.setTimeout (look for executeAt
in ember.js)
After going through the sinon source I made the following mod to let those two get along nicely (gist). It instructs sinon not to touch the window.Date and also patches sinon.test() to wait few more ticks after the test body which allows scheduled timers to get executed and async codes
sinon._originalUseFakeTimers = sinon.useFakeTimers;
sinon.useFakeTimers = function() {
// make sure we don't override window.Date used in
// Backburner.setTimeout() to optimize window.setTimeout() call numbers
return sinon._originalUseFakeTimers.apply(this, [new Date().getTime(), "setTimeout", "setInterval", "clearTimeout", "clearInterval"]);
};
sinon._originalTest = sinon.test;
sinon.test = function(callback) {
return sinon._originalTest.call(this, function() {
callback.apply(this, arguments);
// wait for further runloops to finish (2s is the mocha timeout)
this.clock.tick(2000);
});
};
The answer appears to be not putting the clock.tick
in a run-loop, but the call that actually invokes Ember.run.later
. Thus, the following does work:
var clock = sinon.useFakeTimers();
var myObject = MyObject.create();
Ember.run(myObject, 'setFooToBarLater');
clock.tick(600);
expect(myObject.get('foo')).to.be('bar');
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With