diff --git a/test/init/patched.test.js b/test/init/patched.test.js index 64ed66b..72345c1 100644 --- a/test/init/patched.test.js +++ b/test/init/patched.test.js @@ -7,7 +7,7 @@ // Modules var expect = require('chai').expect, - _ = require('lodash'); + _ = require('lodash'); // Imports var runTests = require('../support'); @@ -15,96 +15,96 @@ var runTests = require('../support'); // Run tests runTests('Patch', function(u, Promise) { - describe('patches', function() { - describe('static method', function() { - var ignore = [ - 'onPossiblyUnhandledRejection', - 'onUnhandledRejectionHandled', - 'longStackTraces', - 'hasLongStackTraces', - 'config', - 'getNewLibraryCopy', - 'is', - 'fromCallback', - 'fromNode', - 'promisify', - 'promisifyAll', - 'all', - 'props', - 'any', - 'some', - 'race', - 'resolve', - 'fulfilled', - 'cast', - 'reject', - 'rejected', - 'setScheduler', - 'method', - 'try', - 'attempt', - 'bind', - 'settle', - 'delay', - 'defer', - 'pending', - 'clone' // comes from bluebird2 / bluebird3 libraries not bluebird itself - ]; - - checkPatched(Promise, ignore); - }); - - describe('prototype method', function() { - var ignore = [ - 'catch', // TODO only ignore on bluebird v3 - 'caught', // TODO only ignore on bluebird v3 - 'error', - 'all', - 'props', - 'any', - 'some', - 'race', - 'bind', - 'isFulfilled', - 'isRejected', - 'isPending', - 'isCancelled', - 'isResolved', - 'value', - 'reason', - 'reflect', - 'settle', - 'delay', - 'timeout', - 'get', - 'return', - 'thenReturn', - 'throw', - 'thenThrow', - 'catchReturn', - 'catchThrow', - 'cancel', - 'break', - 'isCancellable', - 'cancellable', - 'uncancellable', - 'suppressUnhandledRejections', - 'toString', - 'toJSON' - ]; - checkPatched(Promise.prototype, ignore); - }); - }); - - describe('maintains method equality', function() { - it('static methods', function() { - checkEqual(Promise, u.UnpatchedPromise); - }); - - it('prototype methods', function() { - checkEqual(Promise.prototype, u.UnpatchedPromise.prototype); - }); - }); + describe('patches', function() { + describe('static method', function() { + var ignore = [ + 'onPossiblyUnhandledRejection', + 'onUnhandledRejectionHandled', + 'longStackTraces', + 'hasLongStackTraces', + 'config', + 'getNewLibraryCopy', + 'is', + 'fromCallback', + 'fromNode', + 'promisify', + 'promisifyAll', + 'all', + 'props', + 'any', + 'some', + 'race', + 'resolve', + 'fulfilled', + 'cast', + 'reject', + 'rejected', + 'setScheduler', + 'method', + 'try', + 'attempt', + 'bind', + 'settle', + 'delay', + 'defer', + 'pending', + 'clone' // comes from bluebird2 / bluebird3 libraries not bluebird itself + ]; + + checkPatched(Promise, ignore); + }); + + describe('prototype method', function() { + var ignore = [ + 'catch', // TODO only ignore on bluebird v3 + 'caught', // TODO only ignore on bluebird v3 + 'error', + 'all', + 'props', + 'any', + 'some', + 'race', + 'bind', + 'isFulfilled', + 'isRejected', + 'isPending', + 'isCancelled', + 'isResolved', + 'value', + 'reason', + 'reflect', + 'settle', + 'delay', + 'timeout', + 'get', + 'return', + 'thenReturn', + 'throw', + 'thenThrow', + 'catchReturn', + 'catchThrow', + 'cancel', + 'break', + 'isCancellable', + 'cancellable', + 'uncancellable', + 'suppressUnhandledRejections', + 'toString', + 'toJSON' + ]; + checkPatched(Promise.prototype, ignore); + }); + }); + + describe('maintains method equality', function() { + it('static methods', function() { + checkEqual(Promise, u.UnpatchedPromise); + }); + + it('prototype methods', function() { + checkEqual(Promise.prototype, u.UnpatchedPromise.prototype); + }); + }); }); /** @@ -117,15 +117,15 @@ runTests('Patch', function(u, Promise) { * @returns {undefined} */ function checkPatched(obj, ignore) { - _.forIn(obj, function(method, name) { - if (name.match(/^[A-Z_]/)) return; - if (ignore.indexOf(name) !== -1) return; - if (typeof method !== 'function') return; - - it(name, function() { - if (!method.__wrapped) throw new Error("'" + name + "' method not patched"); // jshint ignore:line - }); - }); + _.forIn(obj, function(method, name) { + if (name.match(/^[A-Z_]/)) return; + if (ignore.indexOf(name) !== -1) return; + if (typeof method !== 'function') return; + + it(name, function() { + if (!method.__wrapped) throw new Error("'" + name + "' method not patched"); // jshint ignore:line + }); + }); } /** @@ -136,46 +136,46 @@ function checkPatched(obj, ignore) { * @throws {AssertionError} - If patching has changed things */ function checkEqual(obj, unpatchedObj) { - var matchesUnpatched = getEquals(unpatchedObj); - var matchesPatched = getEquals(obj); + var matchesUnpatched = getEquals(unpatchedObj); + var matchesPatched = getEquals(obj); - expect(matchesPatched).to.deep.equal(matchesUnpatched); + expect(matchesPatched).to.deep.equal(matchesUnpatched); } /** * Loop through all object's methods and return array of any which are equal to each other. * e.g. `obj.method1 == obj.method2, obj.method3 == obj.method4` - * -> [ ['method1', 'method2'], ['method3', 'method4'] ] + * -> [ ['method1', 'method2'], ['method3', 'method4'] ] * * @param {Object} obj - Object whose methods to check * @returns {Array} - Array of matches */ function getEquals(obj) { - var keys = Object.keys(obj).sort(); - - var matches = [], - matched = []; - keys.forEach(function(key) { - var method = obj[key]; - if (typeof method !== 'function') return; - if (matches.indexOf(key) !== -1) return; - - var thisMatches = []; - keys.forEach(function(otherKey) { - if (otherKey <= key) return; - - var otherMethod = obj[otherKey]; - if (method === otherMethod) { - thisMatches.push(otherKey); - matched.push(otherKey); - } - }); - - if (thisMatches.length) { - thisMatches.unshift(key); - matches.push(thisMatches); - } - }); - - return matches; + var keys = Object.keys(obj).sort(); + + var matches = [], + matched = []; + keys.forEach(function(key) { + var method = obj[key]; + if (typeof method !== 'function') return; + if (matches.indexOf(key) !== -1) return; + + var thisMatches = []; + keys.forEach(function(otherKey) { + if (otherKey <= key) return; + + var otherMethod = obj[otherKey]; + if (method === otherMethod) { + thisMatches.push(otherKey); + matched.push(otherKey); + } + }); + + if (thisMatches.length) { + thisMatches.unshift(key); + matches.push(thisMatches); + } + }); + + return matches; } diff --git a/test/methods/bind.test.js b/test/methods/bind.test.js index 3a5c518..97bc356 100644 --- a/test/methods/bind.test.js +++ b/test/methods/bind.test.js @@ -9,13 +9,13 @@ var runTests = require('../support'); // Run tests runTests('Promise.bind()', function(u, Promise) { - u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { - return Promise.bind(value); - }); + u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { + return Promise.bind(value); + }); }); runTests('.bind()', function(u) { - u.testSetProtoMethodReceivingValueReturnsPromise(function(p, value) { - return p.bind(value); - }); + u.testSetProtoMethodReceivingValueReturnsPromise(function(p, value) { + return p.bind(value); + }); }); diff --git a/test/methods/catch.test.js b/test/methods/catch.test.js index 01d16cd..c6dada6 100644 --- a/test/methods/catch.test.js +++ b/test/methods/catch.test.js @@ -14,24 +14,24 @@ var runTests = require('../support'); // Run tests runTests('.catch()', function(u) { - describe('with 1st arg', function() { - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return p.catch(handler); - }, {catches: true}); - }); + describe('with 1st arg', function() { + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return p.catch(handler); + }, {catches: true}); + }); - describe('with 2nd arg', function() { - // NB In bluebird v3 handler is not bound when on 2nd arg. - // `.catch()` calls `.then()` synchronously but with proxy handler. - // No way to test for binding. - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return p.catch(Error, handler); - }, {catches: true, noUndefined: true, noBindTest: (u.bluebirdVersion === 3)}); - }); + describe('with 2nd arg', function() { + // NB In bluebird v3 handler is not bound when on 2nd arg. + // `.catch()` calls `.then()` synchronously but with proxy handler. + // No way to test for binding. + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return p.catch(Error, handler); + }, {catches: true, noUndefined: true, noBindTest: (u.bluebirdVersion === 3)}); + }); }); runTests('.caught()', function(u, Promise) { // jshint ignore:line - it('is alias of .catch()', function() { - expect(Promise.prototype.caught).to.equal(Promise.prototype.catch); - }); + it('is alias of .catch()', function() { + expect(Promise.prototype.caught).to.equal(Promise.prototype.catch); + }); }); diff --git a/test/methods/constructor.test.js b/test/methods/constructor.test.js index 629d901..9436a9a 100644 --- a/test/methods/constructor.test.js +++ b/test/methods/constructor.test.js @@ -11,66 +11,66 @@ var runTests = require('../support'); // Run tests runTests('new Promise()', function(u, Promise) { - describe('returns instance of patched Promise constructor when', function() { - u.describeResolveRejectSyncAsync(function(makePromise) { - u.testIsPromise(function() { - return makePromise(); - }); - }, Promise, {continues: true, catches: true}); + describe('returns instance of patched Promise constructor when', function() { + u.describeResolveRejectSyncAsync(function(makePromise) { + u.testIsPromise(function() { + return makePromise(); + }); + }, Promise, {continues: true, catches: true}); - /* - // TODO test for when resolved with promise e.g. `new Promise(function(resolve) { resolve(Promise.resolve(); )})` - describe('resolves with', function() { - testValues(function(value) { - return new Promise(function(resolve) { - resolve(value); - }); - }); - }); + /* + // TODO test for when resolved with promise e.g. `new Promise(function(resolve) { resolve(Promise.resolve(); )})` + describe('resolves with', function() { + testValues(function(value) { + return new Promise(function(resolve) { + resolve(value); + }); + }); + }); - describe('rejects with', function() { - testValues(function(value) { - var p = new Promise(function(resolve, reject) { // jshint ignore:line - reject(value); - }); - u.setRejectStatus(p); - return p; - }); - }); + describe('rejects with', function() { + testValues(function(value) { + var p = new Promise(function(resolve, reject) { // jshint ignore:line + reject(value); + }); + u.setRejectStatus(p); + return p; + }); + }); - function testValues(fn) { - u.describeValues(function(makeValue) { - u.testIsPromise(function() { - var value = makeValue(); - var p = fn(value); - u.inheritRejectStatus(p, value); - return p; - }); - }); - } - */ + function testValues(fn) { + u.describeValues(function(makeValue) { + u.testIsPromise(function() { + var value = makeValue(); + var p = fn(value); + u.inheritRejectStatus(p, value); + return p; + }); + }); + } + */ - it('unresolved', function(done) { - var p = new Promise(function() {}); - done(u.checkIsPromise(p)); - }); + it('unresolved', function(done) { + var p = new Promise(function() {}); + done(u.checkIsPromise(p)); + }); - describe('handler throws', function() { - u.testIsPromise(function() { - var p = new Promise(function() { - throw u.makeError(); - }); - u.setRejectStatus(p); - return p; - }); - }); - }); + describe('handler throws', function() { + u.testIsPromise(function() { + var p = new Promise(function() { + throw u.makeError(); + }); + u.setRejectStatus(p); + return p; + }); + }); + }); - var testFn = function(handler) { - return new Promise(handler); - }; + var testFn = function(handler) { + return new Promise(handler); + }; - u.testSetStaticCallbackSync(testFn, {handler: function(resolve) { resolve(); }}); + u.testSetStaticCallbackSync(testFn, {handler: function(resolve) { resolve(); }}); - u.testSetStaticCallbackNotBound(testFn, {handler: function(resolve) { resolve(); }}); + u.testSetStaticCallbackNotBound(testFn, {handler: function(resolve) { resolve(); }}); }); diff --git a/test/methods/error.test.js b/test/methods/error.test.js index 57ca662..edafbbc 100644 --- a/test/methods/error.test.js +++ b/test/methods/error.test.js @@ -9,10 +9,10 @@ var runTests = require('../support'); // Run tests runTests('.error()', function(u) { - // NB In bluebird v3 handler is not bound. - // `.error()` calls `.catch()` synchronously which calls `.then()` synchronously but with proxy handler. - // No way to test for binding. - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return p.error(handler); - }, {catches: true, noUndefined: true, noBindTest: (u.bluebirdVersion === 3)}); + // NB In bluebird v3 handler is not bound. + // `.error()` calls `.catch()` synchronously which calls `.then()` synchronously but with proxy handler. + // No way to test for binding. + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return p.error(handler); + }, {catches: true, noUndefined: true, noBindTest: (u.bluebirdVersion === 3)}); }); diff --git a/test/methods/finally.test.js b/test/methods/finally.test.js index a68453f..221cd1d 100644 --- a/test/methods/finally.test.js +++ b/test/methods/finally.test.js @@ -14,13 +14,13 @@ var runTests = require('../support'); // Run tests runTests('.finally()', function(u) { - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return p.finally(handler); - }, {catches: true, continues: true, passThrough: true}); + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return p.finally(handler); + }, {catches: true, continues: true, passThrough: true}); }); runTests('.lastly()', function(u, Promise) { // jshint ignore:line - it('is alias of .finally()', function() { - expect(Promise.prototype.lastly).to.equal(Promise.prototype.finally); - }); + it('is alias of .finally()', function() { + expect(Promise.prototype.lastly).to.equal(Promise.prototype.finally); + }); }); diff --git a/test/methods/join.test.js b/test/methods/join.test.js index 35c1574..4ab6163 100644 --- a/test/methods/join.test.js +++ b/test/methods/join.test.js @@ -13,35 +13,35 @@ var runTests = require('../support'); // TODO Intersect two promise return test sets - test all combinations of promise values and handler return values. // This will make it work like the collection method tests. runTests('.join()', function(u, Promise) { - u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { - return Promise.join(value, value, value); - }); + u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { + return Promise.join(value, value, value); + }); - /* - * NB Due to oddity in bluebird https://github.com/petkaantonov/bluebird/issues/1153 - * `Promise.join()` calls the callback synchronously if input is only values or - * resolved promises, but async if any promises are pending. - * So async calling test is performed separately to allow for this. - * TODO Change test once issue is fixed (if it is considered a bug). - */ - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return Promise.join(p, p, p, handler); - }, {noUndefined: true, noAsyncTest: true}); + /* + * NB Due to oddity in bluebird https://github.com/petkaantonov/bluebird/issues/1153 + * `Promise.join()` calls the callback synchronously if input is only values or + * resolved promises, but async if any promises are pending. + * So async calling test is performed separately to allow for this. + * TODO Change test once issue is fixed (if it is considered a bug). + */ + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return Promise.join(p, p, p, handler); + }, {noUndefined: true, noAsyncTest: true}); - // Check callback called sync/async - describe('calls callback', function() { - describe('synchronously when promises are resolved', function() { - u.testSync(function(handler, cb) { - var p = Promise.join(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), handler); - cb(p); - }); - }); + // Check callback called sync/async + describe('calls callback', function() { + describe('synchronously when promises are resolved', function() { + u.testSync(function(handler, cb) { + var p = Promise.join(Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), handler); + cb(p); + }); + }); - describe('asynchronously when promises are pending', function() { - u.testAsync(function(handler, cb) { - var p = Promise.join(Promise.resolve(1), Promise.resolve(2).tap(function() {}), Promise.resolve(3), handler); - cb(p); - }); - }); - }); + describe('asynchronously when promises are pending', function() { + u.testAsync(function(handler, cb) { + var p = Promise.join(Promise.resolve(1), Promise.resolve(2).tap(function() {}), Promise.resolve(3), handler); + cb(p); + }); + }); + }); }); diff --git a/test/methods/method.test.js b/test/methods/method.test.js index 5cc1457..d581710 100644 --- a/test/methods/method.test.js +++ b/test/methods/method.test.js @@ -11,9 +11,9 @@ var runTests = require('../support'); // Run tests runTests('Promise.method()', function(u, Promise) { - describe('returns a function that', function() { - u.testSetStaticMethodSyncHandler(function(handler) { - return (Promise.method(handler))(); - }); - }); + describe('returns a function that', function() { + u.testSetStaticMethodSyncHandler(function(handler) { + return (Promise.method(handler))(); + }); + }); }); diff --git a/test/methods/reject.test.js b/test/methods/reject.test.js index e28551a..e5869fb 100644 --- a/test/methods/reject.test.js +++ b/test/methods/reject.test.js @@ -14,19 +14,19 @@ var runTests = require('../support'); // Run tests runTests('Promise.reject()', function(u, Promise) { - describe('returns instance of patched Promise constructor when passed', function() { - describe('error object', function() { - u.testIsPromise(function() { - var p = Promise.reject(u.makeError()); - u.setRejectStatus(p); - return p; - }); - }); - }); + describe('returns instance of patched Promise constructor when passed', function() { + describe('error object', function() { + u.testIsPromise(function() { + var p = Promise.reject(u.makeError()); + u.setRejectStatus(p); + return p; + }); + }); + }); }); runTests('Promise.rejected()', function(u, Promise) { // jshint ignore:line - it('is alias of Promise.reject()', function() { - expect(Promise.rejected).to.equal(Promise.reject); - }); + it('is alias of Promise.reject()', function() { + expect(Promise.rejected).to.equal(Promise.reject); + }); }); diff --git a/test/methods/resolve.test.js b/test/methods/resolve.test.js index 79d582e..e880fd6 100644 --- a/test/methods/resolve.test.js +++ b/test/methods/resolve.test.js @@ -14,19 +14,19 @@ var runTests = require('../support'); // Run tests runTests('Promise.resolve()', function(u, Promise) { - u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { - return Promise.resolve(value); - }); + u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { + return Promise.resolve(value); + }); }); runTests('Promise.fulfilled()', function(u, Promise) { // jshint ignore:line - it('is alias of Promise.resolve()', function() { - expect(Promise.fulfilled).to.equal(Promise.resolve); - }); + it('is alias of Promise.resolve()', function() { + expect(Promise.fulfilled).to.equal(Promise.resolve); + }); }); runTests('Promise.cast()', function(u, Promise) { // jshint ignore:line - it('is alias of Promise.resolve()', function() { - expect(Promise.cast).to.equal(Promise.resolve); - }); + it('is alias of Promise.resolve()', function() { + expect(Promise.cast).to.equal(Promise.resolve); + }); }); diff --git a/test/methods/spread.test.js b/test/methods/spread.test.js index 759b1b5..9fd3324 100644 --- a/test/methods/spread.test.js +++ b/test/methods/spread.test.js @@ -12,11 +12,11 @@ var runTests = require('../support'); // TODO Intersect these two test sets - test all combinations of promise values and handler return values. // This will make it work like the collection method tests. runTests('.spread()', function(u, Promise) { - u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { - return Promise.resolve([value, value]).spread(function() {}); - }); + u.testSetStaticMethodReceivingValueReturnsPromise(function(value) { + return Promise.resolve([value, value]).spread(function() {}); + }); - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return p.spread(handler); - }, {noUndefined: true}); + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return p.spread(handler); + }, {noUndefined: true}); }); diff --git a/test/methods/then.test.js b/test/methods/then.test.js index e3bba1a..55debe9 100644 --- a/test/methods/then.test.js +++ b/test/methods/then.test.js @@ -11,15 +11,15 @@ var runTests = require('../support'); // Run tests runTests('.then()', function(u) { - describe('resolve handler', function() { - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return p.then(handler); - }); - }); + describe('resolve handler', function() { + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return p.then(handler); + }); + }); - describe('reject handler', function() { - u.testSetProtoMethodAsyncHandler(function(p, handler) { - return p.then(undefined, handler); - }, {catches: true}); - }); + describe('reject handler', function() { + u.testSetProtoMethodAsyncHandler(function(p, handler) { + return p.then(undefined, handler); + }, {catches: true}); + }); }); diff --git a/test/methods/try.test.js b/test/methods/try.test.js index 7681962..34adc0c 100644 --- a/test/methods/try.test.js +++ b/test/methods/try.test.js @@ -14,13 +14,13 @@ var runTests = require('../support'); // Run tests runTests('Promise.try()', function(u, Promise) { - u.testSetStaticMethodSyncHandler(function(handler) { - return Promise.try(handler); - }); + u.testSetStaticMethodSyncHandler(function(handler) { + return Promise.try(handler); + }); }); runTests('Promise.attempt()', function(u, Promise) { // jshint ignore:line - it('is alias of Promise.try()', function() { - expect(Promise.attempt).to.equal(Promise.try); - }); + it('is alias of Promise.try()', function() { + expect(Promise.attempt).to.equal(Promise.try); + }); }); diff --git a/test/support/checks.js b/test/support/checks.js index fbdc05d..c6bb80f 100644 --- a/test/support/checks.js +++ b/test/support/checks.js @@ -8,42 +8,42 @@ // Exports module.exports = { - /** - * Checks provided promise is a Promise and instance of main Bluebird constructor. - * Returns error object if not. - * - * @param {*} promise - Promise to check - * @returns {Error|undefined} - Error if not correct Promise, undefined if fine - */ - checkIsPromise: function(promise) { - var u = this; - if (!promise || typeof promise.then !== 'function') return new Error('Did not return promise'); - if (!(promise instanceof u.Promise)) return new Error('Did not return promise from correct constructor'); - }, + /** + * Checks provided promise is a Promise and instance of main Bluebird constructor. + * Returns error object if not. + * + * @param {*} promise - Promise to check + * @returns {Error|undefined} - Error if not correct Promise, undefined if fine + */ + checkIsPromise: function(promise) { + var u = this; + if (!promise || typeof promise.then !== 'function') return new Error('Did not return promise'); + if (!(promise instanceof u.Promise)) return new Error('Did not return promise from correct constructor'); + }, - /** - * Checks provided function has been bound to a CLS context exactly once. - * Returns error object if not. - * - * @param {Function} fn - Function to check - * @param {Object} context - CLS context object which `fn` should be bound to - * @returns {Error|undefined} - Error if not bound correctly, undefined if fine - */ - checkBound: function(fn, context) { - var bound = fn._bound; - if (!bound || !bound.length) return new Error('Function not bound'); - if (bound.length > 1) return new Error('Function bound multiple times (' + bound.length + ')'); - if (bound[0].context !== context) return new Error('Function bound to wrong context (expected: ' + JSON.stringify(context) + ', got: ' + JSON.stringify(bound[0].context) + ')'); - }, + /** + * Checks provided function has been bound to a CLS context exactly once. + * Returns error object if not. + * + * @param {Function} fn - Function to check + * @param {Object} context - CLS context object which `fn` should be bound to + * @returns {Error|undefined} - Error if not bound correctly, undefined if fine + */ + checkBound: function(fn, context) { + var bound = fn._bound; + if (!bound || !bound.length) return new Error('Function not bound'); + if (bound.length > 1) return new Error('Function bound multiple times (' + bound.length + ')'); + if (bound[0].context !== context) return new Error('Function bound to wrong context (expected: ' + JSON.stringify(context) + ', got: ' + JSON.stringify(bound[0].context) + ')'); + }, - /** - * Checks provided function has not been bound to a CLS context. - * Returns error object if it has been bound. - * - * @param {Function} fn - Function to check - * @returns {Error|undefined} - Error if bound, undefined if has not - */ - checkNotBound: function(fn) { - if (fn._bound) return new Error('Function bound'); - } + /** + * Checks provided function has not been bound to a CLS context. + * Returns error object if it has been bound. + * + * @param {Function} fn - Function to check + * @returns {Error|undefined} - Error if bound, undefined if has not + */ + checkNotBound: function(fn) { + if (fn._bound) return new Error('Function bound'); + } }; diff --git a/test/support/ctors.js b/test/support/ctors.js index 9c15658..b1ca55c 100644 --- a/test/support/ctors.js +++ b/test/support/ctors.js @@ -13,66 +13,66 @@ module.exports = function(u) { var Promise = u.Promise; /** - * TestError constructor. + * TestError constructor. * All promises created in the tests that reject are rejected with a TestError. * NB Inherits from `Promise.OperationalError` rather than plain `Error` so can be caught by `.error()` * @constructor */ function TestError() { - Promise.OperationalError.call(this, ''); - this.name = 'ClsBluebirdTestError'; - } - util.inherits(TestError, Promise.OperationalError); + Promise.OperationalError.call(this, ''); + this.name = 'ClsBluebirdTestError'; + } + util.inherits(TestError, Promise.OperationalError); // Add TestError to utils object - u.TestError = TestError; + u.TestError = TestError; - /** - * Test object constructor. - * @constructor - * @param {Function} done - Callback to be called when test is complete (i.e. `test.done()` is called) - */ - function Test(done) { - this._done = done; - } + /** + * Test object constructor. + * @constructor + * @param {Function} done - Callback to be called when test is complete (i.e. `test.done()` is called) + */ + function Test(done) { + this._done = done; + } - Test.prototype = { - /** - * Register error. - * If called with a value, it is registered as error for the test. - * (if an error is already registered, it is ignored - 1st error takes precedence) + Test.prototype = { + /** + * Register error. + * If called with a value, it is registered as error for the test. + * (if an error is already registered, it is ignored - 1st error takes precedence) * - * @param {Error} [err] - Error to register - * @returns {undefined} - */ - error: function(err) { + * @param {Error} [err] - Error to register + * @returns {undefined} + */ + error: function(err) { if (err !== undefined && this._err === undefined) { if (!(err instanceof Error)) err = new Error(err); this._err = err; } - }, + }, - /** - * Completes test. - * @param {Promise} promise - Test completes when this promise settles - * @param {Function} [final] - Function to execute after promise settles but before test completes. - * Last chance to register an error e.g. an event should have happened before this point but didn't. - * @returns {undefined} - */ - done: function(promise, final) { - var test = this; + /** + * Completes test. + * @param {Promise} promise - Test completes when this promise settles + * @param {Function} [final] - Function to execute after promise settles but before test completes. + * Last chance to register an error e.g. an event should have happened before this point but didn't. + * @returns {undefined} + */ + done: function(promise, final) { + var test = this; promise.then(function() { if (final) final(); - if (u.getRejectStatus(promise)) test.error(new Error('Promise should not be resolved')); + if (u.getRejectStatus(promise)) test.error(new Error('Promise should not be resolved')); test._done(test._err); - }, function(err) { + }, function(err) { if (final) final(); - if (!u.getRejectStatus(promise) || !(err instanceof TestError)) test.error(err || new Error('Empty rejection')); + if (!u.getRejectStatus(promise) || !(err instanceof TestError)) test.error(err || new Error('Empty rejection')); test._done(test._err); - }); - } - }; + }); + } + }; // Add Test to utils object - u.Test = Test; + u.Test = Test; }; diff --git a/test/support/describeSets.js b/test/support/describeSets.js index 8b48893..806e94d 100644 --- a/test/support/describeSets.js +++ b/test/support/describeSets.js @@ -71,9 +71,9 @@ module.exports = { * * @param {Function} testFn - Function to call for each `describe`. Called with `Promise` constructor. * @param {Object} options - Options object - * @param {boolean} [options.continues=false] - true if handler fires on resolved promise - * @param {boolean} [options.catches=false] - true if handler fires on rejected promise - * @returns {undefined} + * @param {boolean} [options.continues=false] - true if handler fires on resolved promise + * @param {boolean} [options.catches=false] - true if handler fires on rejected promise + * @returns {undefined} */ describePromiseConstructorsResolveRejectSyncAsync: function(testFn, options) { var u = this; @@ -91,13 +91,13 @@ module.exports = { var u = this; u.altPromises.forEach(function(altPromiseParams) { - var Promise = altPromiseParams.Promise; + var Promise = altPromiseParams.Promise; - var runThis = (Promise ? describe : describe.skip); - runThis('promise (' + altPromiseParams.name + ')', function() { + var runThis = (Promise ? describe : describe.skip); + runThis('promise (' + altPromiseParams.name + ')', function() { testFn(Promise); }); - }); + }); }, /** @@ -107,9 +107,9 @@ module.exports = { * @param {Function} testFn - Function to call for each `describe`. * @param {Function} Promise - Promise constructor to create promises with * @param {Object} options - Options object - * @param {boolean} [options.continues=false] - true if handler fires on resolved promise - * @param {boolean} [options.catches=false] - true if handler fires on rejected promise - * @returns {undefined} + * @param {boolean} [options.continues=false] - true if handler fires on resolved promise + * @param {boolean} [options.catches=false] - true if handler fires on rejected promise + * @returns {undefined} */ describeResolveRejectSyncAsyncAttachSyncAsync: function(testFn, Promise, options) { var u = this; @@ -129,9 +129,9 @@ module.exports = { * @param {Function} testFn - Function to call for each `describe`. Called with function to create a promise. * @param {Function} Promise - Promise constructor to create promises with * @param {Object} options - Options object - * @param {boolean} [options.continues=false] - true if handler fires on resolved promise - * @param {boolean} [options.catches=false] - true if handler fires on rejected promise - * @returns {undefined} + * @param {boolean} [options.continues=false] - true if handler fires on resolved promise + * @param {boolean} [options.catches=false] - true if handler fires on rejected promise + * @returns {undefined} */ describeResolveRejectSyncAsync: function(testFn, Promise, options) { var u = this; diff --git a/test/support/index.js b/test/support/index.js index 4119c39..a719463 100644 --- a/test/support/index.js +++ b/test/support/index.js @@ -7,13 +7,13 @@ // Modules var Bluebird2 = require('bluebird2'), - Bluebird3 = require('bluebird3'), - clsBluebird = require('../../lib'), - mochaShim = require('./mochaShim'); + Bluebird3 = require('bluebird3'), + clsBluebird = require('../../lib'), + mochaShim = require('./mochaShim'); // Imports var ns = require('./ns'), - Utils = require('./utils'); + Utils = require('./utils'); // Get bluebird version to test from environment vars var bluebirdVersion = process.env.BLUEBIRD_VERSION * 1; @@ -25,29 +25,29 @@ var PatchedBluebird3 = patch(Bluebird3); // Get bluebird version to use for these tests var Promise, UnpatchedPromise, versionName, altPromises; if (bluebirdVersion === 2) { - Promise = PatchedBluebird2; - UnpatchedPromise = Bluebird2; - versionName = 'Bluebird v2.x'; - altPromises = [ - {name: 'this', Promise: PatchedBluebird2}, - {name: 'bluebird v2 unpatched', Promise: Bluebird2}, - //{name: 'bluebird v3 patched', Promise: PatchedBluebird3}, - {name: 'bluebird v3 unpatched', Promise: Bluebird3}, - {name: 'native', Promise: global.Promise} - ]; + Promise = PatchedBluebird2; + UnpatchedPromise = Bluebird2; + versionName = 'Bluebird v2.x'; + altPromises = [ + {name: 'this', Promise: PatchedBluebird2}, + {name: 'bluebird v2 unpatched', Promise: Bluebird2}, + //{name: 'bluebird v3 patched', Promise: PatchedBluebird3}, + {name: 'bluebird v3 unpatched', Promise: Bluebird3}, + {name: 'native', Promise: global.Promise} + ]; } else if (bluebirdVersion === 3) { - Promise = PatchedBluebird3; - UnpatchedPromise = Bluebird3; - versionName = 'Bluebird v3.x'; - altPromises = [ - {name: 'this', Promise: PatchedBluebird3}, - {name: 'bluebird v3 unpatched', Promise: Bluebird3}, - //{name: 'bluebird v2 patched', Promise: PatchedBluebird2}, - {name: 'bluebird v2 unpatched', Promise: Bluebird2}, - {name: 'native', Promise: global.Promise} - ]; + Promise = PatchedBluebird3; + UnpatchedPromise = Bluebird3; + versionName = 'Bluebird v3.x'; + altPromises = [ + {name: 'this', Promise: PatchedBluebird3}, + {name: 'bluebird v3 unpatched', Promise: Bluebird3}, + //{name: 'bluebird v2 patched', Promise: PatchedBluebird2}, + {name: 'bluebird v2 unpatched', Promise: Bluebird2}, + {name: 'native', Promise: global.Promise} + ]; } else { - throw new Error('BLUEBIRD_VERSION environment variable not set'); + throw new Error('BLUEBIRD_VERSION environment variable not set'); } // Create utils object based on Promise, UnpatchedPromise, ns and altPromises @@ -65,13 +65,13 @@ var utils = new Utils(Promise, UnpatchedPromise, ns, altPromises, bluebirdVersio * @returns {undefined} */ module.exports = function(name, testFn) { - // Apply mocha shim to collapse single `it` statements into parent `describe` - if (!describe.__shimmed) mochaShim(); + // Apply mocha shim to collapse single `it` statements into parent `describe` + if (!describe.__shimmed) mochaShim(); - // Run tests - describe(name + ' (' + versionName + ')', function() { - testFn(utils, Promise); - }, true); + // Run tests + describe(name + ' (' + versionName + ')', function() { + testFn(utils, Promise); + }, true); }; /* @@ -82,19 +82,19 @@ module.exports = function(name, testFn) { * @returns {Function} - Input bluebird constructor */ function patch(Promise) { - // Get independent instance of bluebird library - Promise = Promise.getNewLibraryCopy(); + // Get independent instance of bluebird library + Promise = Promise.getNewLibraryCopy(); - // Patch bluebird with cls-bluebird - clsBluebird(ns, Promise); + // Patch bluebird with cls-bluebird + clsBluebird(ns, Promise); - // Register `onPossiblyUnhandledRejection` handler to exit with error - // if there is an unhandled promise rejection. - Promise.onPossiblyUnhandledRejection(function(err) { - console.log('Unhandled rejection:', err); - process.exit(1); - }); + // Register `onPossiblyUnhandledRejection` handler to exit with error + // if there is an unhandled promise rejection. + Promise.onPossiblyUnhandledRejection(function(err) { + console.log('Unhandled rejection:', err); + process.exit(1); + }); - // Return bluebird constructor - return Promise; + // Return bluebird constructor + return Promise; } diff --git a/test/support/mochaShim.js b/test/support/mochaShim.js index d0522ff..51b4bc6 100644 --- a/test/support/mochaShim.js +++ b/test/support/mochaShim.js @@ -12,115 +12,115 @@ var _ = require('lodash'); // Capture mocha's original methods var originals = { - describe: describe, - it: it, - before: before, - beforeEach: beforeEach, - after: after, - afterEach: afterEach + describe: describe, + it: it, + before: before, + beforeEach: beforeEach, + after: after, + afterEach: afterEach }; // Exports module.exports = function() { - // Init call tracker var - var calls = null; - - // Replace mocha methods - describe = createReplacement(describe, function(name, fn, noCollapse, methodName) { // jshint ignore:line - noCollapse = !!noCollapse; - if (!calls) return describeRun(name, fn, noCollapse, methodName); - calls.push({type: 'describe', name: name, fn: fn, noCollapse: noCollapse, methodName: methodName}); - }); - - describe.__shimmed = true; - - it = createReplacement(it, function(name, fn, methodName) { // jshint ignore:line - if (typeof name === 'function') { - fn = name; - name = ''; - } - - if (!calls) return itMethod(methodName)(name, fn); - calls.push({type: 'it', name: name, fn: fn, methodName: methodName}); - }); - - before = createReplacement(before, function(fn, methodName) { // jshint ignore:line - if (!calls) return method('before', methodName)(fn); - calls.push({type: 'before', fn: fn, methodName: methodName}); - }); - - beforeEach = createReplacement(beforeEach, function(fn, methodName) { // jshint ignore:line - if (!calls) return method('beforeEach', methodName)(fn); - calls.push({type: 'beforeEach', fn: fn, methodName: methodName}); - }); - - after = createReplacement(after, function(fn, methodName) { // jshint ignore:line - if (!calls) return method('after', methodName)(fn); - calls.push({type: 'after', fn: fn, methodName: methodName}); - }); - - beforeEach = createReplacement(afterEach, function(fn, methodName) { // jshint ignore:line - if (!calls) return method('afterEach', methodName)(fn); - calls.push({type: 'afterEach', fn: fn, methodName: methodName}); - }); - - // Function to execute a `describe` statement - function describeRun(name, fn, noCollapse, methodName) { - // Run function and capture calls - calls = []; - fn(); - var thisCalls = calls; - calls = null; - - // Only a single `it` in the `describe` - run as single `it` unless `noCollapse` set - if (thisCalls.length === 1 && !noCollapse) { - var call = thisCalls[0]; - if (call.type === 'it' && (!methodName || !call.methodName || call.methodName === methodName)) { - if (!methodName) methodName = call.methodName; - if (call.name) name += ' ' + call.name; - - itMethod(methodName)(name, call.fn); - return; - } - } - - // Multiple calls in the `describe` - run as usual - describeMethod(methodName)(name, function() { - thisCalls.forEach(function(call) { - if (call.type === 'describe') return describeRun(call.name, call.fn, call.noCollapse, call.methodName); - method(call.type, call.methodName)(call.name, call.fn); - }); - }); - } + // Init call tracker var + var calls = null; + + // Replace mocha methods + describe = createReplacement(describe, function(name, fn, noCollapse, methodName) { // jshint ignore:line + noCollapse = !!noCollapse; + if (!calls) return describeRun(name, fn, noCollapse, methodName); + calls.push({type: 'describe', name: name, fn: fn, noCollapse: noCollapse, methodName: methodName}); + }); + + describe.__shimmed = true; + + it = createReplacement(it, function(name, fn, methodName) { // jshint ignore:line + if (typeof name === 'function') { + fn = name; + name = ''; + } + + if (!calls) return itMethod(methodName)(name, fn); + calls.push({type: 'it', name: name, fn: fn, methodName: methodName}); + }); + + before = createReplacement(before, function(fn, methodName) { // jshint ignore:line + if (!calls) return method('before', methodName)(fn); + calls.push({type: 'before', fn: fn, methodName: methodName}); + }); + + beforeEach = createReplacement(beforeEach, function(fn, methodName) { // jshint ignore:line + if (!calls) return method('beforeEach', methodName)(fn); + calls.push({type: 'beforeEach', fn: fn, methodName: methodName}); + }); + + after = createReplacement(after, function(fn, methodName) { // jshint ignore:line + if (!calls) return method('after', methodName)(fn); + calls.push({type: 'after', fn: fn, methodName: methodName}); + }); + + beforeEach = createReplacement(afterEach, function(fn, methodName) { // jshint ignore:line + if (!calls) return method('afterEach', methodName)(fn); + calls.push({type: 'afterEach', fn: fn, methodName: methodName}); + }); + + // Function to execute a `describe` statement + function describeRun(name, fn, noCollapse, methodName) { + // Run function and capture calls + calls = []; + fn(); + var thisCalls = calls; + calls = null; + + // Only a single `it` in the `describe` - run as single `it` unless `noCollapse` set + if (thisCalls.length === 1 && !noCollapse) { + var call = thisCalls[0]; + if (call.type === 'it' && (!methodName || !call.methodName || call.methodName === methodName)) { + if (!methodName) methodName = call.methodName; + if (call.name) name += ' ' + call.name; + + itMethod(methodName)(name, call.fn); + return; + } + } + + // Multiple calls in the `describe` - run as usual + describeMethod(methodName)(name, function() { + thisCalls.forEach(function(call) { + if (call.type === 'describe') return describeRun(call.name, call.fn, call.noCollapse, call.methodName); + method(call.type, call.methodName)(call.name, call.fn); + }); + }); + } }; function createReplacement(original, executor) { - var replacement = function() { - executor.apply(this, arguments); - }; - - _.forIn(original, function(method, methodName) { - if (typeof method !== 'function') return; - replacement[methodName] = function() { - var args = Array.prototype.slice.call(arguments); - args[executor.length - 1] = methodName; - executor.apply(this, args); - }; - }); - - return replacement; + var replacement = function() { + executor.apply(this, arguments); + }; + + _.forIn(original, function(method, methodName) { + if (typeof method !== 'function') return; + replacement[methodName] = function() { + var args = Array.prototype.slice.call(arguments); + args[executor.length - 1] = methodName; + executor.apply(this, args); + }; + }); + + return replacement; } function describeMethod(methodName) { - return method('describe', methodName); + return method('describe', methodName); } function itMethod(methodName) { - return method('it', methodName); + return method('it', methodName); } function method(name, methodName) { - var fn = originals[name]; - return methodName ? fn[methodName] : fn; + var fn = originals[name]; + return methodName ? fn[methodName] : fn; } diff --git a/test/support/ns.js b/test/support/ns.js index 67aa042..51ec22c 100644 --- a/test/support/ns.js +++ b/test/support/ns.js @@ -23,9 +23,9 @@ shimmer.wrap(ns, 'bind', function(bind) { if (!originalFn._bound) originalFn._bound = []; originalFn._bound.push({ns: ns, context: context || ns.active}); - var fnBound = bind.call(this, fn, context); + var fnBound = bind.call(this, fn, context); - fnBound._originalFn = originalFn; + fnBound._originalFn = originalFn; return fnBound; }; }); diff --git a/test/support/promises.js b/test/support/promises.js index f777a28..1894a71 100644 --- a/test/support/promises.js +++ b/test/support/promises.js @@ -8,128 +8,128 @@ // Exports module.exports = { - /** - * Function to create default literal value. - * NB Returns array so works with collection methods. - * @returns {Array} - */ - // TODO revert to returning number and find better way to deal with collection methods - makeValue: function() { - return [1, 2, 3]; - }, + /** + * Function to create default literal value. + * NB Returns array so works with collection methods. + * @returns {Array} + */ + // TODO revert to returning number and find better way to deal with collection methods + makeValue: function() { + return [1, 2, 3]; + }, - /** - * Function to create default error. - * Error is instance of TestError constructor. - * @returns {TestError} - */ - makeError: function() { - return new this.TestError(); - }, + /** + * Function to create default error. + * Error is instance of TestError constructor. + * @returns {TestError} + */ + makeError: function() { + return new this.TestError(); + }, - /** - * Function to create undefined value. - * @returns {undefined} - */ - makeUndefined: function() { - return undefined; - }, + /** + * Function to create undefined value. + * @returns {undefined} + */ + makeUndefined: function() { + return undefined; + }, - /** - * Function that throws an error. - * @throws {TestError} - */ - makeThrow: function() { - throw this.makeError(); - }, + /** + * Function that throws an error. + * @throws {TestError} + */ + makeThrow: function() { + throw this.makeError(); + }, - /* - * Set of functions to create promises which resolve or reject either synchronously or asynchronously. - * Promises are created from specified Promise constructor. - */ - resolveSync: function(Promise) { - var value = this.makeValue(); - return new Promise(function(resolve) { - resolve(value); - }); - }, + /* + * Set of functions to create promises which resolve or reject either synchronously or asynchronously. + * Promises are created from specified Promise constructor. + */ + resolveSync: function(Promise) { + var value = this.makeValue(); + return new Promise(function(resolve) { + resolve(value); + }); + }, - resolveAsync: function(Promise) { - var value = this.makeValue(); - return new Promise(function(resolve) { - setImmediate(function() { - resolve(value); - }); - }); - }, + resolveAsync: function(Promise) { + var value = this.makeValue(); + return new Promise(function(resolve) { + setImmediate(function() { + resolve(value); + }); + }); + }, - rejectSync: function(Promise) { - var err = this.makeError(); - var p = new Promise(function(resolve, reject) { // jshint ignore:line - reject(err); - }); - this.setRejectStatus(p); - return p; - }, + rejectSync: function(Promise) { + var err = this.makeError(); + var p = new Promise(function(resolve, reject) { // jshint ignore:line + reject(err); + }); + this.setRejectStatus(p); + return p; + }, - rejectAsync: function(Promise) { - var err = this.makeError(); - var p = new Promise(function(resolve, reject) { // jshint ignore:line - setImmediate(function() { - reject(err); - }); - }); - this.setRejectStatus(p); - return p; - }, + rejectAsync: function(Promise) { + var err = this.makeError(); + var p = new Promise(function(resolve, reject) { // jshint ignore:line + setImmediate(function() { + reject(err); + }); + }); + this.setRejectStatus(p); + return p; + }, - /* - * Set of functions to create functions which return promises. - * Promises resolve or reject either synchronously or asynchronously. - * Promises are created from specified Promise constructor. - */ - resolveSyncMethod: function(Promise) { - var u = this; - return function() { - return u.resolveSync(Promise); - }; - }, + /* + * Set of functions to create functions which return promises. + * Promises resolve or reject either synchronously or asynchronously. + * Promises are created from specified Promise constructor. + */ + resolveSyncMethod: function(Promise) { + var u = this; + return function() { + return u.resolveSync(Promise); + }; + }, - resolveAsyncMethod: function(Promise) { - var u = this; - return function() { - return u.resolveAsync(Promise); - }; - }, + resolveAsyncMethod: function(Promise) { + var u = this; + return function() { + return u.resolveAsync(Promise); + }; + }, - rejectSyncMethod: function(Promise) { - var u = this; - var fn = function() { - return u.rejectSync(Promise); - }; - this.setRejectStatus(fn); - return fn; - }, + rejectSyncMethod: function(Promise) { + var u = this; + var fn = function() { + return u.rejectSync(Promise); + }; + this.setRejectStatus(fn); + return fn; + }, - rejectAsyncMethod: function(Promise) { - var u = this; - var fn = function() { - return u.rejectAsync(Promise); - }; - this.setRejectStatus(fn); - return fn; - }, + rejectAsyncMethod: function(Promise) { + var u = this; + var fn = function() { + return u.rejectAsync(Promise); + }; + this.setRejectStatus(fn); + return fn; + }, - /** - * Function that returns function which throws error when called. - * @returns {Function} - */ - throwMethod: function() { - var u = this; - var fn = function() { - u.makeThrow(); - }; - this.setRejectStatus(fn); - return fn; - } + /** + * Function that returns function which throws error when called. + * @returns {Function} + */ + throwMethod: function() { + var u = this; + var fn = function() { + u.makeThrow(); + }; + this.setRejectStatus(fn); + return fn; + } }; diff --git a/test/support/test.js b/test/support/test.js index ee26fa8..2c6c5e0 100644 --- a/test/support/test.js +++ b/test/support/test.js @@ -20,7 +20,7 @@ module.exports = { * @param {string} name - Test case name * @param {Function} fn - Test function * @returns {undefined} - */ + */ test: function(name, fn) { var u = this; @@ -30,22 +30,22 @@ module.exports = { } it(name, function(done) { - u._runTest(fn, done); - }); + u._runTest(fn, done); + }); }, /** - * Same as`u.test()` but runs the test in parallel multiple times. - * If all test runs pass, executes callback with no error. - * If any test run fails, executes callback with first error received. - * Waits for all test runs to complete before calling callback, even if an error is encountered. - * + * Same as`u.test()` but runs the test in parallel multiple times. + * If all test runs pass, executes callback with no error. + * If any test run fails, executes callback with first error received. + * Waits for all test runs to complete before calling callback, even if an error is encountered. + * * Test function is passed a Test object with `.error()` and `.done()` methods. - * - * @param {string} name - Name of test - * @param {Function} fn - Test function - * @returns {undefined} - */ + * + * @param {string} name - Name of test + * @param {Function} fn - Test function + * @returns {undefined} + */ testMultiple: function(name, fn) { var u = this; @@ -55,12 +55,12 @@ module.exports = { } it(name, function(done) { - done = callbackAggregator(TEST_MULTIPLE_ROUNDS, done); + done = callbackAggregator(TEST_MULTIPLE_ROUNDS, done); - for (var i = 0; i < TEST_MULTIPLE_ROUNDS; i++) { - u._runTest(fn, done); - } - }); + for (var i = 0; i < TEST_MULTIPLE_ROUNDS; i++) { + u._runTest(fn, done); + } + }); }, /** diff --git a/test/support/testSets/binding.js b/test/support/testSets/binding.js index 1179458..d779ad4 100644 --- a/test/support/testSets/binding.js +++ b/test/support/testSets/binding.js @@ -10,55 +10,55 @@ // Exports module.exports = { - /** - * Run set of tests on a method to ensure callback is always bound to CLS context. - * Function `fn` should take provided `promise` and call the method being tested on it. - * `fn` is called with a `promise` and a `handler` function which should be attached as the callback to the method under test. - * e.g. `return promise.then(handler)` - * - * If handler is being attached to catch rejections, `options.catches` should be `true` - * - * @param {Function} fn - Test function - * @param {Object} options - Options object - * @param {boolean} options.continues - true if handler fires on resolved promise - * @param {boolean} options.catches - true if handler fires on rejected promise - * @param {boolean} options.passThrough - true if method passes through errors even if handler fires - * @param {Function} [options.handler] - Handler function - * @returns {undefined} - */ - testSetProtoCallbackBound: function(fn, options) { - var u = this; - describe('binds callback on', function() { - u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { - u.testBound(function(handler, p, cb) { - attach(function() { - var newP = fn(p, handler); - if (options.passThrough) u.inheritRejectStatus(newP, p); - cb(newP); - }, p); - }, makePromise, options.handler); - }, u.Promise, options); - }); - }, + /** + * Run set of tests on a method to ensure callback is always bound to CLS context. + * Function `fn` should take provided `promise` and call the method being tested on it. + * `fn` is called with a `promise` and a `handler` function which should be attached as the callback to the method under test. + * e.g. `return promise.then(handler)` + * + * If handler is being attached to catch rejections, `options.catches` should be `true` + * + * @param {Function} fn - Test function + * @param {Object} options - Options object + * @param {boolean} options.continues - true if handler fires on resolved promise + * @param {boolean} options.catches - true if handler fires on rejected promise + * @param {boolean} options.passThrough - true if method passes through errors even if handler fires + * @param {Function} [options.handler] - Handler function + * @returns {undefined} + */ + testSetProtoCallbackBound: function(fn, options) { + var u = this; + describe('binds callback on', function() { + u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { + u.testBound(function(handler, p, cb) { + attach(function() { + var newP = fn(p, handler); + if (options.passThrough) u.inheritRejectStatus(newP, p); + cb(newP); + }, p); + }, makePromise, options.handler); + }, u.Promise, options); + }); + }, - /** - * Run set of tests on a static method to ensure callback is never bound to CLS context. - * Function `fn` should call the method being tested, attaching `handler` as the callback. - * e.g. `return Promise.try(handler)` - * - * @param {Function} fn - Test function - * @param {Object} [options] - Options object - * @param {Function} [options.handler] - Optional handler function - * @returns {undefined} - */ - testSetStaticCallbackNotBound: function(fn, options) { - var u = this; - options = options || {}; + /** + * Run set of tests on a static method to ensure callback is never bound to CLS context. + * Function `fn` should call the method being tested, attaching `handler` as the callback. + * e.g. `return Promise.try(handler)` + * + * @param {Function} fn - Test function + * @param {Object} [options] - Options object + * @param {Function} [options.handler] - Optional handler function + * @returns {undefined} + */ + testSetStaticCallbackNotBound: function(fn, options) { + var u = this; + options = options || {}; - describe('does not bind callback', function() { - u.testNotBound(function(handler) { - return fn(handler); - }, options.handler); - }); - } + describe('does not bind callback', function() { + u.testNotBound(function(handler) { + return fn(handler); + }, options.handler); + }); + } }; diff --git a/test/support/testSets/context.js b/test/support/testSets/context.js index e1dfff6..c8f11e7 100644 --- a/test/support/testSets/context.js +++ b/test/support/testSets/context.js @@ -10,34 +10,34 @@ // Exports module.exports = { - /** - * Run set of tests on a method to ensure callback is always run in correct CLS context. - * Function `fn` should take provided `promise` and call the method being tested on it. - * `fn` is called with a `promise` and a `handler` function which should be attached as the callback to the method under test. - * e.g. `promise.then(handler)` - * - * If handler is being attached to catch rejections, `options.catches` should be `true` - * - * @param {Function} fn - Test function - * @param {Object} options - Options object - * @param {boolean} options.continues - true if handler fires on resolved promise - * @param {boolean} options.catches - true if handler fires on rejected promise - * @param {boolean} options.passThrough - true if method passes through errors even if handler fires - * @param {Function} [options.handler] - Handler function - * @returns {undefined} - */ - testSetProtoCallbackContext: function(fn, options) { - var u = this; - describe('callback runs in context on', function() { - u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { - u.testRunContext(function(handler, p, cb) { - attach(function() { - var newP = fn(p, handler); - if (options.passThrough) u.inheritRejectStatus(newP, p); - cb(newP); - }, p); - }, makePromise, options.handler); - }, u.Promise, options); - }); - } + /** + * Run set of tests on a method to ensure callback is always run in correct CLS context. + * Function `fn` should take provided `promise` and call the method being tested on it. + * `fn` is called with a `promise` and a `handler` function which should be attached as the callback to the method under test. + * e.g. `promise.then(handler)` + * + * If handler is being attached to catch rejections, `options.catches` should be `true` + * + * @param {Function} fn - Test function + * @param {Object} options - Options object + * @param {boolean} options.continues - true if handler fires on resolved promise + * @param {boolean} options.catches - true if handler fires on rejected promise + * @param {boolean} options.passThrough - true if method passes through errors even if handler fires + * @param {Function} [options.handler] - Handler function + * @returns {undefined} + */ + testSetProtoCallbackContext: function(fn, options) { + var u = this; + describe('callback runs in context on', function() { + u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { + u.testRunContext(function(handler, p, cb) { + attach(function() { + var newP = fn(p, handler); + if (options.passThrough) u.inheritRejectStatus(newP, p); + cb(newP); + }, p); + }, makePromise, options.handler); + }, u.Promise, options); + }); + } }; diff --git a/test/support/testSets/groups.js b/test/support/testSets/groups.js index 505e1ab..f3880fa 100644 --- a/test/support/testSets/groups.js +++ b/test/support/testSets/groups.js @@ -11,70 +11,70 @@ var _ = require('lodash'); // Exports module.exports = { - /** - * Run set of tests on a static method that takes a callback to ensure: - * - always returns a Promise which is instance of patched Promise constructor - * - callback is called synchronously - * - callback is not bound to CLS context - * - * `fn` is called with a `handler` function which should be attached as the callback to the method under test. - * `fn` should return the resulting promise. - * e.g. `return Promise.try(handler)` - * - * @param {Function} fn - Test function - * @returns {undefined} - */ - testSetStaticMethodSyncHandler: function(fn) { - var u = this; - u.testSetStaticMethodReceivingHandlerReturnsPromise(fn); - u.testSetStaticCallbackSync(fn); - u.testSetStaticCallbackNotBound(fn); - }, + /** + * Run set of tests on a static method that takes a callback to ensure: + * - always returns a Promise which is instance of patched Promise constructor + * - callback is called synchronously + * - callback is not bound to CLS context + * + * `fn` is called with a `handler` function which should be attached as the callback to the method under test. + * `fn` should return the resulting promise. + * e.g. `return Promise.try(handler)` + * + * @param {Function} fn - Test function + * @returns {undefined} + */ + testSetStaticMethodSyncHandler: function(fn) { + var u = this; + u.testSetStaticMethodReceivingHandlerReturnsPromise(fn); + u.testSetStaticCallbackSync(fn); + u.testSetStaticCallbackNotBound(fn); + }, - /** - * Run set of tests on a prototype method that takes a callback to ensure: - * - always returns a Promise which is instance of patched Promise constructor - * - callback is called asynchronously - * - callback is bound to CLS context - * - * `fn` is called with a `promise` and a `handler` function. - * `fn` should: - * - call the method under test on `promise` with `handler` as callback - * - return the resulting promise. - * e.g. `return promise.then(handler)` - * - * If handler should be called when promise attached to resolves, `options.continues` should be true (default) - * If handler should be called when promise attached to rejects, `options.catches` should be true - * If handler passes through rejections, `options.passThrough` should be true (e.g. `promise.finally()`) - * - * @param {Function} fn - Test function - * @param {Object} [options] - Options object - * @param {boolean} [options.continues] - true if handler fires on resolved promise (default `!options.catches`) - * @param {boolean} [options.catches] - true if handler fires on rejected promise (default `false`) - * @param {boolean} [options.passThrough] - true if method passes through errors even if handler fires (default `false`) - * @param {boolean} [options.noUndefined] - true if method does not accept undefined handler (default `false`) - * @param {boolean} [options.noAsyncTest] - Skip handler called async test if true (default `false`) - * @param {boolean} [options.noBindTest] - Skip handler bound test if true (default `false`) - * @returns {undefined} - */ - testSetProtoMethodAsyncHandler: function(fn, options) { - var u = this; + /** + * Run set of tests on a prototype method that takes a callback to ensure: + * - always returns a Promise which is instance of patched Promise constructor + * - callback is called asynchronously + * - callback is bound to CLS context + * + * `fn` is called with a `promise` and a `handler` function. + * `fn` should: + * - call the method under test on `promise` with `handler` as callback + * - return the resulting promise. + * e.g. `return promise.then(handler)` + * + * If handler should be called when promise attached to resolves, `options.continues` should be true (default) + * If handler should be called when promise attached to rejects, `options.catches` should be true + * If handler passes through rejections, `options.passThrough` should be true (e.g. `promise.finally()`) + * + * @param {Function} fn - Test function + * @param {Object} [options] - Options object + * @param {boolean} [options.continues] - true if handler fires on resolved promise (default `!options.catches`) + * @param {boolean} [options.catches] - true if handler fires on rejected promise (default `false`) + * @param {boolean} [options.passThrough] - true if method passes through errors even if handler fires (default `false`) + * @param {boolean} [options.noUndefined] - true if method does not accept undefined handler (default `false`) + * @param {boolean} [options.noAsyncTest] - Skip handler called async test if true (default `false`) + * @param {boolean} [options.noBindTest] - Skip handler bound test if true (default `false`) + * @returns {undefined} + */ + testSetProtoMethodAsyncHandler: function(fn, options) { + var u = this; - // Conform options - options = _.extend({ - catches: false, - passThrough: false, - noUndefined: false, - noAsyncTest: false, - noBindTest: false - }, options); + // Conform options + options = _.extend({ + catches: false, + passThrough: false, + noUndefined: false, + noAsyncTest: false, + noBindTest: false + }, options); - _.defaults(options, {continues: !options.catches}); + _.defaults(options, {continues: !options.catches}); - // Run tests - u.testSetProtoMethodReturnsPromise(fn, options); - if (!options.noAsyncTest) u.testSetProtoCallbackAsync(fn, options); - if (!options.noBindTest) u.testSetProtoCallbackBound(fn, options); - u.testSetProtoCallbackContext(fn, options); - } + // Run tests + u.testSetProtoMethodReturnsPromise(fn, options); + if (!options.noAsyncTest) u.testSetProtoCallbackAsync(fn, options); + if (!options.noBindTest) u.testSetProtoCallbackBound(fn, options); + u.testSetProtoCallbackContext(fn, options); + } }; diff --git a/test/support/testSets/promise.js b/test/support/testSets/promise.js index 7c68c85..3b7a836 100644 --- a/test/support/testSets/promise.js +++ b/test/support/testSets/promise.js @@ -10,214 +10,214 @@ // Exports module.exports = { - /** - * Run set of tests on a static method which receives a value to ensure always returns a promise - * inherited from correct Promise constructor. - * - * Test function `fn` is called with a `value`. - * `fn` should call the method being tested with `value`, and return resulting promise. - * e.g. `return Promise.resolve(value)` - * - * A different `value` is provided in each test: - * - literal value - * - undefined - * - promise from various constructors, resolved or rejected, sync or async - * - * @param {Function} fn - Test function - * @returns {undefined} - */ - testSetStaticMethodReceivingValueReturnsPromise: function(fn) { - var u = this; - describe('returns instance of patched Promise constructor when passed', function() { - u.describeValues(function(makeValue) { - u.testIsPromise(function() { - var value = makeValue(); - var p = fn(value); - u.inheritRejectStatus(p, value); - return p; - }); - }); - }); - }, - - /** - * Run set of tests on a static method which receives a value to ensure always returns a promise - * inherited from correct Promise constructor. - * - * Test function `fn` is called with a `value`. - * `fn` should call the method being tested with `value`, and return resulting promise. - * e.g. `return Promise.resolve(value)` - * - * A different `value` is provided in each test: - * - literal value - * - undefined - * - promise from various constructors, resolved or rejected, sync or async - * - * @param {Function} fn - Test function - * @returns {undefined} - */ - testSetProtoMethodReceivingValueReturnsPromise: function(fn) { - var u = this; - describe('returns instance of patched Promise constructor when attached to promise', function() { - u.describeResolveRejectSyncAsync(function(makePromise) { - describe('when value is', function() { - u.describeValues(function(makeValue) { - u.testIsPromise(function() { - var p = makePromise(); - var value = makeValue(); - - var newP = fn(p, value); - if (u.getRejectStatus(p) || u.getRejectStatus(value)) u.setRejectStatus(newP); - return newP; - }); - }); - }); - }, u.Promise, {continues: true, catches: true}); - }); - }, - - /** - * Run set of tests on a static method which receives a handler to ensure always returns a promise - * inherited from correct Promise constructor. - * - * Test function `fn` is called with a function `handler`. - * `fn` should call the method being tested with `handler`, and return resulting promise. - * e.g. `return Promise.try(handler)` - * - * A different `handler` is provided in each test, which returns: - * - literal value - * - undefined - * - thrown error - * - promise from various constructors, resolved or rejected, sync or async - * - * @param {Function} fn - Test function - * @returns {undefined} - */ - testSetStaticMethodReceivingHandlerReturnsPromise: function(fn) { - var u = this; - describe('returns instance of patched Promise constructor when callback', function() { - u.describeHandlers(function(handler) { - u.test(function(t) { - // Create handler - var called = 0; - - var handlerWrapped = function() { - called++; - return handler.apply(this, arguments); - }; - - // Run test function with handler - var p = fn(handlerWrapped); - u.inheritRejectStatus(p, handler); - - // Check result is Promise - t.error(u.checkIsPromise(p)); - - // Check handler was called once - t.done(p, function() { - if (!called) t.error(new Error('Callback not called')); - if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); - }); - }); - }); - }); - }, - - /** - * Run set of tests on a prototype method to ensure always returns a promise - * inherited from correct Promise constructor. - * - * `fn` is called with a `promise` and a `handler` function. - * `fn` should call method under test on `promise` with `handler` callback attached - * and return resulting promise. - * e.g. `return promise.then(handler)` - * - * A different `handler` is provided in each test. - * Handlers returns a literal value, throw, or return or a promise that resolves/rejects. - * Promises returned from handlers are instances of various different Promise constructors. - * - * @param {Function} fn - Test function - * @param {Object} options - Options object - * @param {boolean} options.continues - true if handler fires on resolved promise - * @param {boolean} options.catches - true if handler fires rejected promise - * @param {boolean} options.passThrough - true if method passes through errors even if handler fires - * @param {boolean} options.noUndefined - true if method does not accept undefined handler - * @returns {undefined} - */ - testSetProtoMethodReturnsPromise: function(fn, options) { - var u = this; - describe('returns instance of patched Promise constructor when called on promise', function() { - u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { - describe('and handler', function() { - // Test undefined handler - if (!options.noUndefined) { - u.test('is undefined', function(t) { - var p = makePromise(); - - attach(function() { - var newP = fn(p, undefined); - u.inheritRejectStatus(newP, p); - - t.error(u.checkIsPromise(newP)); - t.done(newP); - }, p); - }); - } - - // If handler should not be fired on this promise, check is not fired - var handlerShouldBeCalled = u.getRejectStatus(makePromise) ? options.catches : options.continues; - - if (!handlerShouldBeCalled) { - u.test('is ignored', function(t) { - var p = makePromise(); - - attach(function() { - var newP = fn(p, function() { - t.error(new Error('Handler should not be called')); - }); - u.inheritRejectStatus(newP, p); - - t.error(u.checkIsPromise(newP)); - t.done(newP); - }, p); - }); - return; - } - - // Handler should fire on this promise - // Test all handlers - u.describeHandlers(function(handler) { - u.test(function(t) { - // Create handler - var called = 0; - - var handlerWrapped = function() { - called++; - return handler.apply(this, arguments); - }; - - // Create promise - var p = makePromise(); - - // Run method on promise and pass handler - attach(function() { - var newP = fn(p, handlerWrapped); - u.inheritRejectStatus(newP, handler); - if (options.passThrough && u.getRejectStatus(p)) u.setRejectStatus(newP); - - // Check result is promise - t.error(u.checkIsPromise(newP)); - - // Check handler was called once - t.done(newP, function() { - if (!called) t.error(new Error('Callback not called')); - if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); - }); - }, p); - }); - }); - }); - }, u.Promise, {continues: true, catches: true}); - }); - } + /** + * Run set of tests on a static method which receives a value to ensure always returns a promise + * inherited from correct Promise constructor. + * + * Test function `fn` is called with a `value`. + * `fn` should call the method being tested with `value`, and return resulting promise. + * e.g. `return Promise.resolve(value)` + * + * A different `value` is provided in each test: + * - literal value + * - undefined + * - promise from various constructors, resolved or rejected, sync or async + * + * @param {Function} fn - Test function + * @returns {undefined} + */ + testSetStaticMethodReceivingValueReturnsPromise: function(fn) { + var u = this; + describe('returns instance of patched Promise constructor when passed', function() { + u.describeValues(function(makeValue) { + u.testIsPromise(function() { + var value = makeValue(); + var p = fn(value); + u.inheritRejectStatus(p, value); + return p; + }); + }); + }); + }, + + /** + * Run set of tests on a static method which receives a value to ensure always returns a promise + * inherited from correct Promise constructor. + * + * Test function `fn` is called with a `value`. + * `fn` should call the method being tested with `value`, and return resulting promise. + * e.g. `return Promise.resolve(value)` + * + * A different `value` is provided in each test: + * - literal value + * - undefined + * - promise from various constructors, resolved or rejected, sync or async + * + * @param {Function} fn - Test function + * @returns {undefined} + */ + testSetProtoMethodReceivingValueReturnsPromise: function(fn) { + var u = this; + describe('returns instance of patched Promise constructor when attached to promise', function() { + u.describeResolveRejectSyncAsync(function(makePromise) { + describe('when value is', function() { + u.describeValues(function(makeValue) { + u.testIsPromise(function() { + var p = makePromise(); + var value = makeValue(); + + var newP = fn(p, value); + if (u.getRejectStatus(p) || u.getRejectStatus(value)) u.setRejectStatus(newP); + return newP; + }); + }); + }); + }, u.Promise, {continues: true, catches: true}); + }); + }, + + /** + * Run set of tests on a static method which receives a handler to ensure always returns a promise + * inherited from correct Promise constructor. + * + * Test function `fn` is called with a function `handler`. + * `fn` should call the method being tested with `handler`, and return resulting promise. + * e.g. `return Promise.try(handler)` + * + * A different `handler` is provided in each test, which returns: + * - literal value + * - undefined + * - thrown error + * - promise from various constructors, resolved or rejected, sync or async + * + * @param {Function} fn - Test function + * @returns {undefined} + */ + testSetStaticMethodReceivingHandlerReturnsPromise: function(fn) { + var u = this; + describe('returns instance of patched Promise constructor when callback', function() { + u.describeHandlers(function(handler) { + u.test(function(t) { + // Create handler + var called = 0; + + var handlerWrapped = function() { + called++; + return handler.apply(this, arguments); + }; + + // Run test function with handler + var p = fn(handlerWrapped); + u.inheritRejectStatus(p, handler); + + // Check result is Promise + t.error(u.checkIsPromise(p)); + + // Check handler was called once + t.done(p, function() { + if (!called) t.error(new Error('Callback not called')); + if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); + }); + }); + }); + }); + }, + + /** + * Run set of tests on a prototype method to ensure always returns a promise + * inherited from correct Promise constructor. + * + * `fn` is called with a `promise` and a `handler` function. + * `fn` should call method under test on `promise` with `handler` callback attached + * and return resulting promise. + * e.g. `return promise.then(handler)` + * + * A different `handler` is provided in each test. + * Handlers returns a literal value, throw, or return or a promise that resolves/rejects. + * Promises returned from handlers are instances of various different Promise constructors. + * + * @param {Function} fn - Test function + * @param {Object} options - Options object + * @param {boolean} options.continues - true if handler fires on resolved promise + * @param {boolean} options.catches - true if handler fires rejected promise + * @param {boolean} options.passThrough - true if method passes through errors even if handler fires + * @param {boolean} options.noUndefined - true if method does not accept undefined handler + * @returns {undefined} + */ + testSetProtoMethodReturnsPromise: function(fn, options) { + var u = this; + describe('returns instance of patched Promise constructor when called on promise', function() { + u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { + describe('and handler', function() { + // Test undefined handler + if (!options.noUndefined) { + u.test('is undefined', function(t) { + var p = makePromise(); + + attach(function() { + var newP = fn(p, undefined); + u.inheritRejectStatus(newP, p); + + t.error(u.checkIsPromise(newP)); + t.done(newP); + }, p); + }); + } + + // If handler should not be fired on this promise, check is not fired + var handlerShouldBeCalled = u.getRejectStatus(makePromise) ? options.catches : options.continues; + + if (!handlerShouldBeCalled) { + u.test('is ignored', function(t) { + var p = makePromise(); + + attach(function() { + var newP = fn(p, function() { + t.error(new Error('Handler should not be called')); + }); + u.inheritRejectStatus(newP, p); + + t.error(u.checkIsPromise(newP)); + t.done(newP); + }, p); + }); + return; + } + + // Handler should fire on this promise + // Test all handlers + u.describeHandlers(function(handler) { + u.test(function(t) { + // Create handler + var called = 0; + + var handlerWrapped = function() { + called++; + return handler.apply(this, arguments); + }; + + // Create promise + var p = makePromise(); + + // Run method on promise and pass handler + attach(function() { + var newP = fn(p, handlerWrapped); + u.inheritRejectStatus(newP, handler); + if (options.passThrough && u.getRejectStatus(p)) u.setRejectStatus(newP); + + // Check result is promise + t.error(u.checkIsPromise(newP)); + + // Check handler was called once + t.done(newP, function() { + if (!called) t.error(new Error('Callback not called')); + if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); + }); + }, p); + }); + }); + }); + }, u.Promise, {continues: true, catches: true}); + }); + } }; diff --git a/test/support/testSets/syncAsync.js b/test/support/testSets/syncAsync.js index c165028..df18ddd 100644 --- a/test/support/testSets/syncAsync.js +++ b/test/support/testSets/syncAsync.js @@ -10,57 +10,57 @@ // Exports module.exports = { - /** - * Run set of tests on a prototype method to ensure always calls callback asynchronously. - * Function `fn` should take provided `promise` and call the method being tested on it, - * attaching `handler` as the callback. - * e.g. `return promise.then(handler)` - * - * If handler is being attached to catch rejections, `options.catches` should be `true` - * - * @param {Function} fn - Test function - * @param {Object} options - Options object - * @param {boolean} [options.continues=false] - true if handler fires on resolved promise - * @param {boolean} [options.catches=false] - true if handler fires on rejected promise - * @param {boolean} [options.passThrough=false] - true if method passes through errors even if handler fires - * @returns {undefined} - */ - testSetProtoCallbackAsync: function(fn, options) { - var u = this; - describe('calls callback asynchronously when called on promise', function() { - u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { - u.testAsync(function(handler, cb) { - var p = makePromise(); + /** + * Run set of tests on a prototype method to ensure always calls callback asynchronously. + * Function `fn` should take provided `promise` and call the method being tested on it, + * attaching `handler` as the callback. + * e.g. `return promise.then(handler)` + * + * If handler is being attached to catch rejections, `options.catches` should be `true` + * + * @param {Function} fn - Test function + * @param {Object} options - Options object + * @param {boolean} [options.continues=false] - true if handler fires on resolved promise + * @param {boolean} [options.catches=false] - true if handler fires on rejected promise + * @param {boolean} [options.passThrough=false] - true if method passes through errors even if handler fires + * @returns {undefined} + */ + testSetProtoCallbackAsync: function(fn, options) { + var u = this; + describe('calls callback asynchronously when called on promise', function() { + u.describeResolveRejectSyncAsyncAttachSyncAsync(function(makePromise, attach) { + u.testAsync(function(handler, cb) { + var p = makePromise(); - attach(function() { - var newP = fn(p, handler); - if (options.passThrough) u.inheritRejectStatus(newP, p); - cb(newP); - }, p); - }); - }, u.Promise, options); - }); - }, + attach(function() { + var newP = fn(p, handler); + if (options.passThrough) u.inheritRejectStatus(newP, p); + cb(newP); + }, p); + }); + }, u.Promise, options); + }); + }, - /** - * Run set of tests on a static method to ensure always calls callback synchronously. - * Function `fn` should call the method being tested, attaching `handler` as the callback. - * e.g. `return Promise.try(handler)` - * - * @param {Function} fn - Test function - * @param {Object} [options] - Options object - * @param {Function} [options.handler] - Optional handler function - * @returns {undefined} - */ - testSetStaticCallbackSync: function(fn, options) { - var u = this; - options = options || {}; + /** + * Run set of tests on a static method to ensure always calls callback synchronously. + * Function `fn` should call the method being tested, attaching `handler` as the callback. + * e.g. `return Promise.try(handler)` + * + * @param {Function} fn - Test function + * @param {Object} [options] - Options object + * @param {Function} [options.handler] - Optional handler function + * @returns {undefined} + */ + testSetStaticCallbackSync: function(fn, options) { + var u = this; + options = options || {}; - describe('calls callback synchronously', function() { - u.testSync(function(handler, cb) { - var p = fn(handler); - cb(p); - }, options.handler); - }); - } + describe('calls callback synchronously', function() { + u.testSync(function(handler, cb) { + var p = fn(handler); + cb(p); + }, options.handler); + }); + } }; diff --git a/test/support/tests.js b/test/support/tests.js index 76953fe..3744534 100644 --- a/test/support/tests.js +++ b/test/support/tests.js @@ -8,241 +8,241 @@ // Exports module.exports = { - /** - * Run a function and check it returns a promise from patched constructor. - * `fn` is called immediately. - * - * Checks: - * - `fn()` returns a promise - * - `fn()` returns a promise of the right type - * Any failed check errors are registered on test object, and `t.done()` is called. - * - * @param {Function} fn - Function to run. - * @returns {undefined} - */ - testIsPromise: function(fn) { - var u = this; - u.test(function(t) { - var p = fn(); - t.error(u.checkIsPromise(p)); - t.done(p); - }); - }, - - /** - * Runs a function and checks it calls back a handler asynchronously. - * `fn` is called immediately, and passed a handler. - * - * Checks: - * - handler is called - * - handler is called asynchronously - * Any failed check errors are registered on test object, and `t.done()` is called. - * - * If `handler` argument is provided, it's executed as part of the handler. - * - * @param {Function} fn - Function to run. - * @param {Function} [handler] - Optional handler function - * @returns {undefined} - */ - testAsync: function(fn, handler) { - this._testSyncAsync(fn, false, handler); - }, - - /** - * Run a function and check it calls back a handler synchronously. - * `fn` is called immediately, and passed a handler. - * - * Checks: - * - handler is called - * - handler is called synchronously - * Any failed check errors are registered on test object, and `t.done()` is called. - * - * If `handler` argument is provided, it's executed as part of the handler. - * - * @param {Function} fn - Function to run. - * @param {Function} [handler] - Optional handler function - * @returns {undefined} - */ - testSync: function(fn, handler) { - this._testSyncAsync(fn, true, handler); - }, - - /** - * Runs a function and checks it calls back a handler synchronously or asynchronously. - * `fn` is called immediately, and passed a handler. - * Whether expect sync or async callback is defined by `expectSync` argument. - * - * Checks: - * - handler is called once - * - handler is called as expected (sync/async) - * Any failed check errors are registered on test object, and `t.done()` is called. - * - * If `handler` argument is provided, it's executed as part of the handler. - * - * @param {Function} fn - Function to run. - * @param {boolean} expectSync - true if expect callback to be called sync, false if expect async - * @param {Function} [handler] - Handler function - * @returns {undefined} - */ - _testSyncAsync: function(fn, expectSync, handler) { - var u = this; - u.test(function(t) { - // Create handler - var sync = true, - called = 0; - - var handlerWrapped = function() { - called++; - if (sync !== expectSync) t.error(new Error('Callback called ' + (expectSync ? 'asynchronously' : 'synchronously'))); - if (handler) return handler.apply(this, arguments); - }; - - // Run test function with handler - fn(handlerWrapped, function(p) { - sync = false; - - // Check handler was called once - t.done(p, function() { - if (!called) t.error(new Error('Callback not called')); - if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); - }); - }); - }); - }, - - /** - * Runs a function and checks that when it calls back a handler, the handler has been bound to CLS context. - * `fn` is called immediately, and passed a handler. - * `fn` should create a promise and call callback `cb` with it. - * - * Checks: - * - handler is called once - * - Handler is bound to correct context - * - Handler is bound exactly once, synchronously after handler attached - * - Handler is not bound again before handler is executed (asynchronously) - * - * Any failed check errors are registered on test object, and `t.done()` is called. - * - * `preFn` (if provided) is executed before CLS context created and result passed to `fn` as 2nd arg. - * `handler` (if provided) is executed as part of the handler. - * - * @param {Function} fn - Function to run. - * @param {Function} [preFn] - Function to run before CLS context created - * @param {Function} [handler] - Handler function - * @returns {undefined} - */ - testBound: function(fn, preFn, handler) { - var u = this; - u.test(function(t) { - var preResult; - if (preFn) preResult = preFn(); - - u.runInContext(function(context) { - // Create handler - var called = 0; - - var handlerWrapped = function() { - called++; - t.error(u.checkBound(handlerWrapped, context)); - if (handler) return handler.apply(this, arguments); - }; - - // Run test function with handler - fn(handlerWrapped, preResult, function(p) { - // Check that bound synchronously - t.error(u.checkBound(handlerWrapped, context)); - - // Check handler was called once - t.done(p, function() { - if (!called) t.error(new Error('Callback not called')); - if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); - }); - }); - }); - }); - }, - - /** - * Runs a function and checks that when it calls back a handler, the handler has not been bound to a CLS context. - * `fn` is called immediately, and passed a handler. - * - * Checks: - * - handler is called once - * - handler is not bound - * Any failed check errors are registered on test object, and `t.done()` is called. - * - * If `handler` argument is provided, it's executed as part of the handler. - * - * @param {Function} fn - Function to run. - * @param {Function} [handler] - Handler function - * @returns {undefined} - */ - testNotBound: function(fn, handler) { - var u = this; - u.test(function(t) { - // Create handler - var called = 0; - - var handlerWrapped = function() { - called++; - t.error(u.checkNotBound(handlerWrapped)); - if (handler) return handler.apply(this, arguments); - }; - - // Run test function with handler - var p = fn(handlerWrapped); - - // Check handler was called once - t.done(p, function() { - if (!called) t.error(new Error('Callback not called')); - if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); - }); - }); - }, - - /** - * Runs a function and checks that when it calls back a handler, the handler runs within correct CLS context. - * `fn` is called immediately, and passed a handler. - * - * Checks: - * - handler is called once - * - handler is run in correct context - * - * Any failed check errors are registered on test object, and `t.done()` is called. - * - * `preFn` (if provided) is executed before CLS context created and result passed to `fn` as 2nd arg. - * `handler` (if provided) is executed as part of the handler. - * - * @param {Function} fn - Function to run. - * @param {Function} [preFn] - Function to run before CLS context created - * @param {Function} [handler] - Handler function - * @returns {undefined} - */ - testRunContext: function(fn, preFn, handler) { - var u = this; - u.testMultiple(function(t) { - var preResult; - if (preFn) preResult = preFn(); - - u.runInContext(function(context) { - // Create handler - var called = 0; - - var handlerWrapped = function() { - called++; - if (u.ns.active !== context) t.error(new Error('Function run in wrong context (expected: ' + JSON.stringify(context) + ', got: ' + JSON.stringify(u.ns.active) + ')')); - if (handler) return handler.apply(this, arguments); - }; - - // Run test function with handler - fn(handlerWrapped, preResult, function(p) { - // Check handler was called once - t.done(p, function() { - if (!called) t.error(new Error('Callback not called')); - if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); - }); - }); - }); - }); - } + /** + * Run a function and check it returns a promise from patched constructor. + * `fn` is called immediately. + * + * Checks: + * - `fn()` returns a promise + * - `fn()` returns a promise of the right type + * Any failed check errors are registered on test object, and `t.done()` is called. + * + * @param {Function} fn - Function to run. + * @returns {undefined} + */ + testIsPromise: function(fn) { + var u = this; + u.test(function(t) { + var p = fn(); + t.error(u.checkIsPromise(p)); + t.done(p); + }); + }, + + /** + * Runs a function and checks it calls back a handler asynchronously. + * `fn` is called immediately, and passed a handler. + * + * Checks: + * - handler is called + * - handler is called asynchronously + * Any failed check errors are registered on test object, and `t.done()` is called. + * + * If `handler` argument is provided, it's executed as part of the handler. + * + * @param {Function} fn - Function to run. + * @param {Function} [handler] - Optional handler function + * @returns {undefined} + */ + testAsync: function(fn, handler) { + this._testSyncAsync(fn, false, handler); + }, + + /** + * Run a function and check it calls back a handler synchronously. + * `fn` is called immediately, and passed a handler. + * + * Checks: + * - handler is called + * - handler is called synchronously + * Any failed check errors are registered on test object, and `t.done()` is called. + * + * If `handler` argument is provided, it's executed as part of the handler. + * + * @param {Function} fn - Function to run. + * @param {Function} [handler] - Optional handler function + * @returns {undefined} + */ + testSync: function(fn, handler) { + this._testSyncAsync(fn, true, handler); + }, + + /** + * Runs a function and checks it calls back a handler synchronously or asynchronously. + * `fn` is called immediately, and passed a handler. + * Whether expect sync or async callback is defined by `expectSync` argument. + * + * Checks: + * - handler is called once + * - handler is called as expected (sync/async) + * Any failed check errors are registered on test object, and `t.done()` is called. + * + * If `handler` argument is provided, it's executed as part of the handler. + * + * @param {Function} fn - Function to run. + * @param {boolean} expectSync - true if expect callback to be called sync, false if expect async + * @param {Function} [handler] - Handler function + * @returns {undefined} + */ + _testSyncAsync: function(fn, expectSync, handler) { + var u = this; + u.test(function(t) { + // Create handler + var sync = true, + called = 0; + + var handlerWrapped = function() { + called++; + if (sync !== expectSync) t.error(new Error('Callback called ' + (expectSync ? 'asynchronously' : 'synchronously'))); + if (handler) return handler.apply(this, arguments); + }; + + // Run test function with handler + fn(handlerWrapped, function(p) { + sync = false; + + // Check handler was called once + t.done(p, function() { + if (!called) t.error(new Error('Callback not called')); + if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); + }); + }); + }); + }, + + /** + * Runs a function and checks that when it calls back a handler, the handler has been bound to CLS context. + * `fn` is called immediately, and passed a handler. + * `fn` should create a promise and call callback `cb` with it. + * + * Checks: + * - handler is called once + * - Handler is bound to correct context + * - Handler is bound exactly once, synchronously after handler attached + * - Handler is not bound again before handler is executed (asynchronously) + * + * Any failed check errors are registered on test object, and `t.done()` is called. + * + * `preFn` (if provided) is executed before CLS context created and result passed to `fn` as 2nd arg. + * `handler` (if provided) is executed as part of the handler. + * + * @param {Function} fn - Function to run. + * @param {Function} [preFn] - Function to run before CLS context created + * @param {Function} [handler] - Handler function + * @returns {undefined} + */ + testBound: function(fn, preFn, handler) { + var u = this; + u.test(function(t) { + var preResult; + if (preFn) preResult = preFn(); + + u.runInContext(function(context) { + // Create handler + var called = 0; + + var handlerWrapped = function() { + called++; + t.error(u.checkBound(handlerWrapped, context)); + if (handler) return handler.apply(this, arguments); + }; + + // Run test function with handler + fn(handlerWrapped, preResult, function(p) { + // Check that bound synchronously + t.error(u.checkBound(handlerWrapped, context)); + + // Check handler was called once + t.done(p, function() { + if (!called) t.error(new Error('Callback not called')); + if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); + }); + }); + }); + }); + }, + + /** + * Runs a function and checks that when it calls back a handler, the handler has not been bound to a CLS context. + * `fn` is called immediately, and passed a handler. + * + * Checks: + * - handler is called once + * - handler is not bound + * Any failed check errors are registered on test object, and `t.done()` is called. + * + * If `handler` argument is provided, it's executed as part of the handler. + * + * @param {Function} fn - Function to run. + * @param {Function} [handler] - Handler function + * @returns {undefined} + */ + testNotBound: function(fn, handler) { + var u = this; + u.test(function(t) { + // Create handler + var called = 0; + + var handlerWrapped = function() { + called++; + t.error(u.checkNotBound(handlerWrapped)); + if (handler) return handler.apply(this, arguments); + }; + + // Run test function with handler + var p = fn(handlerWrapped); + + // Check handler was called once + t.done(p, function() { + if (!called) t.error(new Error('Callback not called')); + if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); + }); + }); + }, + + /** + * Runs a function and checks that when it calls back a handler, the handler runs within correct CLS context. + * `fn` is called immediately, and passed a handler. + * + * Checks: + * - handler is called once + * - handler is run in correct context + * + * Any failed check errors are registered on test object, and `t.done()` is called. + * + * `preFn` (if provided) is executed before CLS context created and result passed to `fn` as 2nd arg. + * `handler` (if provided) is executed as part of the handler. + * + * @param {Function} fn - Function to run. + * @param {Function} [preFn] - Function to run before CLS context created + * @param {Function} [handler] - Handler function + * @returns {undefined} + */ + testRunContext: function(fn, preFn, handler) { + var u = this; + u.testMultiple(function(t) { + var preResult; + if (preFn) preResult = preFn(); + + u.runInContext(function(context) { + // Create handler + var called = 0; + + var handlerWrapped = function() { + called++; + if (u.ns.active !== context) t.error(new Error('Function run in wrong context (expected: ' + JSON.stringify(context) + ', got: ' + JSON.stringify(u.ns.active) + ')')); + if (handler) return handler.apply(this, arguments); + }; + + // Run test function with handler + fn(handlerWrapped, preResult, function(p) { + // Check handler was called once + t.done(p, function() { + if (!called) t.error(new Error('Callback not called')); + if (called !== 1) t.error(new Error('Callback called ' + called + ' times')); + }); + }); + }); + }); + } }; diff --git a/test/support/utils.js b/test/support/utils.js index 454bb05..67beb82 100644 --- a/test/support/utils.js +++ b/test/support/utils.js @@ -8,132 +8,132 @@ var _ = require('lodash'); // Imports var addCtors = require('./ctors'), - test = require('./test'), - promises = require('./promises'), - checks = require('./checks'), - tests = require('./tests'), - describeSets = require('./describeSets'), - testSetPromise = require('./testSets/promise'), - testSetSyncAsync = require('./testSets/syncAsync'), - testSetBinding = require('./testSets/binding'), - testSetContext = require('./testSets/context'), - testSetGroups = require('./testSets/groups'); + test = require('./test'), + promises = require('./promises'), + checks = require('./checks'), + tests = require('./tests'), + describeSets = require('./describeSets'), + testSetPromise = require('./testSets/promise'), + testSetSyncAsync = require('./testSets/syncAsync'), + testSetBinding = require('./testSets/binding'), + testSetContext = require('./testSets/context'), + testSetGroups = require('./testSets/groups'); // Constants var REJECT_STATUS_KEY = '__clsBluebirdTestRejectStatus'; // Exports function Utils(Promise, UnpatchedPromise, ns, altPromises, bluebirdVersion) { - this.Promise = Promise; - this.UnpatchedPromise = UnpatchedPromise; - this.ns = ns; - this.altPromises = altPromises; - this.bluebirdVersion = bluebirdVersion; + this.Promise = Promise; + this.UnpatchedPromise = UnpatchedPromise; + this.ns = ns; + this.altPromises = altPromises; + this.bluebirdVersion = bluebirdVersion; - addCtors(this); + addCtors(this); } // Define initial value for `nextId`, used by `.runInContext()` var nextId = 1; Utils.prototype = { - /** - * Create a CLS context and run function within it. - * Context is created with a unique `_id` attribute within it. - * `fn` is called with the CLS context object as argument. - * - * @param {Object} ns - CLS namespace to run within - * @param {Function} fn - Function to execute within context - * @returns {*} - Return value of `fn()` - */ - runInContext: function(fn) { - var u = this; - return u.runAndReturn(function(context) { - var id = nextId; - u.ns.set('_id', id); - nextId++; - - return fn(context); - }); - }, - - /** - * Creates CLS context and runs a function within it. - * Like `ns.run(fn)` but returns the return value of `fn` rather than the context object. - * `fn` is called with the CLS context object as argument. - * - * @param {Function} fn - Function to execute within context - * @returns {*} - Return value of `fn()` - */ - runAndReturn: function runAndReturn(fn) { - var u = this; - var value; - u.ns.run(function(context) { - value = fn(context); - }); - return value; - }, - - /** - * Await settling of promise and call callback when settled. - * Callback is called regardless of whether promise resolves or rejects. - * Always calls callback asynchronously even if promise is already settled at time function is called. - * - * @param {Promise} promise - Promise to watch - * @param {Function} cb - Callback function to call when promise is resolved - * @returns {undefined} - */ - awaitPromise: function(promise, cb) { - (function checkResolved() { - setImmediate(function() { - if (!promise.isPending()) { - cb(); - return; - } - checkResolved(); - }); - })(); - }, - - /** - * Get rejection status of promise. - * @param {Promise} - Promise to get status of - * @returns {boolean} - true if rejecting, false if not - */ - getRejectStatus: function(promise) { - if (!promise) return false; - return !!promise[REJECT_STATUS_KEY]; - }, - - /** - * Set rejection status of promise as rejecting. - * @param {Promise} - Promise to set status of - * @returns {Promise} - Input promise - */ - setRejectStatus: function(promise) { - promise[REJECT_STATUS_KEY] = true; - return promise; - }, - - /** - * Inherit rejection status from one promise to another. - * @param {Promise} target - Target promise - * @param {Promise} source - Source promise - * @returns {Promise} - Target promise - */ - inheritRejectStatus: function(target, source) { - target[REJECT_STATUS_KEY] = this.getRejectStatus(source); - return target; - }, - - /** - * Attach empty catch handler to promise to prevent unhandled rejections - * @param {Promise} promise - Promise to attach catch handler to - * @returns {undefined} - */ - suppressUnhandledRejections: function(promise) { - promise.catch(function() {}); - } + /** + * Create a CLS context and run function within it. + * Context is created with a unique `_id` attribute within it. + * `fn` is called with the CLS context object as argument. + * + * @param {Object} ns - CLS namespace to run within + * @param {Function} fn - Function to execute within context + * @returns {*} - Return value of `fn()` + */ + runInContext: function(fn) { + var u = this; + return u.runAndReturn(function(context) { + var id = nextId; + u.ns.set('_id', id); + nextId++; + + return fn(context); + }); + }, + + /** + * Creates CLS context and runs a function within it. + * Like `ns.run(fn)` but returns the return value of `fn` rather than the context object. + * `fn` is called with the CLS context object as argument. + * + * @param {Function} fn - Function to execute within context + * @returns {*} - Return value of `fn()` + */ + runAndReturn: function runAndReturn(fn) { + var u = this; + var value; + u.ns.run(function(context) { + value = fn(context); + }); + return value; + }, + + /** + * Await settling of promise and call callback when settled. + * Callback is called regardless of whether promise resolves or rejects. + * Always calls callback asynchronously even if promise is already settled at time function is called. + * + * @param {Promise} promise - Promise to watch + * @param {Function} cb - Callback function to call when promise is resolved + * @returns {undefined} + */ + awaitPromise: function(promise, cb) { + (function checkResolved() { + setImmediate(function() { + if (!promise.isPending()) { + cb(); + return; + } + checkResolved(); + }); + })(); + }, + + /** + * Get rejection status of promise. + * @param {Promise} - Promise to get status of + * @returns {boolean} - true if rejecting, false if not + */ + getRejectStatus: function(promise) { + if (!promise) return false; + return !!promise[REJECT_STATUS_KEY]; + }, + + /** + * Set rejection status of promise as rejecting. + * @param {Promise} - Promise to set status of + * @returns {Promise} - Input promise + */ + setRejectStatus: function(promise) { + promise[REJECT_STATUS_KEY] = true; + return promise; + }, + + /** + * Inherit rejection status from one promise to another. + * @param {Promise} target - Target promise + * @param {Promise} source - Source promise + * @returns {Promise} - Target promise + */ + inheritRejectStatus: function(target, source) { + target[REJECT_STATUS_KEY] = this.getRejectStatus(source); + return target; + }, + + /** + * Attach empty catch handler to promise to prevent unhandled rejections + * @param {Promise} promise - Promise to attach catch handler to + * @returns {undefined} + */ + suppressUnhandledRejections: function(promise) { + promise.catch(function() {}); + } }; // mixins