// Type definitions for mocha 7.0
// Project: https://mochajs.org
// Definitions by: Kazi Manzur Rashid <https://github.com/kazimanzurrashid>
//                 otiai10 <https://github.com/otiai10>
//                 jt000 <https://github.com/jt000>
//                 Vadim Macagon <https://github.com/enlight>
//                 Andrew Bradley <https://github.com/cspotcode>
//                 Dmitrii Sorin <https://github.com/1999>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.1

/**
 * Mocha API
 *
 * @see https://mochajs.org/api/mocha
 */
declare class Mocha {
    private _growl;
    private _reporter;
    private _ui;

    constructor(options?: Mocha.MochaOptions);

    suite: Mocha.Suite;
    files: string[];
    options: Mocha.MochaInstanceOptions;

    /**
     * Enable or disable bailing on the first failure.
     *
     * @see https://mochajs.org/api/mocha#bail
     */
    bail(bail?: boolean): this;

    /**
     * Add test `file`.
     *
     * @see https://mochajs.org/api/mocha#addFile
     */
    addFile(file: string): this;

    /**
     * Set reporter to one of the built-in reporters.
     *
     * @see https://mochajs.org/api/mocha#reporter
     */
    reporter(reporter: Mocha.Reporter, reporterOptions?: any): this;

    /**
     * Set reporter to the provided constructor, one of the built-in reporters, or loads a reporter
     * from a module path. Defaults to `"spec"`.
     *
     * @see https://mochajs.org/api/mocha#reporter
     */
    reporter(reporter?: string | Mocha.ReporterConstructor, reporterOptions?: any): this;

    /**
     * Set test UI to one of the built-in test interfaces.
     *
     * @see https://mochajs.org/api/mocha#ui
     */
    ui(name: Mocha.Interface): this;

    /**
     * Set test UI to one of the built-in test interfaces or loads a test interface from a module
     * path. Defaults to `"bdd"`.
     *
     * @see https://mochajs.org/api/mocha#ui
     */
    ui(name?: string): this;

    /**
     * Escape string and add it to grep as a RegExp.
     *
     * @see https://mochajs.org/api/mocha#fgrep
     */
    fgrep(str: string): this;

    /**
     * Add regexp to grep, if `re` is a string it is escaped.
     *
     * @see https://mochajs.org/api/mocha#grep
     */
    grep(re: string | RegExp): this;

    /**
     * Invert `.grep()` matches.
     *
     * @see https://mochajs.org/api/mocha#invert
     */
    invert(): this;

    /**
     * Ignore global leaks.
     *
     * @see https://mochajs.org/api/mocha#ignoreLeaks
     */
    ignoreLeaks(ignore: boolean): this;

    /**
     * Enable global leak checking.
     *
     * @see https://mochajs.org/api/mocha#checkLeaks
     */
    checkLeaks(): this;

    /**
     * Display long stack-trace on failing
     *
     * @see https://mochajs.org/api/mocha#fullTrace
     */
    fullTrace(): this;

    /**
     * Enable growl support.
     *
     * @see https://mochajs.org/api/mocha#growl
     */
    growl(): this;

    /**
     * Ignore `globals` array or string.
     *
     * @see https://mochajs.org/api/mocha#globals
     */
    globals(globals: string | ReadonlyArray<string>): this;

    /**
     * Emit color output.
     *
     * @see https://mochajs.org/api/mocha#useColors
     */
    useColors(colors: boolean): this;

    /**
     * Use inline diffs rather than +/-.
     *
     * @see https://mochajs.org/api/mocha#useInlineDiffs
     */
    useInlineDiffs(inlineDiffs: boolean): this;

    /**
     * Do not show diffs at all.
     *
     * @see https://mochajs.org/api/mocha#hideDiff
     */
    hideDiff(hideDiff: boolean): this;

    /**
     * Set the timeout in milliseconds.
     *
     * @see https://mochajs.org/api/mocha#timeout
     */
    timeout(timeout: string | number): this;

    /**
     * Set the number of times to retry failed tests.
     *
     * @see https://mochajs.org/api/mocha#retries
     */
    retries(n: number): this;

    /**
     * Set slowness threshold in milliseconds.
     *
     * @see https://mochajs.org/api/mocha#slow
     */
    slow(slow: string | number): this;

    /**
     * Enable timeouts.
     *
     * @see https://mochajs.org/api/mocha#enableTimeouts
     */
    enableTimeouts(enabled?: boolean): this;

    /**
     * Makes all tests async (accepting a callback)
     *
     * @see https://mochajs.org/api/mocha#asyncOnly.
     */
    asyncOnly(): this;

    /**
     * Disable syntax highlighting (in browser).
     *
     * @see https://mochajs.org/api/mocha#noHighlighting
     */
    noHighlighting(): this;

    /**
     * Enable uncaught errors to propagate (in browser).
     *
     * @see https://mochajs.org/api/mocha#allowUncaught
     */
    allowUncaught(): boolean;

    /**
     * Delay root suite execution.
     *
     * @see https://mochajs.org/api/mocha#delay
     */
    delay(): boolean;

    /**
     * Tests marked only fail the suite
     *
     * @see https://mochajs.org/api/mocha#forbidOnly
     */
    forbidOnly(): boolean;

    /**
     * Pending tests and tests marked skip fail the suite
     *
     * @see https://mochajs.org/api/mocha#forbidPending
     */
    forbidPending(): boolean;

    /**
     * Run tests and invoke `fn()` when complete.
     *
     * Note that `run` 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.
     *
     * @see https://mochajs.org/api/mocha#run
     */
    run(fn?: (failures: number) => void): Mocha.Runner;

    /**
     * Load registered files.
     *
     * @see https://mochajs.org/api/mocha#loadFiles
     */
    protected loadFiles(fn?: () => void): void;
}

declare namespace Mocha {
    namespace utils {
        /**
         * Compute a slug from the given `str`.
         *
         * @see https://mochajs.org/api/module-utils.html#.slug
         */
        function slug(str: string): string;

        /**
         * Strip the function definition from `str`, and re-indent for pre whitespace.
         *
         * @see https://mochajs.org/api/module-utils.html#.clean
         */
        function clean(str: string): string;

        /**
         * Highlight the given string of `js`.
         */
        function highlight(js: string): string;

        /**
         * Takes some variable and asks `Object.prototype.toString()` what it thinks it is.
         */
        function type(value: any): string;

        /**
         * Stringify `value`. Different behavior depending on type of value:
         *
         * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
         * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
         * - If `value` is an *empty* object, function, or array, returns `'{}'`, `'[Function]'`, or `'[]'` respectively.
         * - If `value` has properties, call canonicalize} on it, then return result of `JSON.stringify()`
         *
         * @see https://mochajs.org/api/module-utils.html#.stringify
         */
        function stringify(value: any): string;

        /**
         * Return a new Thing that has the keys in sorted order. Recursive.
         *
         * If the Thing...
         * - has already been seen, return string `'[Circular]'`
         * - is `undefined`, return string `'[undefined]'`
         * - is `null`, return value `null`
         * - is some other primitive, return the value
         * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
         * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
         * - is an empty `Array`, `Object`, or `Function`, returns `'[]'`, `'{}'`, or `'[Function]'` respectively.
         *
         * @see https://mochajs.org/api/module-utils.html#.canonicalize
         */
        function canonicalize(value: any, stack: any[], typeHint: string): any;

        /**
         * Lookup file names at the given `path`.
         *
         * @see https://mochajs.org/api/Mocha.utils.html#.exports.lookupFiles
         */
        function lookupFiles(filepath: string, extensions?: string[], recursive?: boolean): string[];

        /**
         * Generate an undefined error with a message warning the user.
         *
         * @see https://mochajs.org/api/module-utils.html#.undefinedError
         */
        function undefinedError(): Error;

        /**
         * Generate an undefined error if `err` is not defined.
         *
         * @see https://mochajs.org/api/module-utils.html#.getError
         */
        function getError(err: Error | undefined): Error;

        /**
         * When invoking this function you get a filter function that get the Error.stack as an
         * input, and return a prettify output. (i.e: strip Mocha and internal node functions from
         * stack trace).
         *
         * @see https://mochajs.org/api/module-utils.html#.stackTraceFilter
         */
        function stackTraceFilter(): (stack: string) => string;
    }

    namespace interfaces {
        function bdd(suite: Suite): void;
        function tdd(suite: Suite): void;
        function qunit(suite: Suite): void;
        function exports(suite: Suite): void;
    }

    // #region Test interface augmentations

