summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.jshintrc5
-rw-r--r--.travis.yml7
-rw-r--r--Makefile4
-rw-r--r--karma.conf.js12
-rw-r--r--lib/async.js17
-rw-r--r--mocha_test/compose.js86
-rw-r--r--mocha_test/forever.js44
-rw-r--r--mocha_test/support/is_browser.js4
-rw-r--r--package.json13
-rwxr-xr-xtest/test-async.js223
10 files changed, 274 insertions, 141 deletions
diff --git a/.jshintrc b/.jshintrc
index c66d74c..76be34a 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -21,6 +21,9 @@
"node": true,
"globals": {
"self": true,
- "define": true
+ "define": true,
+ "describe": true,
+ "context": true,
+ "it": true
}
}
diff --git a/.travis.yml b/.travis.yml
index 0a62fca..e225b8f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,4 +3,11 @@ node_js:
- "0.10"
- "0.12"
- "iojs-v2.1.0"
+sudo: false
after_success: npm run coveralls
+
+# Needed to run Karma with Firefox on Travis
+# http://karma-runner.github.io/0.13/plus/travis.html
+before_script:
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
diff --git a/Makefile b/Makefile
index 6609aa6..bd3c367 100644
--- a/Makefile
+++ b/Makefile
@@ -23,8 +23,8 @@ clean:
rm -rf $(BUILDDIR)
lint:
- $(JSHINT) $(SRC) test/*.js perf/*.js
- $(JSCS) $(SRC) test/*.js perf/*.js
+ $(JSHINT) $(SRC) test/*.js mocha_test/* perf/*.js
+ $(JSCS) $(SRC) test/*.js mocha_test/* perf/*.js
.PHONY: test lint build all clean
diff --git a/karma.conf.js b/karma.conf.js
new file mode 100644
index 0000000..9e048c3
--- /dev/null
+++ b/karma.conf.js
@@ -0,0 +1,12 @@
+module.exports = function (config) {
+ config.set({
+ browsers: ['Firefox'],
+ files: ['mocha_test/*.js'],
+ frameworks: ['browserify', 'mocha'],
+ preprocessors: {
+ 'mocha_test/*.js': ['browserify']
+ },
+ reporters: ['mocha'],
+ singleRun: true
+ });
+}
diff --git a/lib/async.js b/lib/async.js
index f3cfb80..9c2b6af 100644
--- a/lib/async.js
+++ b/lib/async.js
@@ -62,6 +62,12 @@
return _toString.call(obj) === '[object Array]';
};
+ // Ported from underscore.js isObject
+ var _isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
+ };
+
function _isArrayLike(arr) {
return _isArray(arr) || (
// has a positive integer length property
@@ -165,7 +171,6 @@
switch (startIndex) {
case 0: return func.call(this, rest);
case 1: return func.call(this, arguments[0], rest);
- case 2: return func.call(this, arguments[0], arguments[1], rest);
}
// Currently unused but handle cases outside of the switch statement:
// var args = Array(startIndex + 1);
@@ -593,7 +598,7 @@
acc.times = parseInt(t.times, 10) || DEFAULT_TIMES;
acc.interval = parseInt(t.interval, 10) || DEFAULT_INTERVAL;
} else {
- throw new Error('Unsupported argument type for \'times\': ' + typeof(t));
+ throw new Error('Unsupported argument type for \'times\': ' + typeof t);
}
}
@@ -1013,7 +1018,7 @@
function _console_fn(name) {
return _restParam(function (fn, args) {
fn.apply(null, args.concat([_restParam(function (err, args) {
- if (typeof console !== 'undefined') {
+ if (typeof console === 'object') {
if (err) {
if (console.error) {
console.error(err);
@@ -1186,7 +1191,7 @@
return callback(e);
}
// if result is Promise object
- if (typeof result !== 'undefined' && typeof result.then === "function") {
+ if (_isObject(result) && typeof result.then === "function") {
result.then(function(value) {
callback(null, value);
}).catch(function(err) {
@@ -1199,11 +1204,11 @@
};
// Node.js
- if (typeof module !== 'undefined' && module.exports) {
+ if (typeof module === 'object' && module.exports) {
module.exports = async;
}
// AMD / RequireJS
- else if (typeof define !== 'undefined' && define.amd) {
+ else if (typeof define === 'function' && define.amd) {
define([], function () {
return async;
});
diff --git a/mocha_test/compose.js b/mocha_test/compose.js
new file mode 100644
index 0000000..27b1869
--- /dev/null
+++ b/mocha_test/compose.js
@@ -0,0 +1,86 @@
+var async = require('../lib/async');
+var expect = require('chai').expect;
+
+describe('compose', function(){
+ context('all functions succeed', function(){
+ it('yields the result of the composition of the functions', function(done){
+ var add2 = function (n, cb) {
+ setTimeout(function () {
+ cb(null, n + 2);
+ });
+ };
+ var mul3 = function (n, cb) {
+ setTimeout(function () {
+ cb(null, n * 3);
+ });
+ };
+ var add1 = function (n, cb) {
+ setTimeout(function () {
+ cb(null, n + 1);
+ });
+ };
+ var add2mul3add1 = async.compose(add1, mul3, add2);
+ add2mul3add1(3, function (err, result) {
+ expect(err).to.not.exist;
+ expect(result).to.eql(16);
+ done();
+ });
+ });
+ });
+
+ context('a function errors', function(){
+ it('yields the error and does not call later functions', function(done){
+ var add1called = false;
+ var mul3error = new Error('mul3 error')
+ var add2 = function (n, cb) {
+ setTimeout(function () {
+ cb(null, n + 2);
+ });
+ };
+ var mul3 = function (n, cb) {
+ setTimeout(function () {
+ cb(mul3error);
+ });
+ };
+ var add1 = function (n, cb) {
+ add1called = true;
+ setTimeout(function () {
+ cb(null, n + 1);
+ });
+ };
+ var add2mul3add1 = async.compose(add1, mul3, add2);
+ add2mul3add1(3, function (err, result) {
+ expect(err).to.eql(mul3error);
+ expect(result).to.not.exist;
+ expect(add1called).to.be.false;
+ done();
+ });
+ });
+ });
+
+ it('calls each function with the binding of the composed function', function(done){
+ var context = {};
+ var add2Context = null;
+ var mul3Context = null;
+ var add2 = function (n, cb) {
+ add2Context = this;
+ setTimeout(function () {
+ cb(null, n + 2);
+ });
+ };
+ var mul3 = function (n, cb) {
+ mul3Context = this;
+ setTimeout(function () {
+ cb(null, n * 3);
+ });
+ };
+ var add2mul3 = async.compose(mul3, add2);
+ add2mul3.call(context, 3, function (err, result) {
+ expect(err).to.not.exist;
+ expect(result).to.eql(15);
+ expect(add2Context).to.equal(context);
+ expect(mul3Context).to.equal(context);
+ done();
+ });
+ });
+});
diff --git a/mocha_test/forever.js b/mocha_test/forever.js
new file mode 100644
index 0000000..970c422
--- /dev/null
+++ b/mocha_test/forever.js
@@ -0,0 +1,44 @@
+var async = require('../lib/async');
+var expect = require('chai').expect;
+var isBrowser = require('./support/is_browser');
+
+describe('forever', function(){
+ context('function is asynchronous', function(){
+ it('executes the function over and over until it yields an error', function(done){
+ var counter = 0;
+ function addOne(callback) {
+ counter++;
+ if (counter === 50) {
+ return callback('too big!');
+ }
+ async.setImmediate(function () {
+ callback();
+ });
+ }
+ async.forever(addOne, function (err) {
+ expect(err).to.eql('too big!');
+ expect(counter).to.eql(50);
+ done();
+ });
+ });
+ });
+
+ context('function is synchronous', function(){
+ it('does not cause a stack overflow', function(done){
+ if (isBrowser()) return done(); // this will take forever in a browser
+ var counter = 0;
+ function addOne(callback) {
+ counter++;
+ if (counter === 50000) { // needs to be huge to potentially overflow stack in node
+ return callback('too big!');
+ }
+ callback();
+ }
+ async.forever(addOne, function (err) {
+ expect(err).to.eql('too big!');
+ expect(counter).to.eql(50000);
+ done();
+ });
+ });
+ });
+});
diff --git a/mocha_test/support/is_browser.js b/mocha_test/support/is_browser.js
new file mode 100644
index 0000000..85e1522
--- /dev/null
+++ b/mocha_test/support/is_browser.js
@@ -0,0 +1,4 @@
+module.exports = function() {
+ return (typeof process === "undefined") ||
+ (process + "" !== "[object process]"); // browserify
+};
diff --git a/package.json b/package.json
index 4028e48..d0021ae 100644
--- a/package.json
+++ b/package.json
@@ -21,12 +21,19 @@
"devDependencies": {
"benchmark": "bestiejs/benchmark.js",
"bluebird": "^2.9.32",
+ "chai": "^3.1.0",
"coveralls": "^2.11.2",
"es6-promise": "^2.3.0",
"jscs": "^1.13.1",
"jshint": "~2.8.0",
+ "karma": "^0.13.2",
+ "karma-browserify": "^4.2.1",
+ "karma-firefox-launcher": "^0.1.6",
+ "karma-mocha": "^0.2.0",
+ "karma-mocha-reporter": "^1.0.2",
"lodash": "^3.9.0",
"mkdirp": "~0.5.1",
+ "mocha": "^2.2.5",
"native-promise-only": "^0.8.0-a",
"nodeunit": ">0.0.0",
"nyc": "^2.1.0",
@@ -47,7 +54,11 @@
]
},
"scripts": {
- "test": "npm run-script lint && nodeunit test/test-async.js",
+ "mocha-node-test": "mocha mocha_test/",
+ "mocha-browser-test": "karma start",
+ "mocha-test": "npm run mocha-node-test && npm run mocha-browser-test",
+ "nodeunit-test": "nodeunit test/test-async.js",
+ "test": "npm run-script lint && npm run nodeunit-test && npm run mocha-test",
"lint": "jshint lib/*.js test/*.js perf/*.js && jscs lib/*.js test/*.js perf/*.js",
"coverage": "nyc npm test && nyc report",
"coveralls": "nyc npm test && nyc report --reporter=text-lcov | coveralls"
diff --git a/test/test-async.js b/test/test-async.js
index fdb949b..dc7d949 100755
--- a/test/test-async.js
+++ b/test/test-async.js
@@ -1,3 +1,8 @@
+/**
+ * NOTE: We are in the process of migrating these tests to Mocha. If you are
+ * adding a new test, consider creating a new spec file in mocha_tests/
+ */
+
var async = require('../lib/async');
if (!Function.prototype.bind) {
@@ -85,50 +90,6 @@ function isBrowser() {
(process + "" !== "[object process]"); // browserify
}
-exports['forever'] = {
-
- 'async': function (test) {
- test.expect(2);
- var counter = 0;
- function addOne(callback) {
- counter++;
- if (counter === 50) {
- return callback('too big!');
- }
- async.setImmediate(function () {
- callback();
- });
- }
- async.forever(addOne, function (err) {
- test.equal(err, 'too big!');
- test.equal(counter, 50);
- test.done();
- });
-},
-
- 'sync': function (test) {
- if (isBrowser()) {
- // this will take forever in a browser
- return test.done();
- }
- test.expect(2);
- var counter = 0;
- function addOne(callback) {
- counter++;
- if (counter === 50000) { // needs to be huge to potentially overflow stack in node
- return callback('too big!');
- }
- callback();
- }
- async.forever(addOne, function (err) {
- test.equal(err, 'too big!');
- test.equal(counter, 50000);
- test.done();
- });
-}
-
-};
-
exports['applyEach'] = function (test) {
test.expect(5);
var call_order = [];
@@ -222,93 +183,6 @@ exports['applyEach partial application'] = function (test) {
});
};
-exports['compose'] = function (test) {
- test.expect(5);
- var add2 = function (n, cb) {
- test.equal(n, 3);
- setTimeout(function () {
- cb(null, n + 2);
- }, 50);
- };
- var mul3 = function (n, cb) {
- test.equal(n, 5);
- setTimeout(function () {
- cb(null, n * 3);
- }, 15);
- };
- var add1 = function (n, cb) {
- test.equal(n, 15);
- setTimeout(function () {
- cb(null, n + 1);
- }, 100);
- };
- var add2mul3add1 = async.compose(add1, mul3, add2);
- add2mul3add1(3, function (err, result) {
- if (err) {
- return test.done(err);
- }
- test.ok(err === null, err + " passed instead of 'null'");
- test.equal(result, 16);
- test.done();
- });
-};
-
-exports['compose error'] = function (test) {
- test.expect(3);
- var testerr = new Error('test');
-
- var add2 = function (n, cb) {
- test.equal(n, 3);
- setTimeout(function () {
- cb(null, n + 2);
- }, 50);
- };
- var mul3 = function (n, cb) {
- test.equal(n, 5);
- setTimeout(function () {
- cb(testerr);
- }, 15);
- };
- var add1 = function (n, cb) {
- test.ok(false, 'add1 should not get called');
- setTimeout(function () {
- cb(null, n + 1);
- }, 100);
- };
- var add2mul3add1 = async.compose(add1, mul3, add2);
- add2mul3add1(3, function (err) {
- test.equal(err, testerr);
- test.done();
- });
-};
-
-exports['compose binding'] = function (test) {
- test.expect(4);
- var testcontext = {name: 'foo'};
-
- var add2 = function (n, cb) {
- test.equal(this, testcontext);
- setTimeout(function () {
- cb(null, n + 2);
- }, 50);
- };
- var mul3 = function (n, cb) {
- test.equal(this, testcontext);
- setTimeout(function () {
- cb(null, n * 3);
- }, 15);
- };
- var add2mul3 = async.compose(mul3, add2);
- add2mul3.call(testcontext, 3, function (err, result) {
- if (err) {
- return test.done(err);
- }
- test.equal(this, testcontext);
- test.equal(result, 15);
- test.done();
- });
-};
-
exports['seq'] = function (test) {
test.expect(5);
var add2 = function (n, cb) {
@@ -728,6 +602,19 @@ exports['retry when all attempts succeeds'] = function(test) {
});
};
+exports['retry fails with invalid arguments'] = function(test) {
+ test.throws(function() {
+ async.retry("");
+ });
+ test.throws(function() {
+ async.retry();
+ });
+ test.throws(function() {
+ async.retry(function() {}, 2, function() {});
+ });
+ test.done();
+};
+
exports['retry with interval when all attempts succeeds'] = function(test) {
var times = 3;
var interval = 500;
@@ -2465,6 +2352,19 @@ exports['sortBy inverted'] = function(test){
});
};
+exports['sortBy error'] = function(test){
+ test.expect(1);
+ var error = new Error('asdas');
+ async.sortBy([{a:1},{a:15},{a:6}], function(x, callback){
+ async.setImmediate(function(){
+ callback(error);
+ });
+ }, function(err){
+ test.equal(err, error);
+ test.done();
+ });
+};
+
exports['apply'] = function(test){
test.expect(6);
var fn = function(){
@@ -2943,6 +2843,22 @@ exports['doWhilst callback params'] = function (test) {
);
};
+exports['doWhilst - error'] = function (test) {
+ test.expect(1);
+ var error = new Error('asdas');
+
+ async.doWhilst(
+ function (cb) {
+ cb(error);
+ },
+ function () {},
+ function (err) {
+ test.equal(err, error);
+ test.done();
+ }
+ );
+};
+
exports['during'] = function (test) {
var call_order = [];
@@ -3002,6 +2918,40 @@ exports['doDuring'] = function (test) {
);
};
+exports['doDuring - error test'] = function (test) {
+ test.expect(1);
+ var error = new Error('asdas');
+
+ async.doDuring(
+ function (cb) {
+ cb(error);
+ },
+ function () {},
+ function (err) {
+ test.equal(err, error);
+ test.done();
+ }
+ );
+};
+
+exports['doDuring - error iterator'] = function (test) {
+ test.expect(1);
+ var error = new Error('asdas');
+
+ async.doDuring(
+ function (cb) {
+ cb(null);
+ },
+ function (cb) {
+ cb(error);
+ },
+ function (err) {
+ test.equal(err, error);
+ test.done();
+ }
+ );
+};
+
exports['whilst optional callback'] = function (test) {
var counter = 0;
async.whilst(
@@ -4235,6 +4185,17 @@ exports['asyncify'] = {
});
},
+ 'asyncify null': function (test) {
+ var parse = async.asyncify(function() {
+ return null;
+ });
+ parse("{\"a\":1}", function (err, result) {
+ test.ok(!err);
+ test.ok(result === null);
+ test.done();
+ });
+ },
+
'variable numbers of arguments': function (test) {
async.asyncify(function (x, y, z) {
test.ok(arguments.length === 3);