import path from "path" ; import * as builtinReporters from "./reporters" ; import * as utils from "./utils" ; import mocharc from "./mocharc" ; import Suite from "./suite" ; import * as esmUtils from "./nodejs/esm-utils" ; import createStatsCollector from "./stats-collector" ; import { warn , createInvalidReporterError , createInvalidInterfaceError , createMochaInstanceAlreadyDisposedError , createMochaInstanceAlreadyRunningError , createUnsupportedError , } from "./errors" ; import * as interfaces from "./interfaces" ; import Runnable from "./runnable" ; import Context from "./context" ; import Runner from "./runner" ; import Hook from "./hook" ; import Test from "./test" ; function escapeStringRegexp ( string ) { if ( typeof string !== "string" ) { throw new TypeError ( "Expected a string" ) ; } return string . replace ( /[|\\{}()[\]^$+*?.]/g , "\\$&" ) . replace ( /-/g , "\\x2d" ) ; } const { EVENT_FILE_PRE_REQUIRE , EVENT_FILE_POST_REQUIRE , EVENT_FILE_REQUIRE } = Suite . constants ; /**
 * A Mocha instance is a finite state machine.
 * These are the states it can be in.
 */ const mochaStates = utils . defineConstants ( { private INIT : "init" , private RUNNING : "running" , private REFERENCES_CLEANED : "referencesCleaned" , private DISPOSED : "disposed" , } ) ; /**
 * To require local UIs and reporters when running in node.
 */ if ( ! utils . isBrowser ( ) && typeof module . paths !== "undefined" ) { const cwd = utils . cwd ( ) ; module . paths . push ( cwd , path . join ( cwd , "node_modules" ) ) ; } export { utils , interfaces , builtinReporters as reporters , Runnable , Context , Runner , Suite , Hook , Test , } ; let currentContext ; export const afterEach = function ( ... args ) { return ( currentContext . afterEach || currentContext . teardown ) . apply ( this , args ) ; } ; export const after = function ( ... args ) { return ( currentContext . after || currentContext . suiteTeardown ) . apply ( this , args ) ; } ; export const beforeEach = function ( ... args ) { return ( currentContext . beforeEach || currentContext . setup ) . apply ( this , args ) ; } ; export const before = function ( ... args ) { return ( currentContext . before || currentContext . suiteSetup ) . apply ( this , args ) ; } ; export const describe = function ( ... args ) { return ( currentContext . describe || currentContext . suite ) . apply ( this , args ) ; } ; describe . only = function ( ... args ) { return ( currentContext . describe || currentContext . suite ) . only . apply ( this , args ) ; } ; describe . skip = function ( ... args ) { return ( currentContext . describe || currentContext . suite ) . skip . apply ( this , args ) ; } ; export const it = function ( ... args ) { return ( currentContext . it || currentContext . test ) . apply ( this , args ) ; } ; it . only = function ( ... args ) { return ( currentContext . it || currentContext . test ) . only . apply ( this , args ) ; } ; it . skip = function ( ... args ) { return ( currentContext . it || currentContext . test ) . skip . apply ( this , args ) ; } ; export const xdescribe = describe . skip ; export const xit = it . skip ; export const setup = beforeEach ; export const suiteSetup = before ; export const suiteTeardown = after ; export const suite = describe ; export const teardown = afterEach ; export const test = it ; export const run = function ( ... args ) { return currentContext . run . apply ( this , args ) ; } ; interface MochaOptions { /** Propagate uncaught errors? */ allowUncaught ? : boolean | undefined ; /** Force `done` callback or promise? */ asyncOnly ? : boolean | undefined ; /** bail on the first test failure. */ bail ? : boolean | undefined ; /** Check for global variable leaks? */ checkLeaks ? : boolean | undefined ; /** Color TTY output from reporter */ color ? : boolean | undefined ; /** Delay root suite execution? */ delay ? : boolean | undefined ; /** Show diff on failure? */ diff ? : boolean | undefined ; /** Report tests without running them? */ dryRun ? : boolean | undefined ; /** Test filter given string. */ fgrep ? : string | undefined ; /** Tests marked `only` fail the suite? */ forbidOnly ? : boolean | undefined ; /** Pending tests fail the suite? */ forbidPending ? : boolean | undefined ; /** Full stacktrace upon failure? */ fullTrace ? : boolean | undefined ; /** Variables expected in global scope. */ globals ? : string [ ] | undefined ; /** Test filter given regular expression. */ grep ? : string | RegExp | undefined ; /** Display inline diffs? */ inlineDiffs ? : boolean | undefined ; /** Invert test filter matches? */ invert ? : boolean | undefined ; /** Disable syntax highlighting? */ noHighlighting ? : boolean | undefined ; /** Reporter name or constructor. */ reporter ? : string | any | undefined ; /** Reporter settings object. */ reporterOptions ? : any ; /** Number of times to retry failed tests. */ retries ? : number | undefined ; /** Slow threshold value. */ slow ? : number | undefined ; /** Timeout threshold value. */ timeout ? : number | string | undefined ; /** Interface name. */ ui ? : any | undefined ; /** Run jobs in parallel */ parallel ? : boolean | undefined ; /** Max number of worker processes for parallel runs. */ jobs ? : number | undefined ; /** Hooks to bootstrap the root suite with. */ rootHooks ? : any | undefined ; /** Pathname of `rootHooks` plugin for parallel runs. */ require ? : string [ ] | undefined ; /** Should be `true` if `Mocha` process is running in a worker process. */ isWorker ? : boolean | undefined ; reporterOption ? : any ; global ? : any ; globalSetup ? : any ; globalTeardown ? : any ; enableGlobalSetup ? : boolean ; enableGlobalTeardown ? : boolean ; files ? : string [ ] ; failZero ? : any ; } const defaultOptions = { allowUncaught : undefined , asyncOnly : undefined , bail : undefined , checkLeaks : undefined , color : undefined , delay : undefined , diff : undefined , dryRun : undefined , fgrep : undefined , forbidOnly : undefined , forbidPending : undefined , fullTrace : undefined , globals : undefined , grep : undefined , inlineDiffs : undefined , invert : undefined , noHighlighting : undefined , reporter : undefined , reporterOptions : undefined , retries : undefined , slow : undefined , timeout : undefined , ui : undefined , parallel : undefined , jobs : undefined , rootHooks : undefined , require : undefined , isWorker : undefined , reporterOption : undefined , global : undefined , } ; class Mocha { private _reporter ; private _ui ; _cleanReferencesAfterRun : boolean ; _state : any ; _runnerClass : any ; _lazyLoadFiles : boolean ; isWorker : boolean ; _previousRunner : any ; suite : Suite ; files : string [ ] ; options : MochaOptions ; /**
     * Constructs a new Mocha instance with `options`.
     */ constructor ( options = defaultOptions ) { options = { ... mocharc , ... options } ; this . files = [ ] ; this . options = options ; 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 . reporterOption || options . reporterOptions ) . slow ( options . slow ) . global ( options . global ) ; if ( typeof options . timeout !== "undefined" ) { this . timeout ( ! options . timeout ? 0 : options . timeout ) ; } if ( "retries" in options ) { this . retries ( options . retries ) ; } [ "allowUncaught" , "asyncOnly" , "bail" , "checkLeaks" , "color" , "delay" , "diff" , "dryRun" , "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  Mocha .  Defaults to
         *  Runner in serial mode; changes in parallel mode.
         *  memberof private this . _runnerClass = exports . Runner ; /**
         * Whether or not to call  Mocha implicitly when calling
         *  Mocha .  If this is `true`, then it's up to the consumer to call
         *  Mocha _or_  Mocha .
         *  private memberof this . _lazyLoadFiles = false ; memberof 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 ) ) { this . parallelMode ( true ) ; } } public see param { boolean } bail returns { Mocha } chainable bail = function ( bail ) { this . suite . bail ( bail !== false ) ; return this ; } ; summary description param file returns addFile ( file ) { this . files . push ( file ) ; return this ; } addFiles ( ... file ) { this . files . push ( ... file ) ; return this ; } public see see param { String | Function } reporterName param { Object } reporterOptions returns { Mocha } chainable throws example reporter = function ( reporterName , reporterOptions ) { if ( typeof reporterName === "function" ) { this . _reporter = reporterName ; } else { reporterName = reporterName || "spec" ; var reporter ; if ( builtinReporters [ reporterName ] ) { reporter = builtinReporters [ reporterName ] ; } if ( ! reporter ) { try { reporter = require ( reporterName ) ; } catch ( err ) { if ( err . code === "MODULE_NOT_FOUND" ) { try { reporter = require ( path . resolve ( utils . cwd ( ) , reporterName ) ) ; } catch ( _err ) { _err . code === "MODULE_NOT_FOUND" ? warn ( `'${ reporterName }' reporter not found` ) : warn ( `'${ reporterName }' reporter blew up with error:\n ${ err . stack }` ) ; } } else { warn ( `'${ reporterName }' reporter blew up with error:\n ${ err . stack }` ) ; } } } if ( ! reporter ) { throw createInvalidReporterError ( `invalid reporter '${ reporterName }'` , reporterName ) ; } this . _reporter = reporter ; } this . options . reporterOption = reporterOptions ; this . options . reporterOptions = reporterOptions ; return this ; } ; public see see param { string | Function } ui returns { Mocha } chainable throws ui = function ( ui ) { var bindInterface ; if ( typeof ui === "function" ) { bindInterface = ui ; } else { ui = ui || "bdd" ; bindInterface = exports . interfaces [ ui ] . styleInterface ; 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 ; } ; resolveFile : any = path . resolve ; description private see Mocha see Mocha see Mocha see Mocha param { Function } fn loadFiles ( callback ? ) { const self = this ; const { suite } = this ; for ( const file of this . files ) { const resolvedFile = this . resolveFile ( file ) ; suite . emit ( EVENT_FILE_PRE_REQUIRE , global , resolvedFile , this ) ; suite . emit ( EVENT_FILE_REQUIRE , require ( resolvedFile ) , resolvedFile , this ) ; suite . emit ( EVENT_FILE_POST_REQUIRE , global , resolvedFile , this ) ; } callback && callback ( ) ; } description public see Mocha see Mocha see Mocha returns { Promise } example loadFilesAsync = function ( ) { 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 ) ; } ) ; } ; private static see Mocha param { string } file static unloadFile = function ( file ) { if ( utils . isBrowser ( ) ) { throw createUnsupportedError ( "unloadFile() is only suported in a Node.js environment" ) ; } return require ( "./nodejs/file-unloader" ) . unloadFile ( file ) ; } ; description public see Mocha returns { Mocha } chainable 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 ; } ; public see Mocha param { string } str returns { Mocha } chainable example fgrep = function ( str ) { if ( ! str ) { return this ; } return this . grep ( new RegExp ( escapeStringRegexp ( str ) ) ) ; } ; summary description public see see Mocha see Mocha param { RegExp | String } re return { Mocha } chainable example example example grep = function ( re ) { if ( utils . isString ( re ) ) { 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 ; } ; public see Mocha return { Mocha } chainable example invert = function ( ) { this . options . invert = true ; return this ; } ; public see param { boolean } checkLeaks return { Mocha } chainable checkLeaks = function ( checkLeaks ) { this . options . checkLeaks = checkLeaks !== false ; return this ; } ; public see Mocha param { boolean } cleanReferencesAfterRun return { Mocha } chainable cleanReferencesAfterRun = function ( cleanReferencesAfterRun ) { this . _cleanReferencesAfterRun = cleanReferencesAfterRun !== false ; return this ; } ; public 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 ; } ; public see param { boolean } fullTrace return { Mocha } chainable fullTrace = function ( fullTrace ) { this . options . fullTrace = fullTrace !== false ; return this ; } ; public see see Mocha param { String [ ] | String } global return { Mocha } chainable example 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 ; } ; globals = global ; public see param { boolean } color return { Mocha } chainable color = function ( color ) { this . options . color = color !== false ; return this ; } ; public see param { boolean } inlineDiffs return { Mocha } chainable inlineDiffs = function ( inlineDiffs ) { this . options . inlineDiffs = inlineDiffs !== false ; return this ; } ; public see param { boolean } diff return { Mocha } chainable diff = function ( diff ) { this . options . diff = diff !== false ; return this ; } ; summary description public see see param { number | string } msecs return { Mocha } chainable example example timeout = function ( msecs ) { this . suite . timeout ( msecs ) ; return this ; } ; public see see param { number } retry return { Mocha } chainable example retries = function ( retry ) { this . suite . retries ( retry ) ; return this ; } ; public see param { number } msecs return { Mocha } chainable example example slow = function ( msecs ) { this . suite . slow ( msecs ) ; return this ; } ; public see param { boolean } asyncOnly return { Mocha } chainable asyncOnly = function ( asyncOnly ) { this . options . asyncOnly = asyncOnly !== false ; return this ; } ; public return { Mocha } chainable noHighlighting = function ( ) { this . options . noHighlighting = true ; return this ; } ; public see param { boolean } allowUncaught return { Mocha } chainable allowUncaught = function ( allowUncaught ) { this . options . allowUncaught = allowUncaught !== false ; return this ; } ; summary description public see returns { Mocha } chainable delay = function delay ( ) { this . options . delay = true ; return this ; } ; public see param { boolean } dryRun return { Mocha } chainable dryRun = function ( dryRun ) { this . options . dryRun = dryRun !== false ; return this ; } ; public see param { boolean } failZero return { Mocha } chainable failZero = function ( failZero ) { this . options . failZero = failZero !== false ; return this ; } ; public see param { boolean } forbidOnly returns { Mocha } chainable forbidOnly = function ( forbidOnly ) { this . options . forbidOnly = forbidOnly !== false ; return this ; } ; public see param { boolean } forbidPending returns { Mocha } chainable 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.
     */ guardRunningStateTransition ( ) { 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 ) ; } } private callback DoneCB param { number } failures description public see Mocha see Runner param { DoneCB } fn returns { Runner } example run ( fn ) { this . guardRunningStateTransition ( ) ; this . _state = mochaStates . RUNNING ; if ( this . _previousRunner ) { this . _previousRunner . dispose ( ) ; this . suite . reset ( ) ; } if ( this . files . length && ! this . _lazyLoadFiles ) { this . loadFiles ( ) ; } const { suite , options } = this ; 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 ( context ) ; } return failureCount ; } ; runAsync ( runner ) . then ( done ) ; return runner ; } param { MochaRootHookObject } hooks chainable 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  Mocha . 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 throws throws returns { Mocha } chainable public 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 ; this . _runnerClass = parallel ? require ( "./nodejs/parallel-buffered-runner" ) : exports . Runner ; return this . lazyLoadFiles ( this . _lazyLoadFiles || parallel ) ; } ; /**
     * Disables implicit call to  Mocha in  Mocha . This
     * setting is used by watch mode, parallel mode, and for loading ESM files.
     *  todo param { boolean } enable - If `true`, disable eager loading of files in
     *  Mocha chainable public lazyLoadFiles = function lazyLoadFiles ( enable ) { this . _lazyLoadFiles = enable === true ; return this ; } ; chainable public param { MochaGlobalFixture | MochaGlobalFixture [ ] } setupFns returns { Mocha } globalSetup = function globalSetup ( setupFns = [ ] ) { setupFns = utils . castArray ( setupFns ) ; this . options . globalSetup = setupFns ; return this ; } ; chainable public param { MochaGlobalFixture | MochaGlobalFixture [ ] } teardownFns returns { Mocha } globalTeardown = function globalTeardown ( teardownFns = [ ] ) { teardownFns = utils . castArray ( teardownFns ) ; this . options . globalTeardown = teardownFns ; return this ; } ; /**
     * Run any global setup fixtures sequentially, if any.
     *
     * This is _automatically called_ by  Mocha _unless_ the `runGlobalSetup` option is `false`; see  Mocha .
     *
     * The context object this function resolves with should be consumed by  Mocha .
     *  param { object } context public returns { Promise < object > } runGlobalSetup = async function runGlobalSetup ( context = { } ) { const { globalSetup } = this . options ; if ( globalSetup && globalSetup . length ) { await this . _runGlobalFixtures ( globalSetup , context ) ; } return context ; } ; /**
     * Run any global teardown fixtures sequentially, if any.
     *
     * This is _automatically called_ by  Mocha _unless_ the `runGlobalTeardown` option is `false`; see  Mocha .
     *
     * Should be called with context object returned by  Mocha , if applicable.
     *  param { object } context public returns { Promise < object > } runGlobalTeardown = async function runGlobalTeardown ( context = { } ) { const { globalTeardown } = this . options ; if ( globalTeardown && globalTeardown . length ) { await this . _runGlobalFixtures ( globalTeardown , context ) ; } return context ; } ; private param { MochaGlobalFixture [ ] } fixtureFns param { object } context returns { Promise < object > } _runGlobalFixtures = async function _runGlobalFixtures ( fixtureFns = [ ] , context = { } ) { for await ( const fixtureFn of fixtureFns ) { await fixtureFn . call ( context ) ; } return context ; } ; chainable public param { boolean } enabled returns { Mocha } enableGlobalSetup = function enableGlobalSetup ( enabled = true ) { this . options . enableGlobalSetup = Boolean ( enabled ) ; return this ; } ; chainable public param { boolean } enabled returns { Mocha } enableGlobalTeardown = function enableGlobalTeardown ( enabled = true ) { this . options . enableGlobalTeardown = Boolean ( enabled ) ; return this ; } ; public returns { boolean } hasGlobalSetupFixtures = function hasGlobalSetupFixtures ( ) { return Boolean ( this . options . globalSetup . length ) ; } ; public returns { boolean } hasGlobalTeardownFixtures ( ) { return Boolean ( this . options . globalTeardown . length ) ; } } export default Mocha ;