    interface HookFunction {
        /**
         * [bdd, qunit, tdd] Describe a "hook" to execute the given callback `fn`. The name of the
         * function is used as the name of the hook.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: Func): void;

        /**
         * [bdd, qunit, tdd] Describe a "hook" to execute the given callback `fn`. The name of the
         * function is used as the name of the hook.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: AsyncFunc): void;

        /**
         * [bdd, qunit, tdd] Describe a "hook" to execute the given `title` and callback `fn`.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (name: string, fn?: Func): void;

        /**
         * [bdd, qunit, tdd] Describe a "hook" to execute the given `title` and callback `fn`.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (name: string, fn?: AsyncFunc): void;
    }

    interface SuiteFunction {
        /**
         * [bdd, tdd] Describe a "suite" with the given `title` and callback `fn` containing
         * nested suites.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn: (this: Suite) => void): Suite;

        /**
         * [qunit] Describe a "suite" with the given `title`.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string): Suite;

        /**
         * [bdd, tdd, qunit] Indicates this suite should be executed exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        only: ExclusiveSuiteFunction;

        /**
         * [bdd, tdd] Indicates this suite should not be executed.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        skip: PendingSuiteFunction;
    }

    interface ExclusiveSuiteFunction {
        /**
         * [bdd, tdd] Describe a "suite" with the given `title` and callback `fn` containing
         * nested suites. Indicates this suite should be executed exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn: (this: Suite) => void): Suite;

        /**
         * [qunit] Describe a "suite" with the given `title`. Indicates this suite should be executed
         * exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string): Suite;
    }

    /**
     * [bdd, tdd] Describe a "suite" with the given `title` and callback `fn` containing
     * nested suites. Indicates this suite should not be executed.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @returns [bdd] `Suite`
     * @returns [tdd] `void`
     */
    interface PendingSuiteFunction {
        (title: string, fn: (this: Suite) => void): Suite | void;
    }

    interface TestFunction {
        /**
         * Describe a specification or test-case with the given callback `fn` acting as a thunk.
         * The name of the function is used as the name of the test.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: Func): Test;

        /**
         * Describe a specification or test-case with the given callback `fn` acting as a thunk.
         * The name of the function is used as the name of the test.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: AsyncFunc): Test;

        /**
         * Describe a specification or test-case with the given `title` and callback `fn` acting
         * as a thunk.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn?: Func): Test;

        /**
         * Describe a specification or test-case with the given `title` and callback `fn` acting
         * as a thunk.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn?: AsyncFunc): Test;

        /**
         * Indicates this test should be executed exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        only: ExclusiveTestFunction;

        /**
         * Indicates this test should not be executed.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        skip: PendingTestFunction;

        /**
         * Number of attempts to retry.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        retries(n: number): void;
    }

    interface ExclusiveTestFunction {
        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn`
         * acting as a thunk. The name of the function is used as the name of the test. Indicates
         * this test should be executed exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: Func): Test;

        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn`
         * acting as a thunk. The name of the function is used as the name of the test. Indicates
         * this test should be executed exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: AsyncFunc): Test;

        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and
         * callback `fn` acting as a thunk. Indicates this test should be executed exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn?: Func): Test;

        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and
         * callback `fn` acting as a thunk. Indicates this test should be executed exclusively.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn?: AsyncFunc): Test;
    }

    interface PendingTestFunction {
        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn`
         * acting as a thunk. The name of the function is used as the name of the test. Indicates
         * this test should not be executed.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: Func): Test;

        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given callback `fn`
         * acting as a thunk. The name of the function is used as the name of the test. Indicates
         * this test should not be executed.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (fn: AsyncFunc): Test;

        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and
         * callback `fn` acting as a thunk. Indicates this test should not be executed.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn?: Func): Test;

        /**
         * [bdd, tdd, qunit] Describe a specification or test-case with the given `title` and
         * callback `fn` acting as a thunk. Indicates this test should not be executed.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        (title: string, fn?: AsyncFunc): Test;
    }

    /**
     * Execute after each test case.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#afterEach
     */
    let afterEach: HookFunction;

    /**
     * Execute after running tests.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#after
     */
    let after: HookFunction;

    /**
     * Execute before each test case.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#beforeEach
     */
    let beforeEach: HookFunction;

    /**
     * Execute before running tests.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#before
     */
    let before: HookFunction;

    /**
     * Describe a "suite" containing nested suites and tests.
     *
     * - _Only available when invoked via the mocha CLI._
     */
    let describe: SuiteFunction;

    /**
     * Describes a test case.
     *
     * - _Only available when invoked via the mocha CLI._
     */
    let it: TestFunction;

    /**
     * Describes a pending test case.
     *
     * - _Only available when invoked via the mocha CLI._
     */
    let xit: PendingTestFunction;

    /**
     * Execute before each test case.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#beforeEach
     */
    let setup: HookFunction;

    /**
     * Execute before running tests.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#before
     */
    let suiteSetup: HookFunction;

    /**
     * Execute after running tests.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#after
     */
    let suiteTeardown: HookFunction;

    /**
     * Describe a "suite" containing nested suites and tests.
     *
     * - _Only available when invoked via the mocha CLI._
     */
    let suite: SuiteFunction;

    /**
     * Execute after each test case.
     *
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#afterEach
     */
    let teardown: HookFunction;

    /**
     * Describes a test case.
     *
     * - _Only available when invoked via the mocha CLI._
     */
    let test: TestFunction;

    /**
     * Triggers root suite execution.
     *
     * - _Only available if flag --delay is passed into Mocha._
     * - _Only available when invoked via the mocha CLI._
     *
     * @see https://mochajs.org/api/global.html#runWithSuite
     */
    function run(): void;

    // #endregion Test interface augmentations

    namespace reporters {
        /**
         * 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.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Base.html
         */
        class Base {
            constructor(runner: Runner, options?: MochaOptions);
            /** @deprecated Use the overload that accepts `Mocha.Runner` instead. */
            constructor(runner: IRunner, options?: MochaOptions);

            /**
             * Test run statistics
             */
            stats: Stats;

            /**
             * Test failures
             */
            failures: Test[];

            /**
             * The configured runner
             */
            runner: Runner;

            /**
             * Output common epilogue used by many of the bundled reporters.
             *
             * @see https://mochajs.org/api/Mocha.reporters.Base.html#.Base#epilogue
             */
            epilogue(): void;

            done?(failures: number, fn?: (failures: number) => void): void;
        }

        namespace Base {
            /**
             * Enables coloring by default
             *
             * @see https://mochajs.org/api/module-base#.useColors
             */
            let useColors: boolean;

            /**
             * Inline diffs instead of +/-
             *
             * @see https://mochajs.org/api/module-base#.inlineDiffs
             */
            let inlineDiffs: boolean;

            /**
             * Default color map
             *
             * @see https://mochajs.org/api/module-base#.colors
             */
            const colors: ColorMap;

            /**
             * Default color map
             *
             * @see https://mochajs.org/api/module-base#.colors
             */
            interface ColorMap {
                // added by Base
                pass: number;
                fail: number;
                "bright pass": number;
                "bright fail": number;
                "bright yellow": number;
                pending: number;
                suite: number;
                "error title": number;
                "error message": number;
                "error stack": number;
                checkmark: number;
                fast: number;
                medium: number;
                slow: number;
                green: number;
                light: number;
                "diff gutter": number;
                "diff added": number;
                "diff removed": number;

                // added by Progress
                progress: number;

                // added by Landing
                plane: number;
                "plane crash": number;
                runway: number;

                [key: string]: number;
            }

            /**
             * Default symbol map
             *
             * @see https://mochajs.org/api/module-base#.symbols
             */
            const symbols: SymbolMap;

            /**
             * Default symbol map
             *
             * @see https://mochajs.org/api/module-base#.symbols
             */
            interface SymbolMap {
                ok: string;
                err: string;
                dot: string;
                comma: string;
                bang: string;
                [key: string]: string;
            }

            /**
             * Color `str` with the given `type` (from `colors`)
             *
             * @see https://mochajs.org/api/module-base#.color
             */
            function color(type: string, str: string): string;

            /**
             * Expose terminal window size
             *
             * @see https://mochajs.org/api/module-base#.window
             */
            const window: {
                width: number;
            };

            /**
             * ANSI TTY control sequences common among reporters.
             *
             * @see https://mochajs.org/api/module-base#.cursor
             */
            namespace cursor {
                /**
                 * Hides the cursor
                 */
                function hide(): void;

                /**
                 * Shows the cursor
                 */
                function show(): void;

                /**
                 * Deletes the current line
                 */
                function deleteLine(): void;

                /**
                 * Moves to the beginning of the line
                 */
                function beginningOfLine(): void;

                /**
                 * Clears the line and moves to the beginning of the line.
                 */
                function CR(): void;
            }

            /**
             * Returns a diff between two strings with colored ANSI output.
             *
             * @see https://mochajs.org/api/module-base#.generateDiff
             */
            function generateDiff(actual: string, expected: string): string;

            /**
             * Output the given `failures` as a list.
             *
             * @see https://mochajs.org/api/Mocha.reporters.Base.html#.exports.list1
             */
            function list(failures: Test[]): void;
        }

        /**
         * Initialize a new `Dot` matrix test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Dot.html
         */
        class Dot extends Base {
        }

        /**
         * Initialize a new `Doc` reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Doc.html
         */
        class Doc extends Base {
        }

        /**
         * Initialize a new `TAP` test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.TAP.html
         */
        class TAP extends Base {
        }

        /**
         * Initialize a new `JSON` reporter
         *
         * @see https://mochajs.org/api/Mocha.reporters.JSON.html
         */
        class JSON extends Base {
        }

        /**
         * Initialize a new `HTML` reporter.
         *
         * - _This reporter cannot be used on the console._
         *
         * @see https://mochajs.org/api/Mocha.reporters.HTML.html
         */
        class HTML extends Base {
            /**
             * Provide suite URL.
             *
             * @see https://mochajs.org/api/Mocha.reporters.HTML.html#suiteURL
             */
            suiteURL(suite: Suite): string;

