insync
Version:
Higher-order functions and common patterns for asynchronous code. Node specific port of async.
1,675 lines (1,175 loc) • 143 kB
JavaScript
'use strict';
// Load Modules
var Code = require('code');
var Lab = require('lab');
var lab = exports.lab = Lab.script();
var Insync = require('../lib');
var Util = require('../lib/util');
// Declare internals
var internals = {};
internals.eachAsync = function (result) {
return function (item, callback) {
setTimeout(function () {
result.push(item);
callback(null);
}, item * 100);
};
};
internals.eachOfAsync = function (result) {
return function (value, key, callback) {
setTimeout(function () {
result.push([value, key]);
callback(null);
}, value * 100);
};
};
internals.mapAsync = function (result) {
return function (item, callback) {
setTimeout(function () {
var dbl = item + item;
result.push(dbl);
callback(null, dbl);
}, item * 100);
};
};
internals.filterAsync = function (callOrder) {
return function (item, callback) {
callOrder.push(item);
setTimeout(function () {
callback(null, item > 1);
}, item * 100);
};
};
internals.reduceAsync = function (callOrder) {
return function (memo, item, callback) {
callOrder.push(item);
setTimeout(function () {
callback(null, memo + item);
});
};
};
internals.doNothing = function () {
var args = Array.prototype.slice.call(arguments);
var callback = args.pop();
setTimeout(function () {
callback(null);
}, 100);
};
// Test aliases
var describe = lab.describe;
var it = lab.it;
var before = lab.before;
var after = lab.after;
var expect = Code.expect;
describe('Insync', function () {
describe('Collection', function () {
describe('each()', function () {
it('iterates over a collection of items in parallel', function (done) {
var result = [];
Insync.each([4, 3, 2, 1], internals.eachAsync(result), function (error) {
expect(error).to.not.exist();
expect(result).to.deep.equal([1, 2, 3, 4]);
done();
});
});
it('provides a default callback if one is not provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.each([4], internals.doNothing);
});
it('short circuits if the array is empty', function (done) {
Insync.each([], Util.noop, function (error) {
expect(error).to.not.exist();
done();
});
});
it('sends an error when it occurs', function (done) {
Insync.each([1], function (item, callback) {
setTimeout(function () {
callback(new Error('async error'));
});
}, function (error) {
expect(error).to.exist();
expect(error.message).to.equal('async error');
done();
});
});
it('is aliased as forEach()', function (done) {
expect(Insync.each).to.equal(Insync.forEach);
done();
});
});
describe('eachSeries()', function () {
it('iterates over a collection of items in series', function (done) {
var result = [];
Insync.eachSeries([1, 3, 2], internals.eachAsync(result), function (error) {
expect(error).to.not.exist();
expect(result).to.deep.equal([1, 3, 2]);
done();
});
});
it('provides a default callback if one is not provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.eachSeries([1], internals.doNothing);
});
it('short circuits if the array is empty', function (done) {
Insync.eachSeries([], Util.noop, function (error) {
expect(error).to.not.exist();
done();
});
});
it('sends an error when it occurs', function (done) {
Insync.eachSeries([1], function (item, callback) {
setTimeout(function () {
callback(new Error('async error'));
});
}, function (error) {
expect(error).to.exist();
expect(error.message).to.equal('async error');
done();
});
});
it('is aliased as forEachSeries()', function (done) {
expect(Insync.eachSeries).to.equal(Insync.forEachSeries);
done();
});
});
describe('eachLimit()', function () {
it('iterates over a collection with a limit', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.eachLimit(arr, 2, internals.eachAsync(result), function (err) {
expect(err).to.not.exist();
expect(result).to.deep.equal(arr);
done();
});
});
it('does not call iterator if array is empty', function (done) {
Insync.eachLimit([], 2, function (item, callback) {
expect(true).to.equal(false);
}, function (err) {
expect(err).to.not.exist();
done();
});
});
it('does not call iterator if limit is zero', function (done) {
Insync.eachLimit([1, 2, 3], 0, function (item, callback) {
expect(true).to.equal(false);
}, function (err) {
expect(err).to.not.exist();
done();
});
});
it('properly passes error to final callback', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.eachLimit(arr, 2, function (item, callback) {
result.push(item);
if (item === 2) {
return callback(new Error('foo'));
}
callback();
}, function (err) {
expect(err).to.exist();
expect(result).to.deep.equal([0, 1, 2]);
done();
});
});
it('provides a default callback if one is not provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.eachLimit([1, 2, 3, 4], 2, internals.doNothing);
});
it('is aliased as forEachLimit()', function (done) {
expect(Insync.eachLimit).to.equal(Insync.forEachLimit);
done();
});
});
describe('eachOf()', function () {
it('iterates over an array in parallel', function (done) {
var result = [];
Insync.eachOf([4, 3, 2, 1], internals.eachOfAsync(result), function (error) {
expect(error).to.not.exist();
expect(result).to.deep.equal([
[1, 3],
[2, 2],
[3, 1],
[4, 0]
]);
done();
});
});
it('iterates over an object in parallel', function (done) {
var result = [];
Insync.eachOf({
a: 4,
b: 3,
c: 2,
d: 1
}, internals.eachOfAsync(result), function (error) {
expect(error).to.not.exist();
expect(result).to.deep.equal([
[1, 'd'],
[2, 'c'],
[3, 'b'],
[4, 'a']
]);
done();
});
});
it('provides a default callback if one is not provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.eachOf([4], internals.doNothing);
});
it('short circuits if the array is empty', function (done) {
Insync.eachOf([], function (value, key, callback) {
expect(true).to.equal(false);
callback();
}, function (error) {
expect(error).to.not.exist();
done();
});
});
it('sends an error when it occurs', function (done) {
Insync.eachOf([1], function (value, key, callback) {
setTimeout(function () {
callback(new Error('async error'));
});
}, function (error) {
expect(error).to.exist();
expect(error.message).to.equal('async error');
done();
});
});
it('is aliased as forEachOf()', function (done) {
expect(Insync.eachOf).to.equal(Insync.forEachOf);
done();
});
});
describe('eachOfSeries()', function () {
it('iterates over an array in series', function (done) {
var result = [];
Insync.eachOfSeries([1, 3, 2], internals.eachOfAsync(result), function (error) {
expect(error).to.not.exist();
expect(result).to.deep.equal([
[1, 0],
[3, 1],
[2, 2]
]);
done();
});
});
it('iterates over an object in series', function (done) {
var result = [];
Insync.eachOfSeries({
a: 4,
b: 3,
c: 2,
d: 1
}, internals.eachOfAsync(result), function (error) {
expect(error).to.not.exist();
expect(result).to.deep.equal([
[4, 'a'],
[3, 'b'],
[2, 'c'],
[1, 'd']
]);
done();
});
});
it('provides a default callback if one is not provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.eachOfSeries([1], internals.doNothing);
});
it('short circuits if the array is empty', function (done) {
Insync.eachOfSeries([], Util.noop, function (error) {
expect(error).to.not.exist();
done();
});
});
it('sends an error when it occurs', function (done) {
Insync.eachOfSeries([1], function (value, key, callback) {
setTimeout(function () {
callback(new Error('async error'));
});
}, function (error) {
expect(error).to.exist();
expect(error.message).to.equal('async error');
done();
});
});
it('is aliased as forEachOfSeries()', function (done) {
expect(Insync.eachOfSeries).to.equal(Insync.forEachOfSeries);
done();
});
});
describe('eachOfLimit()', function () {
it('iterates over an array with a limit', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.eachOfLimit(arr, 2, internals.eachOfAsync(result), function (err) {
expect(err).to.not.exist();
expect(result).to.deep.equal([
[0, 0],
[1, 1],
[2, 2],
[3, 3]
]);
done();
});
});
it('iterates over an object with a limit', function (done) {
var obj = {
a: 0,
b: 1,
c: 2,
d: 3
};
var result = [];
Insync.eachOfLimit(obj, 2, internals.eachOfAsync(result), function (err) {
expect(err).to.not.exist();
expect(result).to.deep.equal([
[0, 'a'],
[1, 'b'],
[2, 'c'],
[3, 'd']
]);
done();
});
});
it('does not call iterator if array is empty', function (done) {
Insync.eachOfLimit([], 2, function (value, key, callback) {
expect(true).to.equal(false);
}, function (err) {
expect(err).to.not.exist();
done();
});
});
it('does not call iterator if limit is zero', function (done) {
Insync.eachOfLimit([1, 2, 3], 0, function (value, key, callback) {
expect(true).to.equal(false);
}, function (err) {
expect(err).to.not.exist();
done();
});
});
it('properly passes error to final callback', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.eachOfLimit(arr, 2, function (value, key, callback) {
result.push([value, key]);
if (value === 2) {
return callback(new Error('foo'));
}
callback();
}, function (err) {
expect(err).to.exist();
expect(result).to.deep.equal([
[0, 0],
[1, 1],
[2, 2]
]);
done();
});
});
it('provides a default callback if one is not provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.eachOfLimit([1, 2, 3, 4], 2, internals.doNothing);
});
it('is aliased as forEachOfLimit()', function (done) {
expect(Insync.eachOfLimit).to.equal(Insync.forEachOfLimit);
done();
});
});
describe('map()', function () {
it('creates a mapped version of input', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.map(arr, internals.mapAsync(result), function (err, mapped) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(mapped).to.deep.equal(result);
done();
});
});
it('works without final callback', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.map(arr, function (item, callback) {
result.push(item);
if (result.length === arr.length) {
expect(arr).to.deep.equal(result);
done();
}
callback(null, item);
});
});
it('properly passes error to final callback', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.map(arr, function (item, callback) {
result.push(item);
if (item === 2) {
return callback(new Error('foo'));
}
callback();
}, function (err) {
expect(err).to.exist();
expect(result).to.deep.equal([0, 1, 2]);
done();
});
});
});
describe('mapSeries()', function () {
it('creates a mapped version of input', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.mapSeries(arr, internals.mapAsync(result), function (err, mapped) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(mapped).to.deep.equal(result);
done();
});
});
it('properly passes error to final callback', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.mapSeries(arr, function (item, callback) {
result.push(item);
if (item === 2) {
return callback(new Error('foo'));
}
callback();
}, function (err) {
expect(err).to.exist();
expect(result).to.deep.equal([0, 1, 2]);
done();
});
});
});
describe('mapLimit()', function () {
it('iterates over a collection with a limit', function (done) {
var arr = [0, 1, 2, 3];
var result = [];
Insync.mapLimit(arr, 2, internals.mapAsync(result), function (err, mapped) {
expect(err).to.not.exist();
expect(result).to.deep.equal(mapped);
done();
});
});
});
describe('filter()', function () {
it('filters an array', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.filter(arr, internals.filterAsync(callOrder), function (err, results) {
expect(err).not.to.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(results).to.deep.equal([2, 3]);
done();
});
});
it('handles errors', function (done) {
var doneCalled = false;
Insync.filter([0, 1, 2], function (item, callback) {
setTimeout(function () {
callback(new Error('foo'));
}, 50);
}, function (err, results) {
expect(err).to.exist();
expect(results).to.not.exist();
expect(doneCalled).to.equal(false);
doneCalled = true;
setTimeout(done, 100);
});
});
it('is aliased as select()', function (done) {
expect(Insync.filter).to.equal(Insync.select);
done();
});
});
describe('filterSeries()', function () {
it('filters an array in series', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.filterSeries(arr, internals.filterAsync(callOrder), function (err, results) {
expect(err).not.to.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(callOrder).to.deep.equal(arr);
expect(results).to.deep.equal([2, 3]);
done();
});
});
it('is aliased as selectSeries()', function (done) {
expect(Insync.filterSeries).to.equal(Insync.selectSeries);
done();
});
});
describe('reject()', function () {
it('filters an array', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.reject(arr, internals.filterAsync(callOrder), function (err, results) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(results).to.deep.equal([0, 1]);
done();
});
});
it('handles errors', function (done) {
var doneCalled = false;
Insync.reject([0, 1, 2], function (item, callback) {
setTimeout(function () {
callback(new Error('foo'));
}, 50);
}, function (err, results) {
expect(err).to.exist();
expect(results).to.not.exist();
expect(doneCalled).to.equal(false);
doneCalled = true;
setTimeout(done, 100);
});
});
});
describe('rejectSeries()', function () {
it('filters an array in series', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.rejectSeries(arr, internals.filterAsync(callOrder), function (err, results) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(callOrder).to.deep.equal(arr);
expect(results).to.deep.equal([0, 1]);
done();
});
});
});
describe('reduce()', function () {
it('reduces an array', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.reduce(arr, 0, internals.reduceAsync(callOrder), function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(6);
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(callOrder).to.deep.equal(arr);
done();
});
});
it('handles errors', function (done) {
var doneCalled = false;
Insync.reduce([1, 2, 3], 0, function (a, x, callback) {
callback(new Error());
}, function (err) {
expect(err).to.exist();
expect(doneCalled).to.equal(false);
doneCalled = true;
setTimeout(done, 100);
});
});
it('is aliased as inject()', function (done) {
expect(Insync.reduce).to.equal(Insync.inject);
done();
});
it('is aliased as foldl()', function (done) {
expect(Insync.reduce).to.equal(Insync.foldl);
done();
});
});
describe('reduceRight()', function () {
it('reduces an array', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.reduceRight(arr, 0, internals.reduceAsync(callOrder), function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(6);
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(callOrder).to.deep.equal([3, 2, 1, 0]);
done();
});
});
it('is aliased as foldr()', function (done) {
expect(Insync.reduceRight).to.equal(Insync.foldr);
done();
});
});
describe('detect()', function () {
it('returns the first value that passes test', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.detect(arr, function (item, callback) {
callOrder.push(item);
setTimeout(function () {
callback(null, item === 2);
}, 100);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(2);
done();
});
});
it('returns undefined when no items pass test', function (done) {
var arr = [0, 1, 2, 3];
var callOrder = [];
Insync.detect(arr, function (item, callback) {
callOrder.push(item);
setTimeout(function () {
callback(null, item === 6);
}, 100);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(undefined);
done();
});
});
it('handles errors', function (done) {
var arr = [0, 1, 2, 3];
Insync.detect(arr, function (item, callback) {
setTimeout(function () {
callback(new Error('foo'));
}, 100);
}, function (err, result) {
expect(err).to.exist();
expect(result).to.not.exist();
done();
});
});
});
describe('detectSeries()', function () {
it('detects in series', function (done) {
var callOrder = [];
Insync.detectSeries([3, 2, 1], function (item, callback) {
callOrder.push(item);
setTimeout(function () {
callback(null, item === 2);
}, 10);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(2);
expect(callOrder).to.deep.equal([3, 2]);
done();
});
});
it('stops on a match', function (done) {
Insync.detectSeries([1, 2, 3, 4], function (item, callback) {
expect(item).to.be.at.most(3);
callback(null, item === 3);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(3);
done();
});
});
it('handles errors', function (done) {
var arr = [0, 1, 2, 3];
Insync.detectSeries(arr, function (item, callback) {
setTimeout(function () {
callback(new Error('foo'));
}, 100);
}, function (err, result) {
expect(err).to.exist();
expect(result).to.not.exist();
done();
});
});
});
describe('some()', function () {
it('returns true if at least one element satisfies test', function (done) {
var arr = [0, 1, 2, 3];
Insync.some(arr, function (item, callback) {
setTimeout(function () {
callback(null, item === 2);
}, 100);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(true);
done();
});
});
it('returns false if no elements satisfies test', function (done) {
var arr = [0, 1, 2, 3];
Insync.some(arr, function (item, callback) {
setTimeout(function () {
callback(null, item === 6);
}, 100);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(false);
done();
});
});
it('returns early on match', function (done) {
var callOrder = [];
Insync.some([1, 2, 3], function (item, callback) {
setTimeout(function () {
callOrder.push(item);
callback(null, item === 1);
}, item * 25);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(true);
expect(callOrder).to.deep.equal([1]);
// note that 2 and 3 are still executed
done();
});
});
it('handles errors', function (done) {
Insync.some([1, 2, 3], function (item, callback) {
setTimeout(function () {
callback(new Error('foo'));
}, 100);
}, function (err, result) {
expect(err).to.exist();
expect(result).to.not.exist();
done();
});
});
it('is aliased as any()', function (done) {
expect(Insync.some).to.equal(Insync.any);
done();
});
});
describe('every()', function () {
it('returns true if every element satisfies test', function (done) {
var arr = [0, 1, 2, 3];
Insync.every(arr, function (item, callback) {
setTimeout(function () {
callback(null, item >= 0 && item < 4);
}, 100);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(true);
done();
});
});
it('returns false if any element fails test', function (done) {
var arr = [0, 1, 2, 3];
Insync.every(arr, function (item, callback) {
setTimeout(function () {
callback(null, item >= 1);
}, 100);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(false);
done();
});
});
it('returns early on failure', function (done) {
var callOrder = [];
Insync.every([1, 2, 3], function (item, callback) {
setTimeout(function () {
callOrder.push(item);
callback(null, item === 1);
}, item * 25);
}, function (err, result) {
expect(err).to.not.exist();
expect(result).to.equal(false);
expect(callOrder).to.deep.equal([1, 2]);
// note that 3 is still executed
done();
});
});
it('handles errors', function (done) {
Insync.every([1, 2, 3], function (item, callback) {
setTimeout(function () {
callback(new Error('foo'));
}, 100);
}, function (err, result) {
expect(err).to.exist();
expect(result).to.not.exist();
done();
});
});
it('is aliased as all()', function (done) {
expect(Insync.every).to.equal(Insync.all);
done();
});
});
describe('concat()', function () {
it('concatenates results', function (done) {
var arr = [0, 1, 2, 3];
Insync.concat(arr, function (item, callback) {
setTimeout(function () {
callback(null, [item, item]);
}, 100);
}, function (err, results) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(results).to.deep.equal([0, 0, 1, 1, 2, 2, 3, 3]);
done();
});
});
it('creates empty array when iterator returns no results', function (done) {
var arr = [0, 1, 2, 3];
Insync.concat(arr, function (item, callback) {
setTimeout(function () {
callback(null);
}, 100);
}, function (err, results) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(results).to.deep.equal([]);
done();
});
});
});
describe('concatSeries()', function () {
it('concatenates results in series', function (done) {
var arr = [0, 1, 2, 3];
Insync.concatSeries(arr, function (item, callback) {
setTimeout(function () {
callback(null, [item, item]);
}, 100);
}, function (err, results) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([0, 1, 2, 3]);
expect(results).to.deep.equal([0, 0, 1, 1, 2, 2, 3, 3]);
done();
});
});
});
describe('sortBy()', function () {
it('performs an asynchronous sort', function (done) {
var arr = [3, 1, 0, 2, 0];
Insync.sortBy(arr, function (item, callback) {
setTimeout(function () {
callback(null, item);
}, 50);
}, function (err, result) {
expect(err).to.not.exist();
expect(arr).to.deep.equal([3, 1, 0, 2, 0]);
expect(result).to.deep.equal([0, 0, 1, 2, 3]);
done();
});
});
it('handles errors properly', function (done) {
var arr = [3, 1, 0, 2, 0];
Insync.sortBy(arr, function (item, callback) {
setTimeout(function () {
if (item === 2) {
return callback(new Error('foo'));
}
callback(null, item);
}, 50);
}, function (err, result) {
expect(err).to.exist();
expect(arr).to.deep.equal([3, 1, 0, 2, 0]);
expect(result).to.not.exist();
done();
});
});
});
});
describe('Flow', function () {
describe('series()', function () {
it('executes array of functions in series', function (done) {
var callOrder = [];
Insync.series([
function (callback) { setTimeout(function () { callOrder.push(0); callback(null, 0); }, 100); },
function (callback) { setTimeout(function () { callOrder.push(1); callback(null, 1); }, 100); },
function (callback) { setTimeout(function () { callOrder.push(2); callback(null, 2, 3); }, 10); }
], function (err, results) {
expect(err).to.not.exist();
expect(callOrder).to.deep.equal([0, 1, 2]);
expect(results).to.deep.equal([0, 1, [2, 3]]);
done();
});
});
it('executes object of functions in series', function (done) {
var callOrder = [];
Insync.series({
zero: function (callback) { setTimeout(function () { callOrder.push(0); callback(null, 0); }, 100); },
one: function (callback) { setTimeout(function () { callOrder.push(1); callback(null, 1); }, 100); },
two: function (callback) { setTimeout(function () { callOrder.push(2); callback(null, 2, 3); }, 10); }
}, function (err, results) {
expect(err).to.not.exist();
expect(callOrder).to.deep.equal([0, 1, 2]);
expect(results).to.deep.equal({ zero: 0, one: 1, two: [2, 3] });
done();
});
});
it('handles empty array of functions', function (done) {
Insync.series([], function (err, results) {
expect(err).to.not.exist();
expect(results).to.deep.equal([]);
done();
});
});
it('handles array functions that call back with no arguments', function (done) {
Insync.series([
function (callback) { setTimeout(function () { callback(); }, 100); }
], function (err, results) {
expect(err).to.not.exist();
expect(results).to.deep.equal([undefined]);
done();
});
});
it('handles object functions that call back with no arguments', function (done) {
Insync.series({
zero: function (callback) { setTimeout(function () { callback(); }, 100); }
}, function (err, results) {
expect(err).to.not.exist();
expect(results).to.deep.equal({ zero: undefined });
done();
});
});
it('handles errors when an array is passed', function (done) {
Insync.series([
function (callback) { setTimeout(function () { callback(new Error()); }, 100); }
], function (err, results) {
expect(err).to.exist();
done();
});
});
it('handles errors when an object is passed', function (done) {
Insync.series({
zero: function (callback) { setTimeout(function () { callback(new Error()); }, 100); }
}, function (err, results) {
expect(err).to.exist();
done();
});
});
it('handles case where no callback is provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.series({
zero: function (callback) { setTimeout(function () { callback(null, 0); }, 100); }
});
});
});
describe('parallel()', function () {
it('executes array of functions in parallel', function (done) {
var callOrder = [];
Insync.parallel([
function (callback) { setTimeout(function () { callOrder.push(0); callback(null, 0); }, 50); },
function (callback) { setTimeout(function () { callOrder.push(1); callback(null, 1); }, 100); },
function (callback) { setTimeout(function () { callOrder.push(2); callback(null, 2, 3); }, 10); }
], function (err, results) {
expect(err).to.not.exist();
expect(callOrder).to.deep.equal([2, 0, 1]);
expect(results).to.deep.equal([0, 1, [2, 3]]);
done();
});
});
it('executes object of functions in parallel', function (done) {
var callOrder = [];
Insync.parallel({
zero: function (callback) { setTimeout(function () { callOrder.push(0); callback(null, 0); }, 50); },
one: function (callback) { setTimeout(function () { callOrder.push(1); callback(null, 1); }, 100); },
two: function (callback) { setTimeout(function () { callOrder.push(2); callback(null, 2, 3); }, 10); }
}, function (err, results) {
expect(err).to.not.exist();
expect(callOrder).to.deep.equal([2, 0, 1]);
expect(results).to.deep.equal({ zero: 0, one: 1, two: [2, 3] });
done();
});
});
it('handles case where no callback is provided', function (done) {
var noop = Util.noop;
Util.noop = function (error) {
Util.noop = noop;
expect(error).to.not.exist();
done();
};
Insync.parallel({
zero: function (callback) { setTimeout(function () { callback(null, 0); }, 100); }
});
});
it('handles callbacks that pass no arguments', function (done) {
var callOrder = [];
Insync.parallel({
zero: function (callback) { setTimeout(function () { callOrder.push(0); callback(); }, 50); },
one: function (callback) { setTimeout(function () { callOrder.push(1); callback(); }, 100); },
two: function (callback) { setTimeout(function () { callOrder.push(2); callback(); }, 10); }
}, function (err, results) {
expect(err).to.not.exist();
expect(callOrder).to.deep.equal([2, 0, 1]);
expect(results).to.deep.equal({ zero: undefined, one: undefined, two: undefined });
done();
});
});
});
describe('whilst()', function () {
it('executes an asynchronous while loop', function (done) {
var callOrder = [];
var count = 0;
Insync.whilst(function () {
callOrder.push(['test', count]);
return count < 5;
}, function (callback) {
callOrder.push(['iterator', count]);
setTimeout(function () {
count++;
callback();
}, 10);
}, function (err) {
expect(err).to.not.exist();
expect(count).to.equal(5);
expect(callOrder).to.deep.equal([
['test', 0],
['iterator', 0], ['test', 1],
['iterator', 1], ['test', 2],
['iterator', 2], ['test', 3],
['iterator', 3], ['test', 4],
['iterator', 4], ['test', 5]
]);
done();
});
});
it('handles errors in iterator', function (done) {
var callOrder = [];
var count = 0;
Insync.whilst(function () {
callOrder.push(['test', count]);
return count < 5;
}, function (callback) {
callOrder.push(['iterator', count]);
setTimeout(function () {
count++;
if (count === 2) {
return callback(new Error('foo'));
}
callback();
}, 50);
}, function (err) {
expect(err).to.exist();
expect(count).to.equal(2);
expect(callOrder).to.deep.equal([
['test', 0],
['iterator', 0], ['test', 1],
['iterator', 1]
]);
done();
});
});
});
describe('doWhilst()', function () {
it('executes an asynchronous do...while loop', function (done) {
var callOrder = [];
var count = 0;
Insync.doWhilst(function (callback) {
callOrder.push(['iterator', count]);
setTimeout(function () {
count++;
callback();
}, 10);
}, function () {
callOrder.push(['test', count]);
return count < 5;
}, function (err) {
expect(err).to.not.exist();
expect(count).to.equal(5);
expect(callOrder).to.deep.equal([
['iterator', 0], ['test', 1],
['iterator', 1], ['test', 2],
['iterator', 2], ['test', 3],
['iterator', 3], ['test', 4],
['iterator', 4], ['test', 5]
]);
done();
});
});
it('iterator calls back with arguments', function (done) {
var callOrder = [];
var count = 0;
Insync.doWhilst(function (callback) {
callOrder.push(['iterator', count]);
setTimeout(function () {
count++;
callback(null, count);
}, 10);
}, function (cnt) {
callOrder.push(['test', cnt]);
return cnt < 5;
}, function (err) {
expect(err).to.not.exist();
expect(count).to.equal(5);
expect(callOrder).to.deep.equal([
['iterator', 0], ['test', 1],
['iterator', 1], ['test', 2],
['iterator', 2], ['test', 3],
['iterator', 3], ['test', 4],
['iterator', 4], ['test', 5]
]);
done();
});
});
it('handles errors in iterator', function (done) {
var callOrder = [];
var count = 0;
Insync.doWhilst(function (callback) {
callOrder.push(['iterator', count]);
setTimeout(function () {
count++;
if (count === 2) {
return callback(new Error('foo'));
}
callback();
}, 50);
}, function () {
callOrder.push(['test', count]);
return count < 5;
}, function (err) {
expect(err).to.exist();
expect(count).to.equal(2);
expect(callOrder).to.deep.equal([
['iterator', 0], ['test', 1],
['iterator', 1]
]);
done();
});
});
});
describe('until()', function () {
it('executes an asynchronous until loop', function (done) {
var callOrder = [];
var count = 0;
Insync.until(function () {
callOrder.push(['test', count]);
return count === 5;
}, function (callback) {
callOrder.push(['iterator', count]);
setTimeout(function () {
count++;
callback();
}, 10);
}, function (err) {
expect(err).to.not.exist();
expect(count).to.equal(5);
expect(callOrder).to.deep.equal([
['test', 0],
['iterator', 0], ['test', 1],
['iterator', 1], ['test', 2],
['iterator', 2],