UNPKG

co-mocha

Version:

Enable support for generators in Mocha tests

343 lines (294 loc) 8.25 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.coMocha = f()}})(function(){var define,module,exports;return (function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){ var co = require('co') var isGenFn = require('is-generator').fn /** * Export `co-mocha`. */ module.exports = coMocha /** * Monkey patch the mocha instance with generator support. * * @param {Function} mocha */ function coMocha (mocha) { // Avoid loading `co-mocha` twice. if (!mocha || mocha._coMochaIsLoaded) { return } var Runnable = mocha.Runnable var run = Runnable.prototype.run /** * Override the Mocha function runner and enable generator support with co. * * @param {Function} fn */ Runnable.prototype.run = function (fn) { var oldFn = this.fn if (isGenFn(oldFn)) { this.fn = co.wrap(oldFn) // Replace `toString` to output the original function contents. this.fn.toString = function () { // https://github.com/mochajs/mocha/blob/7493bca76662318183e55294e906a4107433e20e/lib/utils.js#L251 return Function.prototype.toString.call(oldFn) .replace(/^function *\* *\(.*\)\s*{/, 'function () {') } } return run.call(this, fn) } mocha._coMochaIsLoaded = true } /** * Find active node mocha instances. * * @return {Array} */ function findNodeJSMocha () { var children = require.cache || {} return Object.keys(children) .filter(function (child) { var val = children[child].exports return typeof val === 'function' && val.name === 'Mocha' }) .map(function (child) { return children[child].exports }) } // Attempt to automatically monkey patch available mocha instances. var modules = typeof window === 'undefined' ? findNodeJSMocha() : [window.Mocha] modules.forEach(coMocha) },{"co":2,"is-generator":3}],2:[function(require,module,exports){ /** * slice() reference. */ var slice = Array.prototype.slice; /** * Expose `co`. */ module.exports = co['default'] = co.co = co; /** * Wrap the given generator `fn` into a * function that returns a promise. * This is a separate function so that * every `co()` call doesn't create a new, * unnecessary closure. * * @param {GeneratorFunction} fn * @return {Function} * @api public */ co.wrap = function (fn) { createPromise.__generatorFunction__ = fn; return createPromise; function createPromise() { return co.call(this, fn.apply(this, arguments)); } }; /** * Execute the generator function or a generator * and return a promise. * * @param {Function} fn * @return {Promise} * @api public */ function co(gen) { var ctx = this; var args = slice.call(arguments, 1) // we wrap everything in a promise to avoid promise chaining, // which leads to memory leak errors. // see https://github.com/tj/co/issues/180 return new Promise(function(resolve, reject) { if (typeof gen === 'function') gen = gen.apply(ctx, args); if (!gen || typeof gen.next !== 'function') return resolve(gen); onFulfilled(); /** * @param {Mixed} res * @return {Promise} * @api private */ function onFulfilled(res) { var ret; try { ret = gen.next(res); } catch (e) { return reject(e); } next(ret); } /** * @param {Error} err * @return {Promise} * @api private */ function onRejected(err) { var ret; try { ret = gen.throw(err); } catch (e) { return reject(e); } next(ret); } /** * Get the next value in the generator, * return a promise. * * @param {Object} ret * @return {Promise} * @api private */ function next(ret) { if (ret.done) return resolve(ret.value); var value = toPromise.call(ctx, ret.value); if (value && isPromise(value)) return value.then(onFulfilled, onRejected); return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, ' + 'but the following object was passed: "' + String(ret.value) + '"')); } }); } /** * Convert a `yield`ed value into a promise. * * @param {Mixed} obj * @return {Promise} * @api private */ function toPromise(obj) { if (!obj) return obj; if (isPromise(obj)) return obj; if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj); if ('function' == typeof obj) return thunkToPromise.call(this, obj); if (Array.isArray(obj)) return arrayToPromise.call(this, obj); if (isObject(obj)) return objectToPromise.call(this, obj); return obj; } /** * Convert a thunk to a promise. * * @param {Function} * @return {Promise} * @api private */ function thunkToPromise(fn) { var ctx = this; return new Promise(function (resolve, reject) { fn.call(ctx, function (err, res) { if (err) return reject(err); if (arguments.length > 2) res = slice.call(arguments, 1); resolve(res); }); }); } /** * Convert an array of "yieldables" to a promise. * Uses `Promise.all()` internally. * * @param {Array} obj * @return {Promise} * @api private */ function arrayToPromise(obj) { return Promise.all(obj.map(toPromise, this)); } /** * Convert an object of "yieldables" to a promise. * Uses `Promise.all()` internally. * * @param {Object} obj * @return {Promise} * @api private */ function objectToPromise(obj){ var results = new obj.constructor(); var keys = Object.keys(obj); var promises = []; for (var i = 0; i < keys.length; i++) { var key = keys[i]; var promise = toPromise.call(this, obj[key]); if (promise && isPromise(promise)) defer(promise, key); else results[key] = obj[key]; } return Promise.all(promises).then(function () { return results; }); function defer(promise, key) { // predefine the key in the result results[key] = undefined; promises.push(promise.then(function (res) { results[key] = res; })); } } /** * Check if `obj` is a promise. * * @param {Object} obj * @return {Boolean} * @api private */ function isPromise(obj) { return 'function' == typeof obj.then; } /** * Check if `obj` is a generator. * * @param {Mixed} obj * @return {Boolean} * @api private */ function isGenerator(obj) { return 'function' == typeof obj.next && 'function' == typeof obj.throw; } /** * Check if `obj` is a generator function. * * @param {Mixed} obj * @return {Boolean} * @api private */ function isGeneratorFunction(obj) { var constructor = obj.constructor; if (!constructor) return false; if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true; return isGenerator(constructor.prototype); } /** * Check for plain object. * * @param {Mixed} val * @return {Boolean} * @api private */ function isObject(val) { return Object == val.constructor; } },{}],3:[function(require,module,exports){ /** * Export generator function checks. */ module.exports = isGenerator module.exports.fn = isGeneratorFunction /** * Check whether an object is a generator. * * @param {Object} obj * @return {Boolean} */ function isGenerator (obj) { return obj && typeof obj.next === 'function' && typeof obj.throw === 'function' } /** * Check whether a function is generator. * * @param {Function} fn * @return {Boolean} */ function isGeneratorFunction (fn) { return typeof fn === 'function' && fn.constructor && fn.constructor.name === 'GeneratorFunction' } },{}]},{},[1])(1) });