            /**
             * Provide test URL.
             *
             * @see https://mochajs.org/api/Mocha.reporters.HTML.html#testURL
             */
            testURL(test: Test): string;

            /**
             * Adds code toggle functionality for the provided test's list element.
             *
             * @see https://mochajs.org/api/Mocha.reporters.HTML.html#addCodeToggle
             */
            addCodeToggle(el: HTMLLIElement, contents: string): void;
        }

        /**
         * Initialize a new `List` test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.List.html
         */
        class List extends Base {
        }

        /**
         * Initialize a new `Min` minimal test reporter (best used with --watch).
         *
         * @see https://mochajs.org/api/Mocha.reporters.Min.html
         */
        class Min extends Base {
        }

        /**
         * Initialize a new `Spec` test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Spec.html
         */
        class Spec extends Base {
        }

        /**
         * Initialize a new `NyanCat` test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Nyan.html
         */
        class Nyan extends Base {
            private colorIndex;
            private numberOfLines;
            private rainbowColors;
            private scoreboardWidth;
            private tick;
            private trajectories;
            private trajectoryWidthMax;
            private draw;
            private drawScoreboard;
            private appendRainbow;
            private drawRainbow;
            private drawNyanCat;
            private face;
            private cursorUp;
            private cursorDown;
            private generateColors;
            private rainbowify;
        }

        /**
         * Initialize a new `XUnit` test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.XUnit.html
         */
        class XUnit extends Base {
            constructor(runner: Runner, options?: XUnit.MochaOptions);
            /** @deprecated Use the overload that accepts `Mocha.Runner` instead. */
            constructor(runner: IRunner, options?: XUnit.MochaOptions);

            /**
             * Override done to close the stream (if it's a file).
             *
             * @see https://mochajs.org/api/Mocha.reporters.XUnit.html#done
             */
            done(failures: number, fn: (failures: number) => void): void;

            /**
             * Write out the given line.
             *
             * @see https://mochajs.org/api/Mocha.reporters.XUnit.html#write
             */
            write(line: string): void;

            /**
             * Output tag for the given `test.`
             *
             * @see https://mochajs.org/api/Mocha.reporters.XUnit.html#test
             */
            test(test: Test): void;
        }

        namespace XUnit {
            interface MochaOptions extends Mocha.MochaOptions {
                reporterOptions?: ReporterOptions;
            }

            interface ReporterOptions {
                output?: string;
                suiteName?: string;
            }
        }

        /**
         * Initialize a new `Markdown` test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Markdown.html
         */
        class Markdown extends Base {
        }

        /**
         * Initialize a new `Progress` bar test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Progress.html
         */
        class Progress extends Base {
            constructor(runner: Runner, options?: Progress.MochaOptions);
            /** @deprecated Use the overload that accepts `Mocha.Runner` instead. */
            constructor(runner: IRunner, options?: Progress.MochaOptions);
        }

        namespace Progress {
            interface MochaOptions extends Mocha.MochaOptions {
                reporterOptions?: ReporterOptions;
            }

            interface ReporterOptions {
                open?: string;
                complete?: string;
                incomplete?: string;
                close?: string;
                verbose?: boolean;
            }
        }

        /**
         * Initialize a new `Landing` reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.Landing.html
         */
        class Landing extends Base {
        }

        /**
         * Initialize a new `JSONStream` test reporter.
         *
         * @see https://mochajs.org/api/Mocha.reporters.JSONStream.html
         */
        class JSONStream extends Base {
        }

        // value-only aliases
        const base: typeof Base;
        const dot: typeof Dot;
        const doc: typeof Doc;
        const tap: typeof TAP;
        const json: typeof JSON;
        const html: typeof HTML;
        const list: typeof List;
        const spec: typeof Spec;
        const nyan: typeof Nyan;
        const xunit: typeof XUnit;
        const markdown: typeof Markdown;
        const progress: typeof Progress;
        const landing: typeof Landing;
        // NOTE: not possible to type this correctly:
        // const "json-stream": typeof JSONStream;
    }

    /**
     * Initialize a new `Runnable` with the given `title` and callback `fn`.
     *
     * @see https://mochajs.org/api/Runnable.html
     */
    class Runnable {
        private _slow;
        private _enableTimeouts;
        private _retries;
        private _currentRetry;
        private _timeout;
        private _timeoutError;

        constructor(title: string, fn?: Func | AsyncFunc);

        title: string;
        fn: Func | AsyncFunc | undefined;
        body: string;
        async: boolean;
        sync: boolean;
        timedOut: boolean;
        pending: boolean;
        duration?: number;
        parent?: Suite;
        state?: "failed" | "passed";
        timer?: any;
        ctx?: Context;
        callback?: Done;
        allowUncaught?: boolean;
        file?: string;

        /**
         * Get test timeout.
         *
         * @see https://mochajs.org/api/Runnable.html#timeout
         */
        timeout(): number;

        /**
         * Set test timeout.
         *
         * @see https://mochajs.org/api/Runnable.html#timeout
         */
        timeout(ms: string | number): this;

        /**
         * Get test slowness threshold.
         *
         * @see https://mochajs.org/api/Runnable.html#slow
         */
        slow(): number;

        /**
         * Set test slowness threshold.
         *
         * @see https://mochajs.org/api/Runnable.html#slow
         */
        slow(ms: string | number): this;

        /**
         * Get whether timeouts are enabled.
         *
         * @see https://mochajs.org/api/Runnable.html#enableTimeouts
         */
        enableTimeouts(): boolean;

        /**
         * Set whether timeouts are enabled.
         *
         * @see https://mochajs.org/api/Runnable.html#enableTimeouts
         */
        enableTimeouts(enabled: boolean): this;

        /**
         * Halt and mark as pending.
         */
        skip(): never;

        /**
         * Check if this runnable or its parent suite is marked as pending.
         *
         * @see https://mochajs.org/api/Runnable.html#isPending
         */
        isPending(): boolean;

        /**
         * Return `true` if this Runnable has failed.
         */
        isFailed(): boolean;

        /**
         * Return `true` if this Runnable has passed.
         */
        isPassed(): boolean;

        /**
         * Set or get number of retries.
         *
         * @see https://mochajs.org/api/Runnable.html#retries
         */
        retries(): number;

        /**
         * Set or get number of retries.
         *
         * @see https://mochajs.org/api/Runnable.html#retries
         */
        retries(n: number): void;

        /**
         * Set or get current retry
         *
         * @see https://mochajs.org/api/Runnable.html#currentRetry
         */
        protected currentRetry(): number;

        /**
         * Set or get current retry
         *
         * @see https://mochajs.org/api/Runnable.html#currentRetry
         */
        protected currentRetry(n: number): void;

        /**
         * Return the full title generated by recursively concatenating the parent's full title.
         */
        fullTitle(): string;

        /**
         * Return the title path generated by concatenating the parent's title path with the title.
         */
        titlePath(): string[];

        /**
         * Clear the timeout.
         *
         * @see https://mochajs.org/api/Runnable.html#clearTimeout
         */
        clearTimeout(): void;

        /**
         * Inspect the runnable void of private properties.
         *
         * @see https://mochajs.org/api/Runnable.html#inspect
         */
        inspect(): string;

        /**
         * Reset the timeout.
         *
         * @see https://mochajs.org/api/Runnable.html#resetTimeout
         */
        resetTimeout(): void;

        /**
         * Get a list of whitelisted globals for this test run.
         *
         * @see https://mochajs.org/api/Runnable.html#globals
         */
        globals(): string[];

        /**
         * Set a list of whitelisted globals for this test run.
         *
         * @see https://mochajs.org/api/Runnable.html#globals
         */
        globals(globals: ReadonlyArray<string>): void;

        /**
         * Run the test and invoke `fn(err)`.
         *
         * @see https://mochajs.org/api/Runnable.html#run
         */
        run(fn: Done): void;
    }

    // #region Runnable "error" event
    interface Runnable extends NodeJS.EventEmitter {
        on(event: "error", listener: (error: any) => void): this;
        once(event: "error", listener: (error: any) => void): this;
        addListener(event: "error", listener: (error: any) => void): this;
        removeListener(event: "error", listener: (error: any) => void): this;
        prependListener(event: "error", listener: (error: any) => void): this;
        prependOnceListener(event: "error", listener: (error: any) => void): this;
        emit(name: "error", error: any): boolean;
    }
    // #endregion Runnable "error" event
    // #region Runnable untyped events
    interface Runnable extends NodeJS.EventEmitter {
        on(event: string, listener: (...args: any[]) => void): this;
        once(event: string, listener: (...args: any[]) => void): this;
        addListener(event: string, listener: (...args: any[]) => void): this;
        removeListener(event: string, listener: (...args: any[]) => void): this;
        prependListener(event: string, listener: (...args: any[]) => void): this;
        prependOnceListener(event: string, listener: (...args: any[]) => void): this;
        emit(name: string, ...args: any[]): boolean;
    }
    // #endregion Runnable untyped events

    /**
     * Test context
     *
     * @see https://mochajs.org/api/module-Context.html#~Context
     */
    class Context {
        private _runnable;

        test?: Runnable;
        currentTest?: Test;

        /**
         * Get the context `Runnable`.
         */
        runnable(): Runnable;

