async.waterfall is not working with Sinon.JS fake timers in Node.js #106

Closed
rstuven opened this Issue Feb 27, 2012 · 4 comments

Projects

None yet

4 participants

@rstuven

Using async.series, the following example works just fine.

var async = require("async");
var sinon = require("sinon");

var clock = sinon.useFakeTimers();

async.series([
    function fn1(cb) {
        console.log("fn1");
        setTimeout(function(){
            cb();
        }, 100);
    },
    function fn2(cb) {
        console.log("fn2");
        cb();
    }
]);

clock.tick(1000);

But if we change async.series by async.waterfall, the program exits before fn2 is called.

var async = require("async");
var sinon = require("sinon");

var clock = sinon.useFakeTimers();

async.waterfall([
    function fn1(cb) {
        console.log("fn1");
        setTimeout(function(){
            cb();
        }, 100);
    },
    function fn2(cb) {
        console.log("fn2");
        cb();
    }
]);

clock.tick(1000);

UPDATE: In the browser, async.waterfall works fine.

<script type="text/javascript" src="http://sinonjs.org/releases/sinon-1.3.1.js"></script>
<script type="text/javascript" src="https://raw.github.com/caolan/async/master/dist/async.min.js"></script>
<script type="text/javascript">

var clock = sinon.useFakeTimers();

async.waterfall([
    function fn1(cb) {
        console.log("fn1");
        setTimeout(function(){
            cb();
        }, 100);
    },
    function fn2(cb) {
        console.log("fn2");
        cb();
    }
]);

clock.tick(1000);

</script>
@rstuven

async.auto works fine in Node.js too:

var async = require("async");
var sinon = require("sinon");

var clock = sinon.useFakeTimers();

async.auto({
    "f2": ["f1", function f2(cb) {
        console.log("fn2");
        cb();
    }],
    "f1": function f1(cb) {
        console.log("fn1");
        setTimeout(function(){
            cb();
        }, 100);
    }
});

clock.tick(1000);
@rstuven

I found the source of the issue and a way to "patch" async so it works nicely with Sinon.JS:

if (typeof sinon === "object" && typeof sinon.timers === "object") {
    (function(){
        var nextTick = async.nextTick;
        async.nextTick = function(fn) {
            if (global.setTimeout === sinon.timers.setTimeout)
                nextTick(fn);
            else
                global.setTimeout(fn, 0);
        };
    })();
}
@statico

You're not crazy. We had to do something similar when using fake timers, too.

@caolan caolan closed this Mar 28, 2014
@eloone

If you only need to fake the date you can do sinon.useFakeTimers('Date'), it will work since the problem with async.waterfall comes from sinon faking setIntermediate see #609. Read the useFakeTimers doc to only fake the method you want to fake.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment