UNPKG

cache-lib

Version:

cache.js 是一个轻量级的 JS 库,对 `localStorage`、`sessionStorage`进行了扩展,增加了序列化方法和过期时间。可以直接存取JSON对象、设置过期时间。

2,282 lines (2,028 loc) 502 kB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ (function (process,global){ 'use strict'; /* eslint no-unused-vars: off */ /* eslint-env commonjs */ /** * Shim process.stdout. */ process.stdout = require('browser-stdout')({level: false}); var Mocha = require('./lib/mocha'); /** * Create a Mocha instance. * * @return {undefined} */ var mocha = new Mocha({reporter: 'html'}); /** * Save timer references to avoid Sinon interfering (see GH-237). */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; var uncaughtExceptionHandlers = []; var originalOnerrorHandler = global.onerror; /** * Remove uncaughtException listener. * Revert to original onerror handler if previously defined. */ process.removeListener = function(e, fn) { if (e === 'uncaughtException') { if (originalOnerrorHandler) { global.onerror = originalOnerrorHandler; } else { global.onerror = function() {}; } var i = uncaughtExceptionHandlers.indexOf(fn); if (i !== -1) { uncaughtExceptionHandlers.splice(i, 1); } } }; /** * Implements uncaughtException listener. */ process.on = function(e, fn) { if (e === 'uncaughtException') { global.onerror = function(err, url, line) { fn(new Error(err + ' (' + url + ':' + line + ')')); return !mocha.allowUncaught; }; uncaughtExceptionHandlers.push(fn); } }; // The BDD UI is registered by default, but no UI will be functional in the // browser without an explicit call to the overridden `mocha.ui` (see below). // Ensure that this default UI does not expose its methods to the global scope. mocha.suite.removeAllListeners('pre-require'); var immediateQueue = []; var immediateTimeout; function timeslice() { var immediateStart = new Date().getTime(); while (immediateQueue.length && new Date().getTime() - immediateStart < 100) { immediateQueue.shift()(); } if (immediateQueue.length) { immediateTimeout = setTimeout(timeslice, 0); } else { immediateTimeout = null; } } /** * High-performance override of Runner.immediately. */ Mocha.Runner.immediately = function(callback) { immediateQueue.push(callback); if (!immediateTimeout) { immediateTimeout = setTimeout(timeslice, 0); } }; /** * Function to allow assertion libraries to throw errors directly into mocha. * This is useful when running tests in a browser because window.onerror will * only receive the 'message' attribute of the Error. */ mocha.throwError = function(err) { uncaughtExceptionHandlers.forEach(function(fn) { fn(err); }); throw err; }; /** * Override ui to ensure that the ui functions are initialized. * Normally this would happen in Mocha.prototype.loadFiles. */ mocha.ui = function(ui) { Mocha.prototype.ui.call(this, ui); this.suite.emit('pre-require', global, null, this); return this; }; /** * Setup mocha with the given setting options. */ mocha.setup = function(opts) { if (typeof opts === 'string') { opts = {ui: opts}; } for (var opt in opts) { if (opts.hasOwnProperty(opt)) { this[opt](opts[opt]); } } return this; }; /** * Run mocha, returning the Runner. */ mocha.run = function(fn) { var options = mocha.options; mocha.globals('location'); var query = Mocha.utils.parseQuery(global.location.search || ''); if (query.grep) { mocha.grep(query.grep); } if (query.fgrep) { mocha.fgrep(query.fgrep); } if (query.invert) { mocha.invert(); } return Mocha.prototype.run.call(mocha, function(err) { // The DOM Document is not available in Web Workers. var document = global.document; if ( document && document.getElementById('mocha') && options.noHighlighting !== true ) { Mocha.utils.highlightTags('code'); } if (fn) { fn(err); } }); }; /** * Expose the process shim. * https://github.com/mochajs/mocha/pull/916 */ Mocha.process = process; /** * Expose mocha. */ global.Mocha = Mocha; global.mocha = mocha; // this allows test/acceptance/required-tokens.js to pass; thus, // you can now do `const describe = require('mocha').describe` in a // browser context (assuming browserification). should fix #880 module.exports = global; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./lib/mocha":13,"_process":56,"browser-stdout":39}],2:[function(require,module,exports){ 'use strict'; // just stub out growl module.exports = require('../utils').noop; },{"../utils":36}],3:[function(require,module,exports){ 'use strict'; /** * Expose `Progress`. */ module.exports = Progress; /** * Initialize a new `Progress` indicator. */ function Progress() { this.percent = 0; this.size(0); this.fontSize(11); this.font('helvetica, arial, sans-serif'); } /** * Set progress size to `size`. * * @api public * @param {number} size * @return {Progress} Progress instance. */ Progress.prototype.size = function(size) { this._size = size; return this; }; /** * Set text to `text`. * * @api public * @param {string} text * @return {Progress} Progress instance. */ Progress.prototype.text = function(text) { this._text = text; return this; }; /** * Set font size to `size`. * * @api public * @param {number} size * @return {Progress} Progress instance. */ Progress.prototype.fontSize = function(size) { this._fontSize = size; return this; }; /** * Set font to `family`. * * @param {string} family * @return {Progress} Progress instance. */ Progress.prototype.font = function(family) { this._font = family; return this; }; /** * Update percentage to `n`. * * @param {number} n * @return {Progress} Progress instance. */ Progress.prototype.update = function(n) { this.percent = n; return this; }; /** * Draw on `ctx`. * * @param {CanvasRenderingContext2d} ctx * @return {Progress} Progress instance. */ Progress.prototype.draw = function(ctx) { try { var percent = Math.min(this.percent, 100); var size = this._size; var half = size / 2; var x = half; var y = half; var rad = half - 1; var fontSize = this._fontSize; ctx.font = fontSize + 'px ' + this._font; var angle = Math.PI * 2 * (percent / 100); ctx.clearRect(0, 0, size, size); // outer circle ctx.strokeStyle = '#9f9f9f'; ctx.beginPath(); ctx.arc(x, y, rad, 0, angle, false); ctx.stroke(); // inner circle ctx.strokeStyle = '#eee'; ctx.beginPath(); ctx.arc(x, y, rad - 1, 0, angle, true); ctx.stroke(); // text var text = this._text || (percent | 0) + '%'; var w = ctx.measureText(text).width; ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1); } catch (ignore) { // don't fail if we can't render progress } return this; }; },{}],4:[function(require,module,exports){ (function (global){ 'use strict'; exports.isatty = function isatty() { return true; }; exports.getWindowSize = function getWindowSize() { if ('innerHeight' in global) { return [global.innerHeight, global.innerWidth]; } // In a Web Worker, the DOM Window is not available. return [640, 480]; }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],5:[function(require,module,exports){ 'use strict'; /** * @module Context */ /** * Expose `Context`. */ module.exports = Context; /** * Initialize a new `Context`. * * @api private */ function Context() {} /** * Set or get the context `Runnable` to `runnable`. * * @api private * @param {Runnable} runnable * @return {Context} context */ Context.prototype.runnable = function(runnable) { if (!arguments.length) { return this._runnable; } this.test = this._runnable = runnable; return this; }; /** * Set or get test timeout `ms`. * * @api private * @param {number} ms * @return {Context} self */ Context.prototype.timeout = function(ms) { if (!arguments.length) { return this.runnable().timeout(); } this.runnable().timeout(ms); return this; }; /** * Set test timeout `enabled`. * * @api private * @param {boolean} enabled * @return {Context} self */ Context.prototype.enableTimeouts = function(enabled) { if (!arguments.length) { return this.runnable().enableTimeouts(); } this.runnable().enableTimeouts(enabled); return this; }; /** * Set or get test slowness threshold `ms`. * * @api private * @param {number} ms * @return {Context} self */ Context.prototype.slow = function(ms) { if (!arguments.length) { return this.runnable().slow(); } this.runnable().slow(ms); return this; }; /** * Mark a test as skipped. * * @api private * @throws Pending */ Context.prototype.skip = function() { this.runnable().skip(); }; /** * Set or get a number of allowed retries on failed tests * * @api private * @param {number} n * @return {Context} self */ Context.prototype.retries = function(n) { if (!arguments.length) { return this.runnable().retries(); } this.runnable().retries(n); return this; }; },{}],6:[function(require,module,exports){ 'use strict'; var Runnable = require('./runnable'); var inherits = require('./utils').inherits; /** * Expose `Hook`. */ module.exports = Hook; /** * Initialize a new `Hook` with the given `title` and callback `fn` * * @class * @extends Runnable * @param {String} title * @param {Function} fn */ function Hook(title, fn) { Runnable.call(this, title, fn); this.type = 'hook'; } /** * Inherit from `Runnable.prototype`. */ inherits(Hook, Runnable); /** * Get or set the test `err`. * * @memberof Hook * @public * @param {Error} err * @return {Error} */ Hook.prototype.error = function(err) { if (!arguments.length) { err = this._error; this._error = null; return err; } this._error = err; }; },{"./runnable":32,"./utils":36}],7:[function(require,module,exports){ 'use strict'; var Test = require('../test'); /** * BDD-style interface: * * describe('Array', function() { * describe('#indexOf()', function() { * it('should return -1 when not present', function() { * // ... * }); * * it('should return the index when present', function() { * // ... * }); * }); * }); * * @param {Suite} suite Root suite. */ module.exports = function bddInterface(suite) { var suites = [suite]; suite.on('pre-require', function(context, file, mocha) { var common = require('./common')(suites, context, mocha); context.before = common.before; context.after = common.after; context.beforeEach = common.beforeEach; context.afterEach = common.afterEach; context.run = mocha.options.delay && common.runWithSuite(suite); /** * Describe a "suite" with the given `title` * and callback `fn` containing nested suites * and/or tests. */ context.describe = context.context = function(title, fn) { return common.suite.create({ title: title, file: file, fn: fn }); }; /** * Pending describe. */ context.xdescribe = context.xcontext = context.describe.skip = function( title, fn ) { return common.suite.skip({ title: title, file: file, fn: fn }); }; /** * Exclusive suite. */ context.describe.only = function(title, fn) { return common.suite.only({ title: title, file: file, fn: fn }); }; /** * Describe a specification or test-case * with the given `title` and callback `fn` * acting as a thunk. */ context.it = context.specify = function(title, fn) { var suite = suites[0]; if (suite.isPending()) { fn = null; } var test = new Test(title, fn); test.file = file; suite.addTest(test); return test; }; /** * Exclusive test-case. */ context.it.only = function(title, fn) { return common.test.only(mocha, context.it(title, fn)); }; /** * Pending test case. */ context.xit = context.xspecify = context.it.skip = function(title) { return context.it(title); }; /** * Number of attempts to retry. */ context.it.retries = function(n) { context.retries(n); }; }); }; },{"../test":35,"./common":8}],8:[function(require,module,exports){ 'use strict'; var Suite = require('../suite'); /** * Functions common to more than one interface. * * @param {Suite[]} suites * @param {Context} context * @param {Mocha} mocha * @return {Object} An object containing common functions. */ module.exports = function(suites, context, mocha) { return { /** * This is only present if flag --delay is passed into Mocha. It triggers * root suite execution. * * @param {Suite} suite The root suite. * @return {Function} A function which runs the root suite */ runWithSuite: function runWithSuite(suite) { return function run() { suite.run(); }; }, /** * Execute before running tests. * * @param {string} name * @param {Function} fn */ before: function(name, fn) { suites[0].beforeAll(name, fn); }, /** * Execute after running tests. * * @param {string} name * @param {Function} fn */ after: function(name, fn) { suites[0].afterAll(name, fn); }, /** * Execute before each test case. * * @param {string} name * @param {Function} fn */ beforeEach: function(name, fn) { suites[0].beforeEach(name, fn); }, /** * Execute after each test case. * * @param {string} name * @param {Function} fn */ afterEach: function(name, fn) { suites[0].afterEach(name, fn); }, suite: { /** * Create an exclusive Suite; convenience function * See docstring for create() below. * * @param {Object} opts * @returns {Suite} */ only: function only(opts) { opts.isOnly = true; return this.create(opts); }, /** * Create a Suite, but skip it; convenience function * See docstring for create() below. * * @param {Object} opts * @returns {Suite} */ skip: function skip(opts) { opts.pending = true; return this.create(opts); }, /** * Creates a suite. * @param {Object} opts Options * @param {string} opts.title Title of Suite * @param {Function} [opts.fn] Suite Function (not always applicable) * @param {boolean} [opts.pending] Is Suite pending? * @param {string} [opts.file] Filepath where this Suite resides * @param {boolean} [opts.isOnly] Is Suite exclusive? * @returns {Suite} */ create: function create(opts) { var suite = Suite.create(suites[0], opts.title); suite.pending = Boolean(opts.pending); suite.file = opts.file; suites.unshift(suite); if (opts.isOnly) { suite.parent._onlySuites = suite.parent._onlySuites.concat(suite); } if (typeof opts.fn === 'function') { opts.fn.call(suite); suites.shift(); } else if (typeof opts.fn === 'undefined' && !suite.pending) { throw new Error( 'Suite "' + suite.fullTitle() + '" was defined but no callback was supplied. Supply a callback or explicitly skip the suite.' ); } else if (!opts.fn && suite.pending) { suites.shift(); } return suite; } }, test: { /** * Exclusive test-case. * * @param {Object} mocha * @param {Function} test * @returns {*} */ only: function(mocha, test) { test.parent._onlyTests = test.parent._onlyTests.concat(test); return test; }, /** * Pending test case. * * @param {string} title */ skip: function(title) { context.test(title); }, /** * Number of retry attempts * * @param {number} n */ retries: function(n) { context.retries(n); } } }; }; },{"../suite":34}],9:[function(require,module,exports){ 'use strict'; var Suite = require('../suite'); var Test = require('../test'); /** * Exports-style (as Node.js module) interface: * * exports.Array = { * '#indexOf()': { * 'should return -1 when the value is not present': function() { * * }, * * 'should return the correct index when the value is present': function() { * * } * } * }; * * @param {Suite} suite Root suite. */ module.exports = function(suite) { var suites = [suite]; suite.on('require', visit); function visit(obj, file) { var suite; for (var key in obj) { if (typeof obj[key] === 'function') { var fn = obj[key]; switch (key) { case 'before': suites[0].beforeAll(fn); break; case 'after': suites[0].afterAll(fn); break; case 'beforeEach': suites[0].beforeEach(fn); break; case 'afterEach': suites[0].afterEach(fn); break; default: var test = new Test(key, fn); test.file = file; suites[0].addTest(test); } } else { suite = Suite.create(suites[0], key); suites.unshift(suite); visit(obj[key], file); suites.shift(); } } } }; },{"../suite":34,"../test":35}],10:[function(require,module,exports){ 'use strict'; exports.bdd = require('./bdd'); exports.tdd = require('./tdd'); exports.qunit = require('./qunit'); exports.exports = require('./exports'); },{"./bdd":7,"./exports":9,"./qunit":11,"./tdd":12}],11:[function(require,module,exports){ 'use strict'; var Test = require('../test'); /** * QUnit-style interface: * * suite('Array'); * * test('#length', function() { * var arr = [1,2,3]; * ok(arr.length == 3); * }); * * test('#indexOf()', function() { * var arr = [1,2,3]; * ok(arr.indexOf(1) == 0); * ok(arr.indexOf(2) == 1); * ok(arr.indexOf(3) == 2); * }); * * suite('String'); * * test('#length', function() { * ok('foo'.length == 3); * }); * * @param {Suite} suite Root suite. */ module.exports = function qUnitInterface(suite) { var suites = [suite]; suite.on('pre-require', function(context, file, mocha) { var common = require('./common')(suites, context, mocha); context.before = common.before; context.after = common.after; context.beforeEach = common.beforeEach; context.afterEach = common.afterEach; context.run = mocha.options.delay && common.runWithSuite(suite); /** * Describe a "suite" with the given `title`. */ context.suite = function(title) { if (suites.length > 1) { suites.shift(); } return common.suite.create({ title: title, file: file, fn: false }); }; /** * Exclusive Suite. */ context.suite.only = function(title) { if (suites.length > 1) { suites.shift(); } return common.suite.only({ title: title, file: file, fn: false }); }; /** * Describe a specification or test-case * with the given `title` and callback `fn` * acting as a thunk. */ context.test = function(title, fn) { var test = new Test(title, fn); test.file = file; suites[0].addTest(test); return test; }; /** * Exclusive test-case. */ context.test.only = function(title, fn) { return common.test.only(mocha, context.test(title, fn)); }; context.test.skip = common.test.skip; context.test.retries = common.test.retries; }); }; },{"../test":35,"./common":8}],12:[function(require,module,exports){ 'use strict'; var Test = require('../test'); /** * TDD-style interface: * * suite('Array', function() { * suite('#indexOf()', function() { * suiteSetup(function() { * * }); * * test('should return -1 when not present', function() { * * }); * * test('should return the index when present', function() { * * }); * * suiteTeardown(function() { * * }); * }); * }); * * @param {Suite} suite Root suite. */ module.exports = function(suite) { var suites = [suite]; suite.on('pre-require', function(context, file, mocha) { var common = require('./common')(suites, context, mocha); context.setup = common.beforeEach; context.teardown = common.afterEach; context.suiteSetup = common.before; context.suiteTeardown = common.after; context.run = mocha.options.delay && common.runWithSuite(suite); /** * Describe a "suite" with the given `title` and callback `fn` containing * nested suites and/or tests. */ context.suite = function(title, fn) { return common.suite.create({ title: title, file: file, fn: fn }); }; /** * Pending suite. */ context.suite.skip = function(title, fn) { return common.suite.skip({ title: title, file: file, fn: fn }); }; /** * Exclusive test-case. */ context.suite.only = function(title, fn) { return common.suite.only({ title: title, file: file, fn: fn }); }; /** * Describe a specification or test-case with the given `title` and * callback `fn` acting as a thunk. */ context.test = function(title, fn) { var suite = suites[0]; if (suite.isPending()) { fn = null; } var test = new Test(title, fn); test.file = file; suite.addTest(test); return test; }; /** * Exclusive test-case. */ context.test.only = function(title, fn) { return common.test.only(mocha, context.test(title, fn)); }; context.test.skip = common.test.skip; context.test.retries = common.test.retries; }); }; },{"../test":35,"./common":8}],13:[function(require,module,exports){ (function (process,global,__dirname){ 'use strict'; /*! * mocha * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca> * MIT Licensed */ var escapeRe = require('escape-string-regexp'); var path = require('path'); var reporters = require('./reporters'); var utils = require('./utils'); exports = module.exports = Mocha; /** * To require local UIs and reporters when running in node. */ if (!process.browser) { var cwd = process.cwd(); module.paths.push(cwd, path.join(cwd, 'node_modules')); } /** * Expose internals. */ /** * @public * @class utils * @memberof Mocha */ exports.utils = utils; exports.interfaces = require('./interfaces'); /** * * @memberof Mocha * @public */ exports.reporters = reporters; exports.Runnable = require('./runnable'); exports.Context = require('./context'); /** * * @memberof Mocha */ exports.Runner = require('./runner'); exports.Suite = require('./suite'); exports.Hook = require('./hook'); exports.Test = require('./test'); /** * Return image `name` path. * * @private * @param {string} name * @return {string} */ function image(name) { return path.join(__dirname, '..', 'assets', 'growl', name + '.png'); } /** * Set up mocha with `options`. * * Options: * * - `ui` name "bdd", "tdd", "exports" etc * - `reporter` reporter instance, defaults to `mocha.reporters.spec` * - `globals` array of accepted globals * - `timeout` timeout in milliseconds * - `retries` number of times to retry failed tests * - `bail` bail on the first test failure * - `slow` milliseconds to wait before considering a test slow * - `ignoreLeaks` ignore global leaks * - `fullTrace` display the full stack-trace on failing * - `grep` string or regexp to filter tests with * * @class Mocha * @param {Object} options */ function Mocha(options) { options = options || {}; this.files = []; this.options = options; if (options.grep) { this.grep(new RegExp(options.grep)); } if (options.fgrep) { this.fgrep(options.fgrep); } this.suite = new exports.Suite('', new exports.Context()); this.ui(options.ui); this.bail(options.bail); this.reporter(options.reporter, options.reporterOptions); if (typeof options.timeout !== 'undefined' && options.timeout !== null) { this.timeout(options.timeout); } if (typeof options.retries !== 'undefined' && options.retries !== null) { this.retries(options.retries); } this.useColors(options.useColors); if (options.enableTimeouts !== null) { this.enableTimeouts(options.enableTimeouts); } if (options.slow) { this.slow(options.slow); } } /** * Enable or disable bailing on the first failure. * * @public * @api public * @param {boolean} [bail] */ Mocha.prototype.bail = function(bail) { if (!arguments.length) { bail = true; } this.suite.bail(bail); return this; }; /** * Add test `file`. * * @public * @api public * @param {string} file */ Mocha.prototype.addFile = function(file) { this.files.push(file); return this; }; /** * Set reporter to `reporter`, defaults to "spec". * * @public * @param {String|Function} reporter name or constructor * @param {Object} reporterOptions optional options * @api public * @param {string|Function} reporter name or constructor * @param {Object} reporterOptions optional options */ Mocha.prototype.reporter = function(reporter, reporterOptions) { if (typeof reporter === 'function') { this._reporter = reporter; } else { reporter = reporter || 'spec'; var _reporter; // Try to load a built-in reporter. if (reporters[reporter]) { _reporter = reporters[reporter]; } // Try to load reporters from process.cwd() and node_modules if (!_reporter) { try { _reporter = require(reporter); } catch (err) { if (err.message.indexOf('Cannot find module') !== -1) { // Try to load reporters from a path (absolute or relative) try { _reporter = require(path.resolve(process.cwd(), reporter)); } catch (_err) { err.message.indexOf('Cannot find module') !== -1 ? console.warn('"' + reporter + '" reporter not found') : console.warn( '"' + reporter + '" reporter blew up with error:\n' + err.stack ); } } else { console.warn( '"' + reporter + '" reporter blew up with error:\n' + err.stack ); } } } if (!_reporter && reporter === 'teamcity') { console.warn( 'The Teamcity reporter was moved to a package named ' + 'mocha-teamcity-reporter ' + '(https://npmjs.org/package/mocha-teamcity-reporter).' ); } if (!_reporter) { throw new Error('invalid reporter "' + reporter + '"'); } this._reporter = _reporter; } this.options.reporterOptions = reporterOptions; return this; }; /** * Set test UI `name`, defaults to "bdd". * @public * @api public * @param {string} bdd */ Mocha.prototype.ui = function(name) { name = name || 'bdd'; this._ui = exports.interfaces[name]; if (!this._ui) { try { this._ui = require(name); } catch (err) { throw new Error('invalid interface "' + name + '"'); } } this._ui = this._ui(this.suite); this.suite.on('pre-require', function(context) { exports.afterEach = context.afterEach || context.teardown; exports.after = context.after || context.suiteTeardown; exports.beforeEach = context.beforeEach || context.setup; exports.before = context.before || context.suiteSetup; exports.describe = context.describe || context.suite; exports.it = context.it || context.test; exports.xit = context.xit || context.test.skip; exports.setup = context.setup || context.beforeEach; exports.suiteSetup = context.suiteSetup || context.before; exports.suiteTeardown = context.suiteTeardown || context.after; exports.suite = context.suite || context.describe; exports.teardown = context.teardown || context.afterEach; exports.test = context.test || context.it; exports.run = context.run; }); return this; }; /** * Load registered files. * * @api private */ Mocha.prototype.loadFiles = function(fn) { var self = this; var suite = this.suite; this.files.forEach(function(file) { file = path.resolve(file); suite.emit('pre-require', global, file, self); suite.emit('require', require(file), file, self); suite.emit('post-require', global, file, self); }); fn && fn(); }; /** * Enable growl support. * * @api private */ Mocha.prototype._growl = function(runner, reporter) { var notify = require('growl'); runner.on('end', function() { var stats = reporter.stats; if (stats.failures) { var msg = stats.failures + ' of ' + runner.total + ' tests failed'; notify(msg, {name: 'mocha', title: 'Failed', image: image('error')}); } else { notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { name: 'mocha', title: 'Passed', image: image('ok') }); } }); }; /** * Escape string and add it to grep as a regexp. * * @public * @api public * @param str * @returns {Mocha} */ Mocha.prototype.fgrep = function(str) { return this.grep(new RegExp(escapeRe(str))); }; /** * Add regexp to grep, if `re` is a string it is escaped. * * @public * @param {RegExp|String} re * @return {Mocha} * @api public * @param {RegExp|string} re * @return {Mocha} */ Mocha.prototype.grep = function(re) { if (utils.isString(re)) { // extract args if it's regex-like, i.e: [string, pattern, flag] var arg = re.match(/^\/(.*)\/(g|i|)$|.*/); this.options.grep = new RegExp(arg[1] || arg[0], arg[2]); } else { this.options.grep = re; } return this; }; /** * Invert `.grep()` matches. * * @public * @return {Mocha} * @api public */ Mocha.prototype.invert = function() { this.options.invert = true; return this; }; /** * Ignore global leaks. * * @public * @param {Boolean} ignore * @return {Mocha} * @api public * @param {boolean} ignore * @return {Mocha} */ Mocha.prototype.ignoreLeaks = function(ignore) { this.options.ignoreLeaks = Boolean(ignore); return this; }; /** * Enable global leak checking. * * @return {Mocha} * @api public * @public */ Mocha.prototype.checkLeaks = function() { this.options.ignoreLeaks = false; return this; }; /** * Display long stack-trace on failing * * @return {Mocha} * @api public * @public */ Mocha.prototype.fullTrace = function() { this.options.fullStackTrace = true; return this; }; /** * Enable growl support. * * @return {Mocha} * @api public * @public */ Mocha.prototype.growl = function() { this.options.growl = true; return this; }; /** * Ignore `globals` array or string. * * @param {Array|String} globals * @return {Mocha} * @api public * @public * @param {Array|string} globals * @return {Mocha} */ Mocha.prototype.globals = function(globals) { this.options.globals = (this.options.globals || []).concat(globals); return this; }; /** * Emit color output. * * @param {Boolean} colors * @return {Mocha} * @api public * @public * @param {boolean} colors * @return {Mocha} */ Mocha.prototype.useColors = function(colors) { if (colors !== undefined) { this.options.useColors = colors; } return this; }; /** * Use inline diffs rather than +/-. * * @param {Boolean} inlineDiffs * @return {Mocha} * @api public * @public * @param {boolean} inlineDiffs * @return {Mocha} */ Mocha.prototype.useInlineDiffs = function(inlineDiffs) { this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs; return this; }; /** * Do not show diffs at all. * * @param {Boolean} hideDiff * @return {Mocha} * @api public * @public * @param {boolean} hideDiff * @return {Mocha} */ Mocha.prototype.hideDiff = function(hideDiff) { this.options.hideDiff = hideDiff !== undefined && hideDiff; return this; }; /** * Set the timeout in milliseconds. * * @param {Number} timeout * @return {Mocha} * @api public * @public * @param {number} timeout * @return {Mocha} */ Mocha.prototype.timeout = function(timeout) { this.suite.timeout(timeout); return this; }; /** * Set the number of times to retry failed tests. * * @param {Number} retry times * @return {Mocha} * @api public * @public */ Mocha.prototype.retries = function(n) { this.suite.retries(n); return this; }; /** * Set slowness threshold in milliseconds. * * @param {Number} slow * @return {Mocha} * @api public * @public * @param {number} slow * @return {Mocha} */ Mocha.prototype.slow = function(slow) { this.suite.slow(slow); return this; }; /** * Enable timeouts. * * @param {Boolean} enabled * @return {Mocha} * @api public * @public * @param {boolean} enabled * @return {Mocha} */ Mocha.prototype.enableTimeouts = function(enabled) { this.suite.enableTimeouts( arguments.length && enabled !== undefined ? enabled : true ); return this; }; /** * Makes all tests async (accepting a callback) * * @return {Mocha} * @api public * @public */ Mocha.prototype.asyncOnly = function() { this.options.asyncOnly = true; return this; }; /** * Disable syntax highlighting (in browser). * * @api public * @public */ Mocha.prototype.noHighlighting = function() { this.options.noHighlighting = true; return this; }; /** * Enable uncaught errors to propagate (in browser). * * @return {Mocha} * @api public * @public */ Mocha.prototype.allowUncaught = function() { this.options.allowUncaught = true; return this; }; /** * Delay root suite execution. * @returns {Mocha} */ Mocha.prototype.delay = function delay() { this.options.delay = true; return this; }; /** * Tests marked only fail the suite * @returns {Mocha} */ Mocha.prototype.forbidOnly = function() { this.options.forbidOnly = true; return this; }; /** * Pending tests and tests marked skip fail the suite * @returns {Mocha} */ Mocha.prototype.forbidPending = function() { this.options.forbidPending = true; return this; }; /** * Run tests and invoke `fn()` when complete. * * Note that `loadFiles` relies on Node's `require` to execute * the test interface functions and will be subject to the * cache - if the files are already in the `require` cache, * they will effectively be skipped. Therefore, to run tests * multiple times or to run tests in files that are already * in the `require` cache, make sure to clear them from the * cache first in whichever manner best suits your needs. * * @api public * @public * @param {Function} fn * @return {Runner} */ Mocha.prototype.run = function(fn) { if (this.files.length) { this.loadFiles(); } var suite = this.suite; var options = this.options; options.files = this.files; var runner = new exports.Runner(suite, options.delay); var reporter = new this._reporter(runner, options); runner.ignoreLeaks = options.ignoreLeaks !== false; runner.fullStackTrace = options.fullStackTrace; runner.asyncOnly = options.asyncOnly; runner.allowUncaught = options.allowUncaught; runner.forbidOnly = options.forbidOnly; runner.forbidPending = options.forbidPending; if (options.grep) { runner.grep(options.grep, options.invert); } if (options.globals) { runner.globals(options.globals); } if (options.growl) { this._growl(runner, reporter); } if (options.useColors !== undefined) { exports.reporters.Base.useColors = options.useColors; } exports.reporters.Base.inlineDiffs = options.useInlineDiffs; exports.reporters.Base.hideDiff = options.hideDiff; function done(failures) { if (reporter.done) { reporter.done(failures, fn); } else { fn && fn(failures); } } return runner.run(done); }; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/lib") },{"./context":5,"./hook":6,"./interfaces":10,"./reporters":20,"./runnable":32,"./runner":33,"./suite":34,"./test":35,"./utils":36,"_process":56,"escape-string-regexp":46,"growl":2,"path":40}],14:[function(require,module,exports){ 'use strict'; /** * @module milliseconds */ /** * Helpers. */ var s = 1000; var m = s * 60; var h = m * 60; var d = h * 24; var y = d * 365.25; /** * Parse or format the given `val`. * * @memberof Mocha * @public * @api public * @param {string|number} val * @return {string|number} */ module.exports = function(val) { if (typeof val === 'string') { return parse(val); } return format(val); }; /** * Parse the given `str` and return milliseconds. * * @api private * @param {string} str * @return {number} */ function parse(str) { var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec( str ); if (!match) { return; } var n = parseFloat(match[1]); var type = (match[2] || 'ms').toLowerCase(); switch (type) { case 'years': case 'year': case 'y': return n * y; case 'days': case 'day': case 'd': return n * d; case 'hours': case 'hour': case 'h': return n * h; case 'minutes': case 'minute': case 'm': return n * m; case 'seconds': case 'second': case 's': return n * s; case 'ms': return n; default: // No default case } } /** * Format for `ms`. * * @api private * @param {number} ms * @return {string} */ function format(ms) { if (ms >= d) { return Math.round(ms / d) + 'd'; } if (ms >= h) { return Math.round(ms / h) + 'h'; } if (ms >= m) { return Math.round(ms / m) + 'm'; } if (ms >= s) { return Math.round(ms / s) + 's'; } return ms + 'ms'; } },{}],15:[function(require,module,exports){ 'use strict'; module.exports = Pending; /** * Initialize a new `Pending` error with the given message. * * @param {string} message */ function Pending(message) { this.message = message; } },{}],16:[function(require,module,exports){ (function (process,global){ 'use strict'; /** * @module Base */ /** * Module dependencies. */ var tty = require('tty'); var diff = require('diff'); var ms = require('../ms'); var utils = require('../utils'); var supportsColor = process.browser ? null : require('supports-color'); /** * Expose `Base`. */ exports = module.exports = Base; /** * Save timer references to avoid Sinon interfering. * See: https://github.com/mochajs/mocha/issues/237 */ /* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; var setTimeout = global.setTimeout; var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; var clearInterval = global.clearInterval; /* eslint-enable no-unused-vars, no-native-reassign */ /** * Check if both stdio streams are associated with a tty. */ var isatty = tty.isatty(1) && tty.isatty(2); /** * Enable coloring by default, except in the browser interface. */ exports.useColors = !process.browser && (supportsColor.stdout || process.env.MOCHA_COLORS !== undefined); /** * Inline diffs instead of +/- */ exports.inlineDiffs = false; /** * Default color map. */ exports.colors = { pass: 90, fail: 31, 'bright pass': 92, 'bright fail': 91, 'bright yellow': 93, pending: 36, suite: 0, 'error title': 0, 'error message': 31, 'error stack': 90, checkmark: 32, fast: 90, medium: 33, slow: 31, green: 32, light: 90, 'diff gutter': 90, 'diff added': 32, 'diff removed': 31 }; /** * Default symbol map. */ exports.symbols = { ok: '✓', err: '✖', dot: '․', comma: ',', bang: '!' }; // With node.js on Windows: use symbols available in terminal default fonts if (process.platform === 'win32') { exports.symbols.ok = '\u221A'; exports.symbols.err = '\u00D7'; exports.symbols.dot = '.'; } /** * Color `str` with the given `type`, * allowing colors to be disabled, * as well as user-defined color * schemes. * * @param {string} type * @param {string} str * @return {string} * @api private */ var color = (exports.color = function(type, str) { if (!exports.useColors) { return String(str); } return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; }); /** * Expose term window size, with some defaults for when stderr is not a tty. */ exports.window = { width: 75 }; if (isatty) { exports.window.width = process.stdout.getWindowSize ? process.stdout.getWindowSize(1)[0] : tty.getWindowSize()[1]; } /** * Expose some basic cursor interactions that are common among reporters. */ exports.cursor = { hide: function() { isatty && process.stdout.write('\u001b[?25l'); }, show: function() { isatty && process.stdout.write('\u001b[?25h'); }, deleteLine: function() { isatty && process.stdout.write('\u001b[2K'); }, beginningOfLine: function() { isatty && process.stdout.write('\u001b[0G'); }, CR: function() { if (isatty) { exports.cursor.deleteLine(); exports.cursor.beginningOfLine(); } else { process.stdout.write('\r'); } } }; function showDiff(err) { return ( err && err.showDiff !== false && sameType(err.actual, err.expected) && err.expected !== undefined ); } function stringifyDiffObjs(err) { if (!utils.isString(err.actual) || !utils.isString(err.expected)) { err.actual = utils.stringify(err.actual); err.expected = utils.stringify(err.expected); } } /** * Returns a diff between 2 strings with coloured ANSI output. * * The diff will be either inline or unified dependant on the value * of `Base.inlineDiff`. * * @param {string} actual * @param {string} expected * @return {string} Diff */ var generateDiff = (exports.generateDiff = function(actual, expected) { return exports.inlineDiffs ? inlineDiff(actual, expected) : unifiedDiff(actual, expected); }); /** * Output the given `failures` as a list. * * @public * @memberof Mocha.reporters.Base * @variation 1 * @param {Array} failures * @api public */ exports.list = function(failures) { console.log(); failures.forEach(function(test, i) { // format var fmt = color('error title', ' %s) %s:\n') + color('error message', ' %s') + color('error stack', '\n%s\n'); // msg var msg; var err = test.err; var message; if (err.message && typeof err.message.toString === 'function') { message = err.message + ''; } else if (typeof err.inspect === 'function') { message = err.inspect() + ''; } else { message = ''; } var stack = err.stack || message; var index = message ? stack.indexOf(message) : -1; if (index === -1) { msg = message; } else { index += message.length; msg = stack.slice(0, index); // remove msg from stack stack = stack.slice(index + 1); } // uncaught if (err.uncaught) { msg = 'Uncaught ' + msg; } // explicitly show diff if (!exports.hideDiff && showDiff(err)) { stringifyDiffObjs(err); fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); var match = message.match(/^([^:]+): expected/); msg = '\n ' + color('error message', match ? match[1] : msg); msg += generateDiff(err.actual, err.expected); } // indent stack trace stack = stack.replace(/^/gm, ' '); // indented test title var testTitle = ''; test.titlePath().forEach(function(str, index) { if (index !== 0) { testTitle += '\n '; } for (var i = 0; i < index; i++) { testTitle += ' '; } testTitle += str; }); console.log(fmt, i + 1, testTitle, msg, stack); }); }; /** * Initialize a new `Base` reporter. * * All other reporters generally * inherit from this reporter, providing * stats such as test duration, number * of tests passed / failed etc. * * @memberof Mocha.reporters * @public * @class * @param {Runner} runner * @api public */ function Base(runner) { var stats = (this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }); var failures = (this.failures = []); if (!runner) { return; } this.runner = runner; runner.stats = stats; runner.on('start', function() { stats.start = new Date(); }); runner.on('suite', function(suite) { stats.suites = stats.suites || 0; suite.root || stats.suites++; }); runner.on('test end', function() { stats.tests = stats.tests || 0; stats.tests++; }); runner.on('pass', function(test) { stats.passes = stats.passes || 0; if (test.duration > test.slow()) { test.speed = 'slow'; } else if (test.duration > test.slow() / 2) { test.speed = 'medium'; } else { test.speed = 'fast'; } stats.passes++; }); runner.on('fail', function(test, err) { stats.failures = stats.failures || 0; stats.failures++; if (showDiff(err)) { stringifyDiffObjs(err); } test.err = err; failures.push(test); }); runner.once('end', function() { stats.end = new Date(); stats.duration = stats.end - stats.start; }); runner.on('pending', function() { stats.pending++; }); } /** * Output common epilogue used by many of * the bundled reporters. * * @memberof Mocha.reporters.Base * @public * @api public */ Base.prototype.epilogue = function() { var stats = this.stats; var fmt; console.log(); // passes fmt = color('bright pass', ' ') + color('green', ' %d passing') + color('light', ' (%s)'); console.log(fmt, stats.passes || 0, ms(stats.duration)); // pending if (stats.pending) { fmt = color('pending', ' ') + color('pending', ' %d pending'); console.log(fmt, stats.pending); } // failures if (stats.failures) { fmt = color('fail', ' %d failing'); console.log(fmt, stats.failures); Base.list(this.failures); console.log(); } console.log(); }; /** * Pad the given `str` to `len`. * * @api private * @param {string} str * @param {string} len * @return {string} */ function pad(str, len) { str = String(str); return Array(len - str.length + 1).join(' ') + str; } /** * Returns an inline diff between 2 strings with coloured ANSI output. * * @api private * @param {String} actual * @param {String} expected * @return {string} Diff */ function inlineDiff(actual, expected) { var msg = errorDiff(actual, expected); // linenos var lines = msg.split('\n'); if (lines.length > 4) { var width = String(lines.length).length; msg = lines .map(function(str, i) { return pad(++i, width) + ' |' + ' ' + str; }) .join('\n'); } // legend msg = '\n' + color('diff removed', 'actual') + ' ' + color('diff added', 'expected') + '\n\n' + msg + '\n'; // indent msg = msg.replace(/^/gm, ' '); return msg; } /** * Returns a unified diff between two strings with coloured ANSI output. * * @api private * @param {String} actual * @param {String} expected * @return {string} The diff. */ function unifiedDiff(actual, expected) { var indent = ' '; function cleanUp(line) { if (line[0] === '+') { return indent + colorLines('diff added', line); } if (line[0] === '-') { return indent + colorLines('diff removed', line); } if (line.match(/@@/)) { return '--'; } if (line.match(/\\ No newline/)) { return null; } return indent + line; } function notBlank(line) { return typeof line !== 'undefined' && line !== null; } var msg = diff.createPatch('string', actual, expected); var lines = msg.split('\n').splice(5); return ( '\n ' + colorLines('diff added', '+ expected') + ' ' + colorLines('diff removed', '- actual') + '\n\n' + lines .map(cleanUp) .filter(notBlank) .join('\n') ); } /** * Return a character diff for `err`. * * @api private * @param {String} actual * @param {String} expected * @return {string} the diff */ function errorDiff(actual, expected) { return diff .diffWordsWithSpace(actual, expected) .map(function(str) { if (str.added) { return colorLines('diff added', str.value); } if (str.removed) { return colorLines('diff removed', str.value); } return str.value; }) .join(''); } /** * Color lines for `str`, using the color `name`. * * @api private * @param {string} name * @param {stri