vendredi 16 septembre 2016

Test async.waterfall in node.js with sinon.js timers

I have the following function that I wish to be tested which use async.js heavily in it:

MyClass.prototype.pipeline = function(arg1, arg2) {
    ...
    async.waterfall([
        async.apply(self.a.f.bind(self.a), arg1, arg2),
        function(data, callback) {
            async.each(data, function(d, callback) {
                async.waterfall([
                    async.apply(self.b.f.bind(self.b), d),
                    self.c.f.bind(self.c),
                    self.d.f.bind(self.d),
                    self.e.f.bind(self.f)
                ], function(err, results) {
                    if (err) {
                        ...
                    }
                    callback();
                });
            }, function(err) {
                callback(err, data);
            });
        }
    ], function (err, result) {
        ...
    });
};

Now I know I could separate a-lot of what's going on in here to separate functions, but it's a pipeline of streamlined action passing data from one another after the previous has finished, so I wish to keep it like this instead for example separate the function function(data, callback) {...} with a name like BCDEpipeline. Anyway, my problem is that I do some assertions based on the done callback of the first async.waterfall() done function, problem is it gets called later (deferred) even tho I stubbed a, b, c, d, and e functions already and made them yield the next callback immediately. Note that I can't just stub async.waterfall() and make it yield its done callback because I'll be left with crucial branches of the code untested (The inner done callbacks of the async.each() and the second async.waterfall(). I've tried to use sinon fake timers and used this.clock.tick(0); after invoking the MyClass.prototype.pipeline() function like so:

var obj = new MyClass();
obj.pipeline(5, 3);
this.clock.tick(0);
/* assertions */
...

But even so the assertions parts are being executed before any done function is being called. I tried to dig into the async library code to see how it calls its done functions be it's too much of a headache and I couldn't figure out why even tho the done callbacks calls are deferred and with the sinon fake timers, my assertion code is still executing first. If I use some nested setImmediate() calls it works fine, but that's the worst solution for this problem.

Aucun commentaire:

Enregistrer un commentaire