        /**
         * Set the context `Runnable`.
         */
        runnable(runnable: Runnable): this;
        /** @deprecated Use the overload that accepts `Mocha.Runnable` instead. */
        runnable(runnable: IRunnable): this;

        /**
         * Get test timeout.
         */
        timeout(): number;

        /**
         * Set test timeout.
         */
        timeout(ms: string | number): this;

        /**
         * Get whether timeouts are enabled.
         */
        enableTimeouts(): boolean;

        /**
         * Set whether timeouts are enabled.
         */
        enableTimeouts(enabled: boolean): this;

        /**
         * Get test slowness threshold.
         */
        slow(): number;

        /**
         * Set test slowness threshold.
         */
        slow(ms: string | number): this;

        /**
         * Mark a test as skipped.
         */
        skip(): never;

        /**
         * Get the number of allowed retries on failed tests.
         */
        retries(): number;

        /**
         * Set the number of allowed retries on failed tests.
         */
        retries(n: number): this;

        [key: string]: any;
    }

    interface RunnerConstants {
        readonly EVENT_HOOK_BEGIN: 'hook';
        readonly EVENT_HOOK_END: 'hook end';
        readonly EVENT_RUN_BEGIN: 'start';
        readonly EVENT_DELAY_BEGIN: 'waiting';
        readonly EVENT_DELAY_END: 'ready';
        readonly EVENT_RUN_END: 'end';
        readonly EVENT_SUITE_BEGIN: 'suite';
        readonly EVENT_SUITE_END: 'suite end';
        readonly EVENT_TEST_BEGIN: 'test';
        readonly EVENT_TEST_END: 'test end';
        readonly EVENT_TEST_FAIL: 'fail';
        readonly EVENT_TEST_PASS: 'pass';
        readonly EVENT_TEST_PENDING: 'pending';
        readonly EVENT_TEST_RETRY: 'retry';
    }

    /**
     * Initialize a `Runner` for the given `suite`.
     *
     * @see https://mochajs.org/api/Mocha.Runner.html
     */
    class Runner {
        private _globals;
        private _abort;
        private _delay;
        private _defaultGrep;
        private next;
        private hookErr;
        private prevGlobalsLength;
        private nextSuite;

        static readonly constants: RunnerConstants;

        constructor(suite: Suite, delay: boolean);

        /** @deprecated Use the overload that accepts `Mocha.Suite` instead. */
        constructor(suite: ISuite, delay: boolean);

        suite: Suite;
        started: boolean;
        total: number;
        failures: number;
        asyncOnly?: boolean;
        allowUncaught?: boolean;
        fullStackTrace?: boolean;
        forbidOnly?: boolean;
        forbidPending?: boolean;
        ignoreLeaks?: boolean;
        test?: Test;
        currentRunnable?: Runnable;
        stats?: Stats; // added by reporters

        /**
         * Run tests with full titles matching `re`. Updates runner.total
         * with number of tests matched.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#grep
         */
        grep(re: RegExp, invert: boolean): this;

        /**
         * Returns the number of tests matching the grep search for the
         * given suite.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#grepTotal
         */
        grepTotal(suite: Suite): number;

        /** @deprecated Use the overload that accepts `Mocha.Suite` instead. */
        grepTotal(suite: ISuite): number;

        /**
         * Gets the allowed globals.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#globals
         */
        globals(): string[];

        /**
         * Allow the given `arr` of globals.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#globals
         */
        globals(arr: ReadonlyArray<string>): this;

        /**
         * Run the root suite and invoke `fn(failures)` on completion.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#run
         */
        run(fn?: (failures: number) => void): this;

        /**
         * Cleanly abort execution.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#.Runner#abort
         */
        abort(): this;

        /**
         * Handle uncaught exceptions.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#uncaught
         */
        uncaught(err: any): void;

        /**
         * Wrapper for setImmediate, process.nextTick, or browser polyfill.
         */
        protected static immediately(callback: Function): void;

        /**
         * Return a list of global properties.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#globalProps
         */
        protected globalProps(): string[];

        /**
         * Check for global variable leaks.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#checkGlobals
         */
        protected checkGlobals(test: Test): void;

        /**
         * Fail the given `test`.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#fail
         */
        protected fail(test: Test, err: any): void;

        /**
         * Fail the given `hook` with `err`.
         *
         * Hook failures work in the following pattern:
         * - If bail, then exit
         * - Failed `before` hook skips all tests in a suite and subsuites,
         *   but jumps to corresponding `after` hook
         * - Failed `before each` hook skips remaining tests in a
         *   suite and jumps to corresponding `after each` hook,
         *   which is run only once
         * - Failed `after` hook does not alter
         *   execution order
         * - Failed `after each` hook skips remaining tests in a
         *   suite and subsuites, but executes other `after each`
         *   hooks
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#failHook
         */
        protected failHook(hook: Hook, err: any): void;

        /**
         * Run hook `name` callbacks and then invoke `fn()`.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#hook
         */
        protected hook(name: string, fn: () => void): void;

        /**
         * Run hook `name` for the given array of `suites`
         * in order, and callback `fn(err, errSuite)`.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#hooks
         */
        protected hooks(name: string, suites: Suite[], fn: (err?: any, errSuite?: Suite) => void): void;

        /**
         * Run hooks from the top level down.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#hookUp
         */
        protected hookUp(name: string, fn: (err?: any, errSuite?: Suite) => void): void;

        /**
         * Run hooks from the bottom up.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#hookDown
         */
        protected hookDown(name: string, fn: (err?: any, errSuite?: Suite) => void): void;

        /**
         * Return an array of parent Suites from closest to furthest.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#parents
         */
        protected parents(): Suite[];

        /**
         * Run the current test and callback `fn(err)`.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#runTest
         */
        protected runTest(fn: Done): any;

        /**
         * Run tests in the given `suite` and invoke the callback `fn()` when complete.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#runTests
         */
        protected runTests(suite: Suite, fn: (errSuite?: Suite) => void): void;

        /**
         * Run the given `suite` and invoke the callback `fn()` when complete.
         *
         * @see https://mochajs.org/api/Mocha.Runner.html#runSuite
         */
        protected runSuite(suite: Suite, fn: (errSuite?: Suite) => void): void;
    }

