123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613 |
- '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);
- };
|