Spin wait in node.js

When writing acceptance tests, you often need to wait for something to happen. The easy thing to do is just wait for a certain period of time before checking, but that can make your tests slower than necessary. The accepted solution is to poll for whatever it is that you’re waiting for.

C# has a handy SpinWait.SpinUntil method, and I found this node module with similar behaviour. I needed it to work with promises though, so I ended up writing my own:

var DEFAULT_TIMEOUT = 5000;

function waitUntil (predicate, done, timeout, started) {
    timeout = defaultParameter(timeout, DEFAULT_TIMEOUT);
    started = defaultParameter(started, Date.now());

    predicate().done(function(res) {
        if (res) {
            return done();
        }

        if ((started + timeout) < Date.now()) {
            throw new Error("timed out");
        }

        setTimeout(function() {
            waitUntil(predicate, done, timeout, started);
        }, 100);
    });
};

function defaultParameter (parameter, defaultValue) {
    if (typeof(parameter) === 'undefined') {
        return defaultValue;
    }
    return parameter;
};

module.exports.waitUntil = waitUntil;

The first argument needs to be a predicate function, that returns a promise; and the second will be called if the first ever succeeds. You can also change the default timeout (5s). Something like this:

SpinWait.waitUntil(function() {
    return getAllTransactions(USER_ID).then(function(data) {
        return data.rows.length > 0;
    });
}, function() {
    getAllTransactions(USER_ID).done(function(data) {
        assert.equal(1, data.rows.length);
        var transaction = data.rows[0];
        assert.equal(1000, transaction.amount);
        done();
    });
});
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s