    // #region Runner "waiting" event
    interface Runner {
        on(event: "waiting", listener: (rootSuite: Suite) => void): this;
        once(event: "waiting", listener: (rootSuite: Suite) => void): this;
        addListener(event: "waiting", listener: (rootSuite: Suite) => void): this;
        removeListener(event: "waiting", listener: (rootSuite: Suite) => void): this;
        prependListener(event: "waiting", listener: (rootSuite: Suite) => void): this;
        prependOnceListener(event: "waiting", listener: (rootSuite: Suite) => void): this;
        emit(name: "waiting", rootSuite: Suite): boolean;
    }
    // #endregion Runner "waiting" event
    // #region Runner "start" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "start", listener: () => void): this;
        once(event: "start", listener: () => void): this;
        addListener(event: "start", listener: () => void): this;
        removeListener(event: "start", listener: () => void): this;
        prependListener(event: "start", listener: () => void): this;
        prependOnceListener(event: "start", listener: () => void): this;
        emit(name: "start"): boolean;
    }
    // #endregion Runner "start" event
    // #region Runner "end" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "end", listener: () => void): this;
        once(event: "end", listener: () => void): this;
        addListener(event: "end", listener: () => void): this;
        removeListener(event: "end", listener: () => void): this;
        prependListener(event: "end", listener: () => void): this;
        prependOnceListener(event: "end", listener: () => void): this;
        emit(name: "end"): boolean;
    }
    // #endregion Runner "end" event
    // #region Runner "suite" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "suite", listener: (suite: Suite) => void): this;
        once(event: "suite", listener: (suite: Suite) => void): this;
        addListener(event: "suite", listener: (suite: Suite) => void): this;
        removeListener(event: "suite", listener: (suite: Suite) => void): this;
        prependListener(event: "suite", listener: (suite: Suite) => void): this;
        prependOnceListener(event: "suite", listener: (suite: Suite) => void): this;
        emit(name: "suite", suite: Suite): boolean;
    }
    // #endregion Runner "suite" event
    // #region Runner "suite end" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "suite end", listener: (suite: Suite) => void): this;
        once(event: "suite end", listener: (suite: Suite) => void): this;
        addListener(event: "suite end", listener: (suite: Suite) => void): this;
        removeListener(event: "suite end", listener: (suite: Suite) => void): this;
        prependListener(event: "suite end", listener: (suite: Suite) => void): this;
        prependOnceListener(event: "suite end", listener: (suite: Suite) => void): this;
        emit(name: "suite end", suite: Suite): boolean;
    }
    // #endregion Runner "suite end" event
    // #region Runner "test" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "test", listener: (test: Test) => void): this;
        once(event: "test", listener: (test: Test) => void): this;
        addListener(event: "test", listener: (test: Test) => void): this;
        removeListener(event: "test", listener: (test: Test) => void): this;
        prependListener(event: "test", listener: (test: Test) => void): this;
        prependOnceListener(event: "test", listener: (test: Test) => void): this;
        emit(name: "test", test: Test): boolean;
    }
    // #endregion Runner "test" event
    // #region Runner "test end" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "test end", listener: (test: Test) => void): this;
        once(event: "test end", listener: (test: Test) => void): this;
        addListener(event: "test end", listener: (test: Test) => void): this;
        removeListener(event: "test end", listener: (test: Test) => void): this;
        prependListener(event: "test end", listener: (test: Test) => void): this;
        prependOnceListener(event: "test end", listener: (test: Test) => void): this;
        emit(name: "test end", test: Test): boolean;
    }
    // #endregion Runner "test end" event
    // #region Runner "hook" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "hook", listener: (hook: Hook) => void): this;
        once(event: "hook", listener: (hook: Hook) => void): this;
        addListener(event: "hook", listener: (hook: Hook) => void): this;
        removeListener(event: "hook", listener: (hook: Hook) => void): this;
        prependListener(event: "hook", listener: (hook: Hook) => void): this;
        prependOnceListener(event: "hook", listener: (hook: Hook) => void): this;
        emit(name: "hook", hook: Hook): boolean;
    }
    // #endregion Runner "hook" event
    // #region Runner "hook end" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "hook end", listener: (hook: Hook) => void): this;
        once(event: "hook end", listener: (hook: Hook) => void): this;
        addListener(event: "hook end", listener: (hook: Hook) => void): this;
        removeListener(event: "hook end", listener: (hook: Hook) => void): this;
        prependListener(event: "hook end", listener: (hook: Hook) => void): this;
        prependOnceListener(event: "hook end", listener: (hook: Hook) => void): this;
        emit(name: "hook end", hook: Hook): boolean;
    }
    // #endregion Runner "hook end" event
    // #region Runner "pass" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "pass", listener: (test: Test) => void): this;
        once(event: "pass", listener: (test: Test) => void): this;
        addListener(event: "pass", listener: (test: Test) => void): this;
        removeListener(event: "pass", listener: (test: Test) => void): this;
        prependListener(event: "pass", listener: (test: Test) => void): this;
        prependOnceListener(event: "pass", listener: (test: Test) => void): this;
        emit(name: "pass", test: Test): boolean;
    }
    // #endregion Runner "pass" event
    // #region Runner "fail" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "fail", listener: (test: Test, err: any) => void): this;
        once(event: "fail", listener: (test: Test, err: any) => void): this;
        addListener(event: "fail", listener: (test: Test, err: any) => void): this;
        removeListener(event: "fail", listener: (test: Test, err: any) => void): this;
        prependListener(event: "fail", listener: (test: Test, err: any) => void): this;
        prependOnceListener(event: "fail", listener: (test: Test, err: any) => void): this;
        emit(name: "fail", test: Test, err: any): boolean;
    }
    // #endregion Runner "fail" event
    // #region Runner "pending" event
    interface Runner extends NodeJS.EventEmitter {
        on(event: "pending", listener: (test: Test) => void): this;
        once(event: "pending", listener: (test: Test) => void): this;
        addListener(event: "pending", listener: (test: Test) => void): this;
        removeListener(event: "pending", listener: (test: Test) => void): this;
        prependListener(event: "pending", listener: (test: Test) => void): this;
        prependOnceListener(event: "pending", listener: (test: Test) => void): this;
        emit(name: "pending", test: Test): boolean;
    }
    // #endregion Runner "pending" event
    // #region Runner untyped events
    interface Runner extends NodeJS.EventEmitter {
        on(event: string, listener: (...args: any[]) => void): this;
        once(event: string, listener: (...args: any[]) => void): this;
        addListener(event: string, listener: (...args: any[]) => void): this;
        removeListener(event: string, listener: (...args: any[]) => void): this;
        prependListener(event: string, listener: (...args: any[]) => void): this;
        prependOnceListener(event: string, listener: (...args: any[]) => void): this;
        emit(name: string, ...args: any[]): boolean;
    }
    // #endregion Runner untyped events

    interface SuiteConstants {
        readonly EVENT_FILE_POST_REQUIRE: 'post-require';
        readonly EVENT_FILE_PRE_REQUIRE: 'pre-require';
        readonly EVENT_FILE_REQUIRE: 'require';
        readonly EVENT_ROOT_SUITE_RUN: 'run';

        readonly HOOK_TYPE_AFTER_ALL: 'afterAll';
        readonly HOOK_TYPE_AFTER_EACH: 'afterEach';
        readonly HOOK_TYPE_BEFORE_ALL: 'beforeAll';
        readonly HOOK_TYPE_BEFORE_EACH: 'beforeEach';

        readonly EVENT_SUITE_ADD_HOOK_AFTER_ALL: 'afterAll';
        readonly EVENT_SUITE_ADD_HOOK_AFTER_EACH: 'afterEach';
        readonly EVENT_SUITE_ADD_HOOK_BEFORE_ALL: 'beforeAll';
        readonly EVENT_SUITE_ADD_HOOK_BEFORE_EACH: 'beforeEach';
        readonly EVENT_SUITE_ADD_SUITE: 'suite';
        readonly EVENT_SUITE_ADD_TEST: 'test';
    }

    /**
     * Initialize a new `Suite` with the given `title` and `ctx`.
     *
     * @see https://mochajs.org/api/Mocha.Suite.html
     */
    class Suite {
        private _beforeEach;
        private _beforeAll;
        private _afterEach;
        private _afterAll;
        private _timeout;
        private _enableTimeouts;
        private _slow;
        private _bail;
        private _retries;
        private _onlyTests;
        private _onlySuites;

        static readonly constants: SuiteConstants;

        constructor(title: string, parentContext?: Context);
        /** @deprecated Use the overload that accepts `Mocha.Context` instead. */
        constructor(title: string, parentContext?: IContext);

        ctx: Context;
        suites: Suite[];
        tests: Test[];
        pending: boolean;
        file?: string;
        root: boolean;
        delayed: boolean;
        parent: Suite | undefined;
        title: string;

        /**
         * Create a new `Suite` with the given `title` and parent `Suite`. When a suite
         * with the same title is already present, that suite is returned to provide
         * nicer reporter and more flexible meta-testing.
         *
         * @see https://mochajs.org/api/mocha#.exports.create
         */
        static create(parent: Suite, title: string): Suite;
        /** @deprecated Use the overload that accepts `Mocha.Suite` instead. */
        static create(parent: ISuite, title: string): Suite;

        /**
         * Return a clone of this `Suite`.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#clone
         */
        clone(): Suite;

        /**
         * Get timeout `ms`.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#timeout
         */
        timeout(): number;

        /**
         * Set timeout `ms` or short-hand such as "2s".
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#timeout
         */
        timeout(ms: string | number): this;

        /**
         * Get number of times to retry a failed test.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#retries
         */
        retries(): number;

        /**
         * Set number of times to retry a failed test.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#retries
         */
        retries(n: string | number): this;

        /**
         * Get whether timeouts are enabled.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#enableTimeouts
         */
        enableTimeouts(): boolean;

        /**
         * Set whether timeouts are `enabled`.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#enableTimeouts
         */
        enableTimeouts(enabled: boolean): this;

        /**
         * Get slow `ms`.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#slow
         */
        slow(): number;

        /**
         * Set slow `ms` or short-hand such as "2s".
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#slow
         */
        slow(ms: string | number): this;

        /**
         * Get whether to bail after first error.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#bail
         */
        bail(): boolean;

        /**
         * Set whether to bail after first error.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#bail
         */
        bail(bail: boolean): this;

        /**
         * Check if this suite or its parent suite is marked as pending.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#isPending
         */
        isPending(): boolean;

        /**
         * Run `fn(test[, done])` before running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll
         */
        beforeAll(fn?: Func): this;

        /**
         * Run `fn(test[, done])` before running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll
         */
        beforeAll(fn?: AsyncFunc): this;

        /**
         * Run `fn(test[, done])` before running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll
         */
        beforeAll(title: string, fn?: Func): this;

        /**
         * Run `fn(test[, done])` before running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeAll
         */
        beforeAll(title: string, fn?: AsyncFunc): this;

        /**
         * Run `fn(test[, done])` after running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterAll
         */
        afterAll(fn?: Func): this;

        /**
         * Run `fn(test[, done])` after running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterAll
         */
        afterAll(fn?: AsyncFunc): this;

        /**
         * Run `fn(test[, done])` after running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterAll
         */
        afterAll(title: string, fn?: Func): this;

        /**
         * Run `fn(test[, done])` after running tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterAll
         */
        afterAll(title: string, fn?: AsyncFunc): this;

        /**
         * Run `fn(test[, done])` before each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach
         */
        beforeEach(fn?: Func): this;

        /**
         * Run `fn(test[, done])` before each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach
         */
        beforeEach(fn?: AsyncFunc): this;

        /**
         * Run `fn(test[, done])` before each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach
         */
        beforeEach(title: string, fn?: Func): this;

        /**
         * Run `fn(test[, done])` before each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#beforeEach
         */
        beforeEach(title: string, fn?: AsyncFunc): this;

        /**
         * Run `fn(test[, done])` after each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterEach
         */
        afterEach(fn?: Func): this;

        /**
         * Run `fn(test[, done])` after each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterEach
         */
        afterEach(fn?: AsyncFunc): this;

        /**
         * Run `fn(test[, done])` after each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterEach
         */
        afterEach(title: string, fn?: Func): this;

        /**
         * Run `fn(test[, done])` after each test case.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#afterEach
         */
        afterEach(title: string, fn?: AsyncFunc): this;

        /**
         * Add a test `suite`.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#addSuite
         */
        addSuite(suite: Suite): this;
        /** @deprecated Use the overload that accepts `Mocha.ISuite` instead. */
        addSuite(suite: ISuite): this;

        /**
         * Add a `test` to this suite.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#addTest
         */
        addTest(test: Test): this;
        /** @deprecated Use the overload that accepts `Mocha.ITest` instead. */
        addTest(test: ITest): this;

        /**
         * Return the full title generated by recursively concatenating the parent's
         * full title.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#.Suite#fullTitle
         */
        fullTitle(): string;

        /**
         * Return the title path generated by recursively concatenating the parent's
         * title path.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#.Suite#titlePath
         */
        titlePath(): string[];

        /**
         * Return the total number of tests.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#.Suite#total
         */
        total(): number;

        /**
         * Iterates through each suite recursively to find all tests. Applies a
         * function in the format `fn(test)`.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#eachTest
         */
        eachTest(fn: (test: Test) => void): this;

        /**
         * This will run the root suite if we happen to be running in delayed mode.
         *
         * @see https://mochajs.org/api/Mocha.Suite.html#run
         */
        run(): void;

        /**
         * Generic hook-creator.
         */
        protected _createHook(title: string, fn?: Func | AsyncFunc): Hook;
    }

    // #region Suite "beforeAll" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "beforeAll", listener: (hook: Hook) => void): this;
        once(event: "beforeAll", listener: (hook: Hook) => void): this;
        addListener(event: "beforeAll", listener: (hook: Hook) => void): this;
        removeListener(event: "beforeAll", listener: (hook: Hook) => void): this;
        prependListener(event: "beforeAll", listener: (hook: Hook) => void): this;
        prependOnceListener(event: "beforeAll", listener: (hook: Hook) => void): this;
        emit(name: "beforeAll", hook: Hook): boolean;
    }
    // #endregion Suite "beforeAll" event
    // #region Suite "afterAll" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "afterAll", listener: (hook: Hook) => void): this;
        once(event: "afterAll", listener: (hook: Hook) => void): this;
        addListener(event: "afterAll", listener: (hook: Hook) => void): this;
        removeListener(event: "afterAll", listener: (hook: Hook) => void): this;
        prependListener(event: "afterAll", listener: (hook: Hook) => void): this;
        prependOnceListener(event: "afterAll", listener: (hook: Hook) => void): this;
        emit(name: "afterAll", hook: Hook): boolean;
    }
    // #endregion Suite "afterAll" event
    // #region Suite "beforeEach" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "beforeEach", listener: (hook: Hook) => void): this;
        once(event: "beforeEach", listener: (hook: Hook) => void): this;
        addListener(event: "beforeEach", listener: (hook: Hook) => void): this;
        removeListener(event: "beforeEach", listener: (hook: Hook) => void): this;
        prependListener(event: "beforeEach", listener: (hook: Hook) => void): this;
        prependOnceListener(event: "beforeEach", listener: (hook: Hook) => void): this;
        emit(name: "beforeEach", hook: Hook): boolean;
    }
    // #endregion Suite "beforeEach" event
    // #region Suite "afterEach" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "afterEach", listener: (hook: Hook) => void): this;
        once(event: "afterEach", listener: (hook: Hook) => void): this;
        addListener(event: "afterEach", listener: (hook: Hook) => void): this;
        removeListener(event: "afterEach", listener: (hook: Hook) => void): this;
        prependListener(event: "afterEach", listener: (hook: Hook) => void): this;
        prependOnceListener(event: "afterEach", listener: (hook: Hook) => void): this;
        emit(name: "afterEach", hook: Hook): boolean;
    }
    // #endregion Suite "afterEach" event
    // #region Suite "suite" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "suite", listener: (suite: Suite) => void): this;
        once(event: "suite", listener: (suite: Suite) => void): this;
        addListener(event: "suite", listener: (suite: Suite) => void): this;
        removeListener(event: "suite", listener: (suite: Suite) => void): this;
        prependListener(event: "suite", listener: (suite: Suite) => void): this;
        prependOnceListener(event: "suite", listener: (suite: Suite) => void): this;
        emit(name: "suite", suite: Suite): boolean;
    }
    // #endregion Suite "suite" event
    // #region Suite "test" event
    interface Suite {
        on(event: "test", listener: (test: Test) => void): this;
        once(event: "test", listener: (test: Test) => void): this;
        addListener(event: "test", listener: (test: Test) => void): this;
        removeListener(event: "test", listener: (test: Test) => void): this;
        prependListener(event: "test", listener: (test: Test) => void): this;
        prependOnceListener(event: "test", listener: (test: Test) => void): this;
        emit(name: "test", test: Test): boolean;
    }
    // #endregion Suite "test" event
    // #region Suite "run" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "run", listener: () => void): this;
        once(event: "run", listener: () => void): this;
        addListener(event: "run", listener: () => void): this;
        removeListener(event: "run", listener: () => void): this;
        prependListener(event: "run", listener: () => void): this;
        prependOnceListener(event: "run", listener: () => void): this;
        emit(name: "run"): boolean;
    }
    // #endregion Suite "run" event
    // #region Suite "pre-require" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        once(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        addListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        removeListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        prependListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        prependOnceListener(event: "pre-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        emit(name: "pre-require", context: MochaGlobals, file: string, mocha: Mocha): boolean;
    }
    // #endregion Suite "pre-require" event
    // #region Suite "require" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this;
        once(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this;
        addListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this;
        removeListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this;
        prependListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this;
        prependOnceListener(event: "require", listener: (module: any, file: string, mocha: Mocha) => void): this;
        emit(name: "require", module: any, file: string, mocha: Mocha): boolean;
    }
    // #endregion Suite "require" event
    // #region Suite "post-require" event
    interface Suite extends NodeJS.EventEmitter {
        on(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        once(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        addListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        removeListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        prependListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        prependOnceListener(event: "post-require", listener: (context: MochaGlobals, file: string, mocha: Mocha) => void): this;
        emit(name: "post-require", context: MochaGlobals, file: string, mocha: Mocha): boolean;
    }
    // #endregion Suite "post-require" event
    // #region Suite untyped events
    interface Suite extends NodeJS.EventEmitter {
        on(event: string, listener: (...args: any[]) => void): this;
        once(event: string, listener: (...args: any[]) => void): this;
        addListener(event: string, listener: (...args: any[]) => void): this;
        removeListener(event: string, listener: (...args: any[]) => void): this;
        prependListener(event: string, listener: (...args: any[]) => void): this;
        prependOnceListener(event: string, listener: (...args: any[]) => void): this;
        emit(name: string, ...args: any[]): boolean;
    }
    // #endregion Runner untyped events

    /**
     * Initialize a new `Hook` with the given `title` and callback `fn`
     *
     * @see https://mochajs.org/api/Hook.html
     */
    class Hook extends Runnable {
        private _error;

        type: "hook";
        originalTitle?: string; // added by Runner

        /**
         * Get the test `err`.
         *
         * @see https://mochajs.org/api/Hook.html#error
         */
        error(): any;

        /**
         * Set the test `err`.
         *
         * @see https://mochajs.org/api/Hook.html#error
         */
        error(err: any): void;
    }

    /**
     * Initialize a new `Test` with the given `title` and callback `fn`.
     *
     * @see https://mochajs.org/api/Test.html
     */
    class Test extends Runnable {
        type: "test";
        speed?: "slow" | "medium" | "fast"; // added by reporters
        err?: Error; // added by reporters
        clone(): Test;
    }

    /**
     * Test statistics
     */
    interface Stats {
        suites: number;
        tests: number;
        passes: number;
        pending: number;
        failures: number;
        start?: Date;
        end?: Date;
        duration?: number;
    }

    type TestInterface = (suite: Suite) => void;

    interface ReporterConstructor {
        new (runner: Runner, options: MochaOptions): reporters.Base;
    }

    type Done = (err?: any) => void;

    /**
     * Callback function used for tests and hooks.
     */
    type Func = (this: Context, done: Done) => void;

    /**
     * Async callback function used for tests and hooks.
     */
    type AsyncFunc = (this: Context) => PromiseLike<any>;

    /**
     * Options to pass to Mocha.
     */
    interface MochaOptions {
        /** Test interfaces ("bdd", "tdd", "exports", etc.). */
        ui?: Interface;

        /**
         * Reporter constructor, built-in reporter name, or reporter module path. Defaults to
         * `"spec"`.
         */
        reporter?: string | ReporterConstructor;

        /** Options to pass to the reporter. */
        reporterOptions?: any;

        /** Array of accepted globals. */
        globals?: string[];

        /** timeout in milliseconds or time string like '1s'. */
        timeout?: number | string;

        enableTimeouts?: boolean;

        /** number of times to retry failed tests. */
        retries?: number;

        /** bail on the first test failure. */
        bail?: boolean;

        /** milliseconds to wait before considering a test slow. */
        slow?: number;

        /** ignore global leaks. */
        ignoreLeaks?: boolean;

        /** display the full stack trace on failure. */
        fullStackTrace?: boolean;

        /** string or regexp to filter tests with. */
        grep?: string | RegExp;

        /** Enable growl support. */
        growl?: boolean;

        /** Emit color output. */
        useColors?: boolean;

        /** Use inline diffs rather than +/-. */
        inlineDiffs?: boolean;

        /** Do not show diffs at all. */
        hideDiff?: boolean;

        asyncOnly?: boolean;
        delay?: boolean;
        forbidOnly?: boolean;
        forbidPending?: boolean;
        noHighlighting?: boolean;
        allowUncaught?: boolean;
    }

    interface MochaInstanceOptions extends MochaOptions {
        files?: string[];
    }

    /**
     * Variables added to the global scope by Mocha when run in the CLI.
     */
    interface MochaGlobals {
        /**
         * Execute before running tests.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#before
         */
        before: HookFunction;

        /**
         * Execute after running tests.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#after
         */
        after: HookFunction;

        /**
         * Execute before each test case.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#beforeEach
         */
        beforeEach: HookFunction;

        /**
         * Execute after each test case.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#afterEach
         */
        afterEach: HookFunction;

        /**
         * Describe a "suite" containing nested suites and tests.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        describe: SuiteFunction;

        /**
         * Describe a "suite" containing nested suites and tests.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        context: SuiteFunction;

        /**
         * Pending suite.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        xdescribe: PendingSuiteFunction;

        /**
         * Pending suite.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        xcontext: PendingSuiteFunction;

        /**
         * Describes a test case.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        it: TestFunction;

        /**
         * Describes a test case.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        specify: TestFunction;

        /**
         * Describes a pending test case.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        xit: PendingTestFunction;

        /**
         * Describes a pending test case.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        xspecify: PendingTestFunction;

        /**
         * Execute before running tests.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#before
         */
        suiteSetup: HookFunction;

        /**
         * Execute after running tests.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#after
         */
        suiteTeardown: HookFunction;

        /**
         * Execute before each test case.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#beforeEach
         */
        setup: HookFunction;

        /**
         * Execute after each test case.
         *
         * - _Only available when invoked via the mocha CLI._
         *
         * @see https://mochajs.org/api/global.html#afterEach
         */
        teardown: HookFunction;

        /**
         * Describe a "suite" containing nested suites and tests.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        suite: SuiteFunction;

        /**
         * Describes a test case.
         *
         * - _Only available when invoked via the mocha CLI._
         */
        test: TestFunction;

        run: typeof run;
    }

    /**
     * Third-party declarations that want to add new entries to the `Reporter` union can
     * contribute names here.
     */
    interface ReporterContributions {
        Base: never;
        base: never;
        Dot: never;
        dot: never;
        TAP: never;
        tap: never;
        JSON: never;
        json: never;
        HTML: never;
        html: never;
        List: never;
        list: never;
        Min: never;
        min: never;
        Spec: never;
        spec: never;
        Nyan: never;
        nyan: never;
        XUnit: never;
        xunit: never;
        Markdown: never;
        markdown: never;
        Progress: never;
        progress: never;
        Landing: never;
        landing: never;
        JSONStream: never;
        "json-stream": never;
    }

    type Reporter = keyof ReporterContributions;

    /**
     * Third-party declarations that want to add new entries to the `Interface` union can
     * contribute names here.
     */
    interface InterfaceContributions {
        bdd: never;
        tdd: never;
        qunit: never;
        exports: never;
    }

    type Interface = keyof InterfaceContributions;

    // #region Deprecations

    /** @deprecated use `Mocha.Context` instead. */
    interface IContext {
        test?: IRunnable;
        runnable(): IRunnable | undefined;
        /** @deprecated `.runnable()` returns `this` in `Mocha.Context`. */
        runnable(runnable: IRunnable): IContext;
        timeout(): number;
        /** @deprecated `.timeout()` returns `this` in `Mocha.Context`. */
        timeout(timeout: number): IContext;
        /** @deprecated `.enableTimeouts()` has additional overloads in `Mocha.Context`. */
        /** @deprecated `.enableTimeouts()` returns `this` in `Mocha.Context`. */
        enableTimeouts(enableTimeouts: boolean): IContext;
        /** @deprecated `.slow()` has additional overloads in `Mocha.Context`. */
        /** @deprecated `.slow()` returns `this` in `Mocha.Context`. */
        slow(slow: number): IContext;
        /** @deprecated `.skip()` returns `never` in `Mocha.Context`. */
        skip(): IContext;
        retries(): number;
        /** @deprecated `.retries()` returns `this` in `Mocha.Context`. */
        retries(retries: number): IContext;
    }

    /** @deprecated use `Mocha.Suite` instead. */
    interface ISuiteCallbackContext {
        /** @deprecated `.timeout()` has additional overloads in `Mocha.Suite`. */
        timeout(ms: number | string): this;
        /** @deprecated `.retries()` has additional overloads in `Mocha.Suite`. */
        retries(n: number): this;
        /** @deprecated `.slow()` has additional overloads in `Mocha.Suite`. */
        slow(ms: number): this;
    }

    /** @deprecated use `Mocha.Context` instead. */
    interface IHookCallbackContext {
        /** @deprecated `.skip()` returns `never` in `Mocha.Context`. */
        skip(): this;
        /** @deprecated `.timeout()` has additional overloads in `Mocha.Context`. */
        timeout(ms: number | string): this;
        [index: string]: any;
    }

    /** @deprecated use `Mocha.Context` instead. */
    interface ITestCallbackContext {
        /** @deprecated `.skip()` returns `never` in `Mocha.Context`. */
        skip(): this;
        /** @deprecated `.timeout()` has additional overloads in `Mocha.Context`. */
        timeout(ms: number | string): this;
        /** @deprecated `.retries()` has additional overloads in `Mocha.Context`. */
        retries(n: number): this;
        /** @deprecated `.slow()` has additional overloads in `Mocha.Context`. */
        slow(ms: number): this;
        [index: string]: any;
    }

    /** Partial interface for Mocha's `Runnable` class. */
    /** @deprecated use `Mocha.Runnable` instead. */
    interface IRunnable extends NodeJS.EventEmitter {
        title: string;
        /** @deprecated `.fn` has type `Func | AsyncFunc` in `Mocha.Runnable`. */
        fn: Function | undefined;
        async: boolean;
        sync: boolean;
        timedOut: boolean;
        /** @deprecated `.timeout()` has additional overloads in `Mocha.Runnable`. */
        timeout(n: number | string): this;
        duration?: number;
    }

    /** Partial interface for Mocha's `Suite` class. */
    /** @deprecated use `Mocha.Suite` instead. */
    interface ISuite {
        /** @deprecated `.ctx` has type `Mocha.Context` in `Mocha.Suite`. */
        ctx: IContext;
        /** @deprecated `.parent` has type `Mocha.Suite | undefined` in `Mocha.Suite`. */
        parent: ISuite | undefined;
        root: boolean;
        title: string;
        /** @deprecated `.suites` has type `Mocha.Suite[]` in `Mocha.Suite`. */
        suites: ISuite[];
        /** @deprecated `.tests` has type `Mocha.Test[]` in `Mocha.Suite`. */
        tests: ITest[];

        bail(): boolean;
        /** @deprecated `.bail()` returns `this` in `Mocha.Suite`. */
        bail(bail: boolean): ISuite;
        fullTitle(): string;
        retries(): number;
        /** @deprecated `.retries()` returns `this` in `Mocha.Suite`. */
        retries(retries: number): ISuite;
        slow(): number;
        /** @deprecated `.slow()` returns `this` in `Mocha.Suite`. */
        slow(slow: number): ISuite;
        timeout(): number;
        /** @deprecated `.timeout()` returns `this` in `Mocha.Suite`. */
        timeout(timeout: number): ISuite;
    }

    /** Partial interface for Mocha's `Test` class. */
    /** @deprecated use `Mocha.Test` instead. */
    interface ITest extends IRunnable {
        body?: string;
        file?: string;
        /** @deprecated `.parent` has type `Mocha.Suite | undefined` in `Mocha.Test`. */
        parent?: ISuite;
        pending: boolean;
        state?: 'failed' | 'passed';
        type: 'test';
        fullTitle(): string;
    }

    /** @deprecated use `Mocha.Hook` instead. */
    interface IHook extends IRunnable {
        /** @deprecated `.ctx` has type `Mocha.Context` in `Mocha.Runnable`. */
        ctx?: IContext;
        /** @deprecated `.parent` has type `Mocha.Suite` in `Mocha.Runnable`. */
        parent?: ISuite;
        type: 'hook';
        /** @deprecated `.error()` has additional overloads in `Mocha.Hook`. */
        error(err: Error): void;
    }

    /** @deprecated use `Mocha.Context` instead. */
    interface IBeforeAndAfterContext extends IHookCallbackContext {
        /** @deprecated `.currentTest` has type `Mocha.Test` in `Mocha.Context`. */
        currentTest?: ITest;
    }

    /** @deprecated use `Mocha.Stats` instead. */
    type IStats = Stats;

    /** Partial interface for Mocha's `Runner` class. */
    /** @deprecated use `Mocha.Runner` instead. */
    interface IRunner extends NodeJS.EventEmitter {
        asyncOnly?: boolean;
        stats?: IStats;
        started: boolean;
        /** @deprecated `.suite` has type `Mocha.Suite` in `Mocha.Runner`. */
        suite: ISuite;
        total: number;
        failures: number;
        forbidOnly?: boolean;
        forbidPending?: boolean;
        fullStackTrace?: boolean;
        ignoreLeaks?: boolean;
        grep(re: RegExp, invert: boolean): this;
        /** @deprecated Parameter `suite` has type `Mocha.Suite` in `Mocha.Runner`. */
        grepTotal(suite: ISuite): number;
        /** @deprecated `.globals()` has different overloads in `Mocha.Runner`. */
        globals(arr: ReadonlyArray<string>): this | string[];
        abort(): this;
        run(fn?: (failures: number) => void): this;
    }

    /** @deprecated use `Mocha.SuiteFunction` instead. */
    interface IContextDefinition {
        /** @deprecated use `Mocha.SuiteFunction` instead. */
        (description: string, callback: (this: ISuiteCallbackContext) => void): ISuite;
        /** @deprecated use `Mocha.SuiteFunction` instead. */
        only(description: string, callback: (this: ISuiteCallbackContext) => void): ISuite;
        /** @deprecated use `Mocha.SuiteFunction` instead. */
        skip(description: string, callback: (this: ISuiteCallbackContext) => void): void;
    }

    /** @deprecated use `Mocha.TestFunction` instead. */
    interface ITestDefinition {
        /** @deprecated use `Mocha.TestFunction` instead. */
        /** @deprecated `Mocha.TestFunction` does not allow mixing `done` with a return type of `PromiseLike<any>`. */
        (expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => PromiseLike<any> | void): ITest;
        /** @deprecated use `Mocha.TestFunction` instead. */
        /** @deprecated `Mocha.TestFunction#only` does not allow mixing `done` with a return type of `PromiseLike<any>`. */
        only(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => PromiseLike<any> | void): ITest;
        /** @deprecated use `Mocha.TestFunction` instead. */
        /** @deprecated `Mocha.TestFunction#skip` does not allow mixing `done` with a return type of `PromiseLike<any>`. */
        skip(expectation: string, callback?: (this: ITestCallbackContext, done: MochaDone) => PromiseLike<any> | void): void;
    }

    // #endregion
}

// #region Test interface augmentations

/**
 * Triggers root suite execution.
 *
 * - _Only available if flag --delay is passed into Mocha._
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#runWithSuite
 */
declare function run(): void;

/**
 * Execute before running tests.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#before
 */
declare var before: Mocha.HookFunction;

/**
 * Execute before running tests.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#before
 */
declare var suiteSetup: Mocha.HookFunction;

/**
 * Execute after running tests.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#after
 */
declare var after: Mocha.HookFunction;

/**
 * Execute after running tests.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#after
 */
declare var suiteTeardown: Mocha.HookFunction;

/**
 * Execute before each test case.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#beforeEach
 */
declare var beforeEach: Mocha.HookFunction;

/**
 * Execute before each test case.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#beforeEach
 */
declare var setup: Mocha.HookFunction;

/**
 * Execute after each test case.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#afterEach
 */
declare var afterEach: Mocha.HookFunction;

/**
 * Execute after each test case.
 *
 * - _Only available when invoked via the mocha CLI._
 *
 * @see https://mochajs.org/api/global.html#afterEach
 */
declare var teardown: Mocha.HookFunction;

/**
 * Describe a "suite" containing nested suites and tests.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var describe: Mocha.SuiteFunction;

/**
 * Describe a "suite" containing nested suites and tests.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var context: Mocha.SuiteFunction;

/**
 * Describe a "suite" containing nested suites and tests.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var suite: Mocha.SuiteFunction;

/**
 * Pending suite.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var xdescribe: Mocha.PendingSuiteFunction;

/**
 * Pending suite.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var xcontext: Mocha.PendingSuiteFunction;

/**
 * Describes a test case.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var it: Mocha.TestFunction;

/**
 * Describes a test case.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var specify: Mocha.TestFunction;

/**
 * Describes a test case.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var test: Mocha.TestFunction;

/**
 * Describes a pending test case.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var xit: Mocha.PendingTestFunction;

/**
 * Describes a pending test case.
 *
 * - _Only available when invoked via the mocha CLI._
 */
declare var xspecify: Mocha.PendingTestFunction;

// #endregion Test interface augmentations

// #region Reporter augmentations

// Forward declaration for `HTMLLIElement` from lib.dom.d.ts.
// Required by Mocha.reporters.HTML.
// NOTE: Mocha *must not* have a direct dependency on DOM types.
// tslint:disable-next-line no-empty-interface
interface HTMLLIElement { }

// Augments the DOM `Window` object when lib.dom.d.ts is loaded.
// tslint:disable-next-line no-empty-interface
interface Window extends Mocha.MochaGlobals { }

declare namespace NodeJS {
    // Forward declaration for `NodeJS.EventEmitter` from node.d.ts.
    // Required by Mocha.Runnable, Mocha.Runner, and Mocha.Suite.
    // NOTE: Mocha *must not* have a direct dependency on @types/node.
    // tslint:disable-next-line no-empty-interface
    interface EventEmitter { }

    // Augments NodeJS's `global` object when node.d.ts is loaded
    // tslint:disable-next-line no-empty-interface
    interface Global extends Mocha.MochaGlobals { }
}

// #endregion Reporter augmentations

// #region Browser augmentations

/**
 * Mocha global.
 *
 * - _Only supported in the browser._
 */
declare const mocha: BrowserMocha;

interface BrowserMocha extends Mocha {
    /**
     * 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.
     *
     * - _Only supported in the browser._
     */
    throwError(err: any): never;

    /**
     * Setup mocha with the given settings options.
     *
     * - _Only supported in the browser._
     */
    setup(opts?: Mocha.Interface | MochaSetupOptions): this;
}

/**
 * Options to pass to `mocha.setup` in the browser.
 */
interface MochaSetupOptions extends Mocha.MochaOptions {
    /** @deprecated This is not used by Mocha. Use `files` instead. */
    require?: string[];
    fullTrace?: boolean;
}

// #endregion Browser augmentations

// #region Deprecations

/** @deprecated use `Mocha.Done` instead. */
type MochaDone = Mocha.Done;

/** @deprecated use `Mocha.ReporterConstructor` instead. */
type ReporterConstructor = Mocha.ReporterConstructor;

// #endregion Deprecations

declare module "mocha" {
    export = Mocha;
}

declare module "mocha/lib/ms" {
    export = milliseconds;
    /**
     * Parse the given `str` and return milliseconds.
     *
     * @see {@link https://mochajs.org/api/module-milliseconds.html}
     * @see {@link https://mochajs.org/api/module-milliseconds.html#~parse}
     */
    function milliseconds(val: string): number;

    /**
     * Format for `ms`.
     *
     * @see {@link https://mochajs.org/api/module-milliseconds.html}
     * @see {@link https://mochajs.org/api/module-milliseconds.html#~format}
     */
    function milliseconds(val: number): string;
}

declare module "mocha/lib/interfaces/common" {
    export = common;

    function common(suites: Mocha.Suite[], context: Mocha.MochaGlobals, mocha: Mocha): common.CommonFunctions;

    namespace common {
        interface CommonFunctions {
            /**
             * This is only present if flag --delay is passed into Mocha. It triggers
             * root suite execution.
             */
            runWithSuite(suite: Mocha.Suite): () => void;

            /**
             * Execute before running tests.
             */
            before(fn?: Mocha.Func | Mocha.AsyncFunc): void;

            /**
             * Execute before running tests.
             */
            before(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void;

            /**
             * Execute after running tests.
             */
            after(fn?: Mocha.Func | Mocha.AsyncFunc): void;

            /**
             * Execute after running tests.
             */
            after(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void;

            /**
             * Execute before each test case.
             */
            beforeEach(fn?: Mocha.Func | Mocha.AsyncFunc): void;

            /**
             * Execute before each test case.
             */
            beforeEach(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void;

            /**
             * Execute after each test case.
             */
            afterEach(fn?: Mocha.Func | Mocha.AsyncFunc): void;

            /**
             * Execute after each test case.
             */
            afterEach(name: string, fn?: Mocha.Func | Mocha.AsyncFunc): void;

            suite: SuiteFunctions;
            test: TestFunctions;
        }

        interface CreateOptions {
            /** Title of suite */
            title: string;

            /** Suite function */
            fn?: (this: Mocha.Suite) => void;

            /** Is suite pending? */
            pending?: boolean;

            /** Filepath where this Suite resides */
            file?: string;

            /** Is suite exclusive? */
            isOnly?: boolean;
        }

        interface SuiteFunctions {
            /**
             * Create an exclusive Suite; convenience function
             */
            only(opts: CreateOptions): Mocha.Suite;

            /**
             * Create a Suite, but skip it; convenience function
             */
            skip(opts: CreateOptions): Mocha.Suite;

            /**
             * Creates a suite.
             */
            create(opts: CreateOptions): Mocha.Suite;
        }

        interface TestFunctions {
            /**
             * Exclusive test-case.
             */
            only(mocha: Mocha, test: Mocha.Test): Mocha.Test;

            /**
             * Pending test case.
             */
            skip(title: string): void;

            /**
             * Number of retry attempts
             */
            retries(n: number): void;
        }
    }
}
