| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255 |
- 'use strict';
- /*!
- * mocha
- * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
- * MIT Licensed
- */
- var escapeRe = require('escape-string-regexp');
- var path = require('node:path');
- var builtinReporters = require('./reporters');
- var utils = require('./utils');
- var mocharc = require('./mocharc.json');
- var Suite = require('./suite');
- var esmUtils = require('./nodejs/esm-utils');
- var createStatsCollector = require('./stats-collector');
- const {
- createInvalidReporterError,
- createInvalidInterfaceError,
- createMochaInstanceAlreadyDisposedError,
- createMochaInstanceAlreadyRunningError,
- createUnsupportedError
- } = require('./errors');
- const {EVENT_FILE_PRE_REQUIRE, EVENT_FILE_POST_REQUIRE, EVENT_FILE_REQUIRE} =
- Suite.constants;
- var debug = require('debug')('mocha:mocha');
- /**
- * @typedef {import('./types.d.ts').DoneCB} DoneCB
- * @typedef {import('./types.d.ts').MochaGlobalFixture} MochaGlobalFixture
- * @typedef {import('./types.d.ts').MochaOptions} MochaOptions
- * @typedef {import('./types.d.ts').MochaRootHookObject} MochaRootHookObject
- * @typedef {import('./types.d.ts').Reporter} Reporter
- */
- exports = module.exports = Mocha;
- /**
- * A Mocha instance is a finite state machine.
- * These are the states it can be in.
- * @private
- */
- var mochaStates = utils.defineConstants({
- /**
- * Initial state of the mocha instance
- * @private
- */
- INIT: 'init',
- /**
- * Mocha instance is running tests
- * @private
- */
- RUNNING: 'running',
- /**
- * Mocha instance is done running tests and references to test functions and hooks are cleaned.
- * You can reset this state by unloading the test files.
- * @private
- */
- REFERENCES_CLEANED: 'referencesCleaned',
- /**
- * Mocha instance is disposed and can no longer be used.
- * @private
- */
- DISPOSED: 'disposed'
- });
- /**
- * To require local UIs and reporters when running in node.
- */
- if (!utils.isBrowser() && typeof module.paths !== 'undefined') {
- var cwd = utils.cwd();
- module.paths.push(cwd, path.join(cwd, 'node_modules'));
- }
- /**
- * Expose internals.
- * @private
- */
- exports.utils = utils;
- exports.interfaces = require('./interfaces');
- /**
- * @public
- * @memberof Mocha
- */
- exports.reporters = builtinReporters;
- exports.Runnable = require('./runnable');
- exports.Context = require('./context');
- /**
- *
- * @memberof Mocha
- */
- exports.Runner = require('./runner');
- exports.Suite = Suite;
- exports.Hook = require('./hook');
- exports.Test = require('./test');
- let currentContext;
- exports.afterEach = function (...args) {
- return (currentContext.afterEach || currentContext.teardown).apply(
- this,
- args
- );
- };
- exports.after = function (...args) {
- return (currentContext.after || currentContext.suiteTeardown).apply(
- this,
- args
- );
- };
- exports.beforeEach = function (...args) {
- return (currentContext.beforeEach || currentContext.setup).apply(this, args);
- };
- exports.before = function (...args) {
- return (currentContext.before || currentContext.suiteSetup).apply(this, args);
- };
- exports.describe = function (...args) {
- return (currentContext.describe || currentContext.suite).apply(this, args);
- };
- exports.describe.only = function (...args) {
- return (currentContext.describe || currentContext.suite).only.apply(
- this,
- args
- );
- };
- exports.describe.skip = function (...args) {
- return (currentContext.describe || currentContext.suite).skip.apply(
- this,
- args
- );
- };
- exports.it = function (...args) {
- return (currentContext.it || currentContext.test).apply(this, args);
- };
- exports.it.only = function (...args) {
- return (currentContext.it || currentContext.test).only.apply(this, args);
- };
- exports.it.skip = function (...args) {
- return (currentContext.it || currentContext.test).skip.apply(this, args);
- };
- exports.xdescribe = exports.describe.skip;
- exports.xit = exports.it.skip;
- exports.setup = exports.beforeEach;
- exports.suiteSetup = exports.before;
- exports.suiteTeardown = exports.after;
- exports.suite = exports.describe;
- exports.teardown = exports.afterEach;
- exports.test = exports.it;
- exports.run = function (...args) {
- return currentContext.run.apply(this, args);
- };
- /**
- * Constructs a new Mocha instance with `options`.
- *
- * @public
- * @class Mocha
- * @param {MochaOptions} [options] - Settings object.
- */
- function Mocha(options = {}) {
- options = {...mocharc, ...options};
- this.files = [];
- this.options = options;
- // root suite
- this.suite = new exports.Suite('', new exports.Context(), true);
- this._cleanReferencesAfterRun = true;
- this._state = mochaStates.INIT;
- this.grep(options.grep)
- .fgrep(options.fgrep)
- .ui(options.ui)
- .reporter(
- options.reporter,
- options['reporter-option'] ||
- options.reporterOption ||
- options.reporterOptions // for backwards compatibility
- )
- .slow(options.slow)
- .global(options.global);
- // this guard exists because Suite#timeout does not consider `undefined` to be valid input
- if (typeof options.timeout !== 'undefined') {
- this.timeout(options.timeout === false ? 0 : options.timeout);
- }
- if ('retries' in options) {
- this.retries(options.retries);
- }
- [
- 'allowUncaught',
- 'asyncOnly',
- 'bail',
- 'checkLeaks',
- 'color',
- 'delay',
- 'diff',
- 'dryRun',
- 'passOnFailingTestSuite',
- 'failZero',
- 'forbidOnly',
- 'forbidPending',
- 'fullTrace',
- 'inlineDiffs',
- 'invert'
- ].forEach(function (opt) {
- if (options[opt]) {
- this[opt]();
- }
- }, this);
- if (options.rootHooks) {
- this.rootHooks(options.rootHooks);
- }
- /**
- * The class which we'll instantiate in {@link Mocha#run}. Defaults to
- * {@link Runner} in serial mode; changes in parallel mode.
- * @memberof Mocha
- * @private
- */
- this._runnerClass = exports.Runner;
- /**
- * Whether or not to call {@link Mocha#loadFiles} implicitly when calling
- * {@link Mocha#run}. If this is `true`, then it's up to the consumer to call
- * {@link Mocha#loadFiles} _or_ {@link Mocha#loadFilesAsync}.
- * @private
- * @memberof Mocha
- */
- this._lazyLoadFiles = false;
- /**
- * It's useful for a Mocha instance to know if it's running in a worker process.
- * We could derive this via other means, but it's helpful to have a flag to refer to.
- * @memberof Mocha
- * @private
- */
- this.isWorker = Boolean(options.isWorker);
- this.globalSetup(options.globalSetup)
- .globalTeardown(options.globalTeardown)
- .enableGlobalSetup(options.enableGlobalSetup)
- .enableGlobalTeardown(options.enableGlobalTeardown);
- if (
- options.parallel &&
- (typeof options.jobs === 'undefined' || options.jobs > 1)
- ) {
- debug('attempting to enable parallel mode');
- this.parallelMode(true);
- }
- }
- /**
- * Enables or disables bailing on the first failure.
- *
- * @public
- * @see [CLI option](../#-bail-b)
- * @param {boolean} [bail=true] - Whether to bail on first error.
- * @returns {Mocha} this
- * @chainable
- */
- Mocha.prototype.bail = function (bail) {
- this.suite.bail(bail !== false);
- return this;
- };
- /**
- * @summary
- * Adds `file` to be loaded for execution.
- *
- * @description
- * Useful for generic setup code that must be included within test suite.
- *
- * @public
- * @see [CLI option](../#-file-filedirectoryglob)
- * @param {string} file - Pathname of file to be loaded.
- * @returns {Mocha} this
- * @chainable
- */
- Mocha.prototype.addFile = function (file) {
- this.files.push(file);
- return this;
- };
- /**
- * Sets reporter to `reporter`, defaults to "spec".
- *
- * @public
- * @see [CLI option](../#-reporter-name-r-name)
- * @see [Reporters](../#reporters)
- * @param {String|Reporter} reporterName - Reporter name or constructor.
- * @param {Object} [reporterOptions] - Options used to configure the reporter.
- * @returns {Mocha} this
- * @chainable
- * @throws {Error} if requested reporter cannot be loaded
- * @example
- *
- * // Use XUnit reporter and direct its output to file
- * mocha.reporter('xunit', { output: '/path/to/testspec.xunit.xml' });
- */
- Mocha.prototype.reporter = function (reporterName, reporterOptions) {
- if (typeof reporterName === 'function') {
- this._reporter = reporterName;
- } else {
- reporterName = reporterName || 'spec';
- var reporter;
- // Try to load a built-in reporter.
- if (builtinReporters[reporterName]) {
- reporter = builtinReporters[reporterName];
- }
- // Try to load reporters from process.cwd() and node_modules
- if (!reporter) {
- let foundReporter;
- try {
- foundReporter = require.resolve(reporterName);
- reporter = require(foundReporter);
- } catch (err) {
- if (foundReporter) {
- throw createInvalidReporterError(err.message, foundReporter);
- }
- // Try to load reporters from a cwd-relative path
- try {
- reporter = require(path.resolve(reporterName));
- } catch (err) {
- throw createInvalidReporterError(err.message, reporterName);
- }
- }
- }
- this._reporter = reporter;
- }
- this.options.reporterOption = reporterOptions;
- // alias option name is used in built-in reporters xunit/tap/progress
- this.options.reporterOptions = reporterOptions;
- return this;
- };
- /**
- * Sets test UI `name`, defaults to "bdd".
- *
- * @public
- * @see [CLI option](../#-ui-name-u-name)
- * @see [Interface DSLs](../#interfaces)
- * @param {string|Function} [ui=bdd] - Interface name or class.
- * @returns {Mocha} this
- * @chainable
- * @throws {Error} if requested interface cannot be loaded
- */
- Mocha.prototype.ui = function (ui) {
- var bindInterface;
- if (typeof ui === 'function') {
- bindInterface = ui;
- } else {
- ui = ui || 'bdd';
- bindInterface = exports.interfaces[ui];
- if (!bindInterface) {
- try {
- bindInterface = require(ui);
- } catch (err) {
- throw createInvalidInterfaceError(`invalid interface '${ui}'`, ui);
- }
- }
- }
- bindInterface(this.suite);
- this.suite.on(EVENT_FILE_PRE_REQUIRE, function (context) {
- currentContext = context;
- });
- return this;
- };
- /**
- * Loads `files` prior to execution. Does not support ES Modules.
- *
- * @description
- * The implementation relies on Node's `require` to execute
- * the test interface functions and will be subject to its cache.
- * Supports only CommonJS modules. To load ES modules, use Mocha#loadFilesAsync.
- *
- * @private
- * @see {@link Mocha#addFile}
- * @see {@link Mocha#run}
- * @see {@link Mocha#unloadFiles}
- * @see {@link Mocha#loadFilesAsync}
- * @param {Function} [fn] - Callback invoked upon completion.
- */
- Mocha.prototype.loadFiles = function (fn) {
- var self = this;
- var suite = this.suite;
- this.files.forEach(function (file) {
- file = path.resolve(file);
- suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
- suite.emit(EVENT_FILE_REQUIRE, require(file), file, self);
- suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
- });
- fn && fn();
- };
- /**
- * Loads `files` prior to execution. Supports Node ES Modules.
- *
- * @description
- * The implementation relies on Node's `require` and `import` to execute
- * the test interface functions and will be subject to its cache.
- * Supports both CJS and ESM modules.
- *
- * @public
- * @see {@link Mocha#addFile}
- * @see {@link Mocha#run}
- * @see {@link Mocha#unloadFiles}
- * @param {Object} [options] - Settings object.
- * @param {Function} [options.esmDecorator] - Function invoked on esm module name right before importing it. By default will passthrough as is.
- * @returns {Promise}
- * @example
- *
- * // loads ESM (and CJS) test files asynchronously, then runs root suite
- * mocha.loadFilesAsync()
- * .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0))
- * .catch(() => process.exitCode = 1);
- */
- Mocha.prototype.loadFilesAsync = function ({esmDecorator} = {}) {
- var self = this;
- var suite = this.suite;
- this.lazyLoadFiles(true);
- return esmUtils.loadFilesAsync(
- this.files,
- function (file) {
- suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self);
- },
- function (file, resultModule) {
- suite.emit(EVENT_FILE_REQUIRE, resultModule, file, self);
- suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self);
- },
- esmDecorator
- );
- };
- /**
- * Removes a previously loaded file from Node's `require` cache.
- *
- * @private
- * @static
- * @see {@link Mocha#unloadFiles}
- * @param {string} file - Pathname of file to be unloaded.
- */
- Mocha.unloadFile = function (file) {
- if (utils.isBrowser()) {
- throw createUnsupportedError(
- 'unloadFile() is only supported in a Node.js environment'
- );
- }
- return require('./nodejs/file-unloader').unloadFile(file);
- };
- /**
- * Unloads `files` from Node's `require` cache.
- *
- * @description
- * This allows required files to be "freshly" reloaded, providing the ability
- * to reuse a Mocha instance programmatically.
- * Note: does not clear ESM module files from the cache
- *
- * <strong>Intended for consumers — not used internally</strong>
- *
- * @public
- * @see {@link Mocha#run}
- * @returns {Mocha} this
- * @chainable
- */
- Mocha.prototype.unloadFiles = function () {
- if (this._state === mochaStates.DISPOSED) {
- throw createMochaInstanceAlreadyDisposedError(
- 'Mocha instance is already disposed, it cannot be used again.',
- this._cleanReferencesAfterRun,
- this
- );
- }
- this.files.forEach(function (file) {
- Mocha.unloadFile(file);
- });
- this._state = mochaStates.INIT;
- return this;
- };
- /**
- * Sets `grep` filter after escaping RegExp special characters.
- *
- * @public
- * @see {@link Mocha#grep}
- * @param {string} str - Value to be converted to a regexp.
- * @returns {Mocha} this
- * @chainable
- * @example
- *
- * // Select tests whose full title begins with `"foo"` followed by a period
- * mocha.fgrep('foo.');
- */
- Mocha.prototype.fgrep = function (str) {
- if (!str) {
- return this;
- }
- return this.grep(new RegExp(escapeRe(str)));
- };
- /**
- * @summary
- * Sets `grep` filter used to select specific tests for execution.
- *
- * @description
- * If `re` is a regexp-like string, it will be converted to regexp.
- * The regexp is tested against the full title of each test (i.e., the
- * name of the test preceded by titles of each its ancestral suites).
- * As such, using an <em>exact-match</em> fixed pattern against the
- * test name itself will not yield any matches.
- * <br>
- * <strong>Previous filter value will be overwritten on each call!</strong>
- *
- * @public
- * @see [CLI option](../#-grep-regexp-g-regexp)
- * @see {@link Mocha#fgrep}
- * @see {@link Mocha#invert}
- * @param {RegExp|String} re - Regular expression used to select tests.
- * @return {Mocha} this
- * @chainable
- * @example
- *
- * // Select tests whose full title contains `"match"`, ignoring case
- * mocha.grep(/match/i);
- * @example
- *
- * // Same as above but with regexp-like string argument
- * mocha.grep('/match/i');
- * @example
- *
- * // ## Anti-example
- * // Given embedded test `it('only-this-test')`...
- * mocha.grep('/^only-this-test$/'); // NO! Use `.only()` to do this!
- */
- 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(/^\/(.*)\/([gimy]{0,4})$|.*/);
- this.options.grep = new RegExp(arg[1] || arg[0], arg[2]);
- } else {
- this.options.grep = re;
- }
- return this;
- };
- /**
- * Inverts `grep` matches.
- *
- * @public
- * @see {@link Mocha#grep}
- * @return {Mocha} this
- * @chainable
- * @example
- *
- * // Select tests whose full title does *not* contain `"match"`, ignoring case
- * mocha.grep(/match/i).invert();
- */
- Mocha.prototype.invert = function () {
- this.options.invert = true;
- return this;
- };
- /**
- * Enables or disables checking for global variables leaked while running tests.
- *
- * @public
- * @see [CLI option](../#-check-leaks)
- * @param {boolean} [checkLeaks=true] - Whether to check for global variable leaks.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.checkLeaks = function (checkLeaks) {
- this.options.checkLeaks = checkLeaks !== false;
- return this;
- };
- /**
- * Enables or disables whether or not to dispose after each test run.
- * Disable this to ensure you can run the test suite multiple times.
- * If disabled, be sure to dispose mocha when you're done to prevent memory leaks.
- * @public
- * @see {@link Mocha#dispose}
- * @param {boolean} cleanReferencesAfterRun
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.cleanReferencesAfterRun = function (cleanReferencesAfterRun) {
- this._cleanReferencesAfterRun = cleanReferencesAfterRun !== false;
- return this;
- };
- /**
- * Manually dispose this mocha instance. Mark this instance as `disposed` and unable to run more tests.
- * It also removes function references to tests functions and hooks, so variables trapped in closures can be cleaned by the garbage collector.
- * @public
- */
- Mocha.prototype.dispose = function () {
- if (this._state === mochaStates.RUNNING) {
- throw createMochaInstanceAlreadyRunningError(
- 'Cannot dispose while the mocha instance is still running tests.'
- );
- }
- this.unloadFiles();
- this._previousRunner && this._previousRunner.dispose();
- this.suite.dispose();
- this._state = mochaStates.DISPOSED;
- };
- /**
- * Displays full stack trace upon test failure.
- *
- * @public
- * @see [CLI option](../#-full-trace)
- * @param {boolean} [fullTrace=true] - Whether to print full stacktrace upon failure.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.fullTrace = function (fullTrace) {
- this.options.fullTrace = fullTrace !== false;
- return this;
- };
- /**
- * Specifies whitelist of variable names to be expected in global scope.
- *
- * @public
- * @see [CLI option](../#-global-variable-name)
- * @see {@link Mocha#checkLeaks}
- * @param {String[]|String} global - Accepted global variable name(s).
- * @return {Mocha} this
- * @chainable
- * @example
- *
- * // Specify variables to be expected in global scope
- * mocha.global(['jQuery', 'MyLib']);
- */
- Mocha.prototype.global = function (global) {
- this.options.global = (this.options.global || [])
- .concat(global)
- .filter(Boolean)
- .filter(function (elt, idx, arr) {
- return arr.indexOf(elt) === idx;
- });
- return this;
- };
- // for backwards compatibility, 'globals' is an alias of 'global'
- Mocha.prototype.globals = Mocha.prototype.global;
- /**
- * Enables or disables TTY color output by screen-oriented reporters.
- *
- * @public
- * @see [CLI option](../#-color-c-colors)
- * @param {boolean} [color=true] - Whether to enable color output.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.color = function (color) {
- this.options.color = color !== false;
- return this;
- };
- /**
- * Enables or disables reporter to use inline diffs (rather than +/-)
- * in test failure output.
- *
- * @public
- * @see [CLI option](../#-inline-diffs)
- * @param {boolean} [inlineDiffs=true] - Whether to use inline diffs.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.inlineDiffs = function (inlineDiffs) {
- this.options.inlineDiffs = inlineDiffs !== false;
- return this;
- };
- /**
- * Enables or disables reporter to include diff in test failure output.
- *
- * @public
- * @see [CLI option](../#-diff)
- * @param {boolean} [diff=true] - Whether to show diff on failure.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.diff = function (diff) {
- this.options.diff = diff !== false;
- return this;
- };
- /**
- * @summary
- * Sets timeout threshold value.
- *
- * @description
- * A string argument can use shorthand (such as "2s") and will be converted.
- * If the value is `0`, timeouts will be disabled.
- *
- * @public
- * @see [CLI option](../#-timeout-ms-t-ms)
- * @see [Timeouts](../#timeouts)
- * @param {number|string} msecs - Timeout threshold value.
- * @return {Mocha} this
- * @chainable
- * @example
- *
- * // Sets timeout to one second
- * mocha.timeout(1000);
- * @example
- *
- * // Same as above but using string argument
- * mocha.timeout('1s');
- */
- Mocha.prototype.timeout = function (msecs) {
- this.suite.timeout(msecs);
- return this;
- };
- /**
- * Sets the number of times to retry failed tests.
- *
- * @public
- * @see [CLI option](../#-retries-n)
- * @see [Retry Tests](../#retry-tests)
- * @param {number} retry - Number of times to retry failed tests.
- * @return {Mocha} this
- * @chainable
- * @example
- *
- * // Allow any failed test to retry one more time
- * mocha.retries(1);
- */
- Mocha.prototype.retries = function (retry) {
- this.suite.retries(retry);
- return this;
- };
- /**
- * Sets slowness threshold value.
- *
- * @public
- * @see [CLI option](../#-slow-ms-s-ms)
- * @param {number} msecs - Slowness threshold value.
- * @return {Mocha} this
- * @chainable
- * @example
- *
- * // Sets "slow" threshold to half a second
- * mocha.slow(500);
- * @example
- *
- * // Same as above but using string argument
- * mocha.slow('0.5s');
- */
- Mocha.prototype.slow = function (msecs) {
- this.suite.slow(msecs);
- return this;
- };
- /**
- * Forces all tests to either accept a `done` callback or return a promise.
- *
- * @public
- * @see [CLI option](../#-async-only-a)
- * @param {boolean} [asyncOnly=true] - Whether to force `done` callback or promise.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.asyncOnly = function (asyncOnly) {
- this.options.asyncOnly = asyncOnly !== false;
- return this;
- };
- /**
- * Disables syntax highlighting (in browser).
- *
- * @public
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.noHighlighting = function () {
- this.options.noHighlighting = true;
- return this;
- };
- /**
- * Enables or disables uncaught errors to propagate.
- *
- * @public
- * @see [CLI option](../#-allow-uncaught)
- * @param {boolean} [allowUncaught=true] - Whether to propagate uncaught errors.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.allowUncaught = function (allowUncaught) {
- this.options.allowUncaught = allowUncaught !== false;
- return this;
- };
- /**
- * @summary
- * Delays root suite execution.
- *
- * @description
- * Used to perform async operations before any suites are run.
- *
- * @public
- * @see [delayed root suite](../#delayed-root-suite)
- * @returns {Mocha} this
- * @chainable
- */
- Mocha.prototype.delay = function delay() {
- this.options.delay = true;
- return this;
- };
- /**
- * Enables or disables running tests in dry-run mode.
- *
- * @public
- * @see [CLI option](../#-dry-run)
- * @param {boolean} [dryRun=true] - Whether to activate dry-run mode.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.dryRun = function (dryRun) {
- this.options.dryRun = dryRun !== false;
- return this;
- };
- /**
- * Fails test run if no tests encountered with exit-code 1.
- *
- * @public
- * @see [CLI option](../#-fail-zero)
- * @param {boolean} [failZero=true] - Whether to fail test run.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.failZero = function (failZero) {
- this.options.failZero = failZero !== false;
- return this;
- };
- /**
- * Fail test run if tests were failed.
- *
- * @public
- * @see [CLI option](../#-pass-on-failing-test-suite)
- * @param {boolean} [passOnFailingTestSuite=false] - Whether to fail test run.
- * @return {Mocha} this
- * @chainable
- */
- Mocha.prototype.passOnFailingTestSuite = function(passOnFailingTestSuite) {
- this.options.passOnFailingTestSuite = passOnFailingTestSuite === true;
- return this;
- };
- /**
- * Causes tests marked `only` to fail the suite.
- *
- * @public
- * @see [CLI option](../#-forbid-only)
- * @param {boolean} [forbidOnly=true] - Whether tests marked `only` fail the suite.
- * @returns {Mocha} this
- * @chainable
- */
- Mocha.prototype.forbidOnly = function (forbidOnly) {
- this.options.forbidOnly = forbidOnly !== false;
- return this;
- };
- /**
- * Causes pending tests and tests marked `skip` to fail the suite.
- *
- * @public
- * @see [CLI option](../#-forbid-pending)
- * @param {boolean} [forbidPending=true] - Whether pending tests fail the suite.
- * @returns {Mocha} this
- * @chainable
- */
- Mocha.prototype.forbidPending = function (forbidPending) {
- this.options.forbidPending = forbidPending !== false;
- return this;
- };
- /**
- * Throws an error if mocha is in the wrong state to be able to transition to a "running" state.
- * @private
- */
- Mocha.prototype._guardRunningStateTransition = function () {
- if (this._state === mochaStates.RUNNING) {
- throw createMochaInstanceAlreadyRunningError(
- 'Mocha instance is currently running tests, cannot start a next test run until this one is done',
- this
- );
- }
- if (
- this._state === mochaStates.DISPOSED ||
- this._state === mochaStates.REFERENCES_CLEANED
- ) {
- throw createMochaInstanceAlreadyDisposedError(
- 'Mocha instance is already disposed, cannot start a new test run. Please create a new mocha instance. Be sure to set disable `cleanReferencesAfterRun` when you want to reuse the same mocha instance for multiple test runs.',
- this._cleanReferencesAfterRun,
- this
- );
- }
- };
- /**
- * Mocha version as specified by "package.json".
- *
- * @name Mocha#version
- * @type string
- * @readonly
- */
- Object.defineProperty(Mocha.prototype, 'version', {
- value: require('../package.json').version,
- configurable: false,
- enumerable: true,
- writable: false
- });
- /**
- * Runs root suite and invokes `fn()` when complete.
- *
- * @description
- * 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!
- *
- * @public
- * @see {@link Mocha#unloadFiles}
- * @see {@link Runner#run}
- * @param {DoneCB} [fn] - Callback invoked when test execution completed.
- * @returns {import("./runner.js")} runner instance
- * @example
- *
- * // exit with non-zero status if there were test failures
- * mocha.run(failures => process.exitCode = failures ? 1 : 0);
- */
- Mocha.prototype.run = function (fn) {
- this._guardRunningStateTransition();
- this._state = mochaStates.RUNNING;
- if (this._previousRunner) {
- this._previousRunner.dispose();
- this.suite.reset();
- }
- if (this.files.length && !this._lazyLoadFiles) {
- this.loadFiles();
- }
- var suite = this.suite;
- var options = this.options;
- options.files = this.files;
- const runner = new this._runnerClass(suite, {
- cleanReferencesAfterRun: this._cleanReferencesAfterRun,
- delay: options.delay,
- dryRun: options.dryRun,
- failZero: options.failZero
- });
- createStatsCollector(runner);
- var reporter = new this._reporter(runner, options);
- runner.checkLeaks = options.checkLeaks === true;
- runner.fullStackTrace = options.fullTrace;
- 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.global) {
- runner.globals(options.global);
- }
- if (options.color !== undefined) {
- exports.reporters.Base.useColors = options.color;
- }
- exports.reporters.Base.inlineDiffs = options.inlineDiffs;
- exports.reporters.Base.hideDiff = !options.diff;
- const done = failures => {
- this._previousRunner = runner;
- this._state = this._cleanReferencesAfterRun
- ? mochaStates.REFERENCES_CLEANED
- : mochaStates.INIT;
- fn = fn || utils.noop;
- if (typeof reporter.done === 'function') {
- reporter.done(failures, fn);
- } else {
- fn(failures);
- }
- };
- const runAsync = async runner => {
- const context =
- this.options.enableGlobalSetup && this.hasGlobalSetupFixtures()
- ? await this.runGlobalSetup(runner)
- : {};
- const failureCount = await runner.runAsync({
- files: this.files,
- options
- });
- if (this.options.enableGlobalTeardown && this.hasGlobalTeardownFixtures()) {
- await this.runGlobalTeardown(runner, {context});
- }
- return failureCount;
- };
- // no "catch" here is intentional. errors coming out of
- // Runner#run are considered uncaught/unhandled and caught
- // by the `process` event listeners.
- // also: returning anything other than `runner` would be a breaking
- // change
- runAsync(runner).then(done);
- return runner;
- };
- /**
- * Assigns hooks to the root suite
- * @param {MochaRootHookObject} [hooks] - Hooks to assign to root suite
- * @chainable
- */
- Mocha.prototype.rootHooks = function rootHooks({
- beforeAll = [],
- beforeEach = [],
- afterAll = [],
- afterEach = []
- } = {}) {
- beforeAll = utils.castArray(beforeAll);
- beforeEach = utils.castArray(beforeEach);
- afterAll = utils.castArray(afterAll);
- afterEach = utils.castArray(afterEach);
- beforeAll.forEach(hook => {
- this.suite.beforeAll(hook);
- });
- beforeEach.forEach(hook => {
- this.suite.beforeEach(hook);
- });
- afterAll.forEach(hook => {
- this.suite.afterAll(hook);
- });
- afterEach.forEach(hook => {
- this.suite.afterEach(hook);
- });
- return this;
- };
- /**
- * Toggles parallel mode.
- *
- * Must be run before calling {@link Mocha#run}. Changes the `Runner` class to
- * use; also enables lazy file loading if not already done so.
- *
- * Warning: when passed `false` and lazy loading has been enabled _via any means_ (including calling `parallelMode(true)`), this method will _not_ disable lazy loading. Lazy loading is a prerequisite for parallel
- * mode, but parallel mode is _not_ a prerequisite for lazy loading!
- * @param {boolean} [enable] - If `true`, enable; otherwise disable.
- * @throws If run in browser
- * @throws If Mocha not in `INIT` state
- * @returns {Mocha}
- * @chainable
- * @public
- */
- Mocha.prototype.parallelMode = function parallelMode(enable = true) {
- if (utils.isBrowser()) {
- throw createUnsupportedError('parallel mode is only supported in Node.js');
- }
- const parallel = Boolean(enable);
- if (
- parallel === this.options.parallel &&
- this._lazyLoadFiles &&
- this._runnerClass !== exports.Runner
- ) {
- return this;
- }
- if (this._state !== mochaStates.INIT) {
- throw createUnsupportedError(
- 'cannot change parallel mode after having called run()'
- );
- }
- this.options.parallel = parallel;
- // swap Runner class
- this._runnerClass = parallel
- ? require('./nodejs/parallel-buffered-runner')
- : exports.Runner;
- // lazyLoadFiles may have been set `true` otherwise (for ESM loading),
- // so keep `true` if so.
- return this.lazyLoadFiles(this._lazyLoadFiles || parallel);
- };
- /**
- * Disables implicit call to {@link Mocha#loadFiles} in {@link Mocha#run}. This
- * setting is used by watch mode, parallel mode, and for loading ESM files.
- * @todo This should throw if we've already loaded files; such behavior
- * necessitates adding a new state.
- * @param {boolean} [enable] - If `true`, disable eager loading of files in
- * {@link Mocha#run}
- * @chainable
- * @public
- */
- Mocha.prototype.lazyLoadFiles = function lazyLoadFiles(enable) {
- this._lazyLoadFiles = enable === true;
- debug('set lazy load to %s', enable);
- return this;
- };
- /**
- * Configures one or more global setup fixtures.
- *
- * If given no parameters, _unsets_ any previously-set fixtures.
- * @chainable
- * @public
- * @param {MochaGlobalFixture|MochaGlobalFixture[]} [setupFns] - Global setup fixture(s)
- * @returns {Mocha}
- */
- Mocha.prototype.globalSetup = function globalSetup(setupFns = []) {
- setupFns = utils.castArray(setupFns);
- this.options.globalSetup = setupFns;
- debug('configured %d global setup functions', setupFns.length);
- return this;
- };
- /**
- * Configures one or more global teardown fixtures.
- *
- * If given no parameters, _unsets_ any previously-set fixtures.
- * @chainable
- * @public
- * @param {MochaGlobalFixture|MochaGlobalFixture[]} [teardownFns] - Global teardown fixture(s)
- * @returns {Mocha}
- */
- Mocha.prototype.globalTeardown = function globalTeardown(teardownFns = []) {
- teardownFns = utils.castArray(teardownFns);
- this.options.globalTeardown = teardownFns;
- debug('configured %d global teardown functions', teardownFns.length);
- return this;
- };
- /**
- * Run any global setup fixtures sequentially, if any.
- *
- * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalSetup` option is `false`; see {@link Mocha#enableGlobalSetup}.
- *
- * The context object this function resolves with should be consumed by {@link Mocha#runGlobalTeardown}.
- * @param {object} [context] - Context object if already have one
- * @public
- * @returns {Promise<object>} Context object
- */
- Mocha.prototype.runGlobalSetup = async function runGlobalSetup(context = {}) {
- const {globalSetup} = this.options;
- if (globalSetup && globalSetup.length) {
- debug('run(): global setup starting');
- await this._runGlobalFixtures(globalSetup, context);
- debug('run(): global setup complete');
- }
- return context;
- };
- /**
- * Run any global teardown fixtures sequentially, if any.
- *
- * This is _automatically called_ by {@link Mocha#run} _unless_ the `runGlobalTeardown` option is `false`; see {@link Mocha#enableGlobalTeardown}.
- *
- * Should be called with context object returned by {@link Mocha#runGlobalSetup}, if applicable.
- * @param {object} [context] - Context object if already have one
- * @public
- * @returns {Promise<object>} Context object
- */
- Mocha.prototype.runGlobalTeardown = async function runGlobalTeardown(
- context = {}
- ) {
- const {globalTeardown} = this.options;
- if (globalTeardown && globalTeardown.length) {
- debug('run(): global teardown starting');
- await this._runGlobalFixtures(globalTeardown, context);
- }
- debug('run(): global teardown complete');
- return context;
- };
- /**
- * Run global fixtures sequentially with context `context`
- * @private
- * @param {MochaGlobalFixture[]} [fixtureFns] - Fixtures to run
- * @param {object} [context] - context object
- * @returns {Promise<object>} context object
- */
- Mocha.prototype._runGlobalFixtures = async function _runGlobalFixtures(
- fixtureFns = [],
- context = {}
- ) {
- for await (const fixtureFn of fixtureFns) {
- await fixtureFn.call(context);
- }
- return context;
- };
- /**
- * Toggle execution of any global setup fixture(s)
- *
- * @chainable
- * @public
- * @param {boolean } [enabled=true] - If `false`, do not run global setup fixture
- * @returns {Mocha}
- */
- Mocha.prototype.enableGlobalSetup = function enableGlobalSetup(enabled = true) {
- this.options.enableGlobalSetup = Boolean(enabled);
- return this;
- };
- /**
- * Toggle execution of any global teardown fixture(s)
- *
- * @chainable
- * @public
- * @param {boolean } [enabled=true] - If `false`, do not run global teardown fixture
- * @returns {Mocha}
- */
- Mocha.prototype.enableGlobalTeardown = function enableGlobalTeardown(
- enabled = true
- ) {
- this.options.enableGlobalTeardown = Boolean(enabled);
- return this;
- };
- /**
- * Returns `true` if one or more global setup fixtures have been supplied.
- * @public
- * @returns {boolean}
- */
- Mocha.prototype.hasGlobalSetupFixtures = function hasGlobalSetupFixtures() {
- return Boolean(this.options.globalSetup.length);
- };
- /**
- * Returns `true` if one or more global teardown fixtures have been supplied.
- * @public
- * @returns {boolean}
- */
- Mocha.prototype.hasGlobalTeardownFixtures =
- function hasGlobalTeardownFixtures() {
- return Boolean(this.options.globalTeardown.length);
- };
|