mocha
semver
>=8.0.0 <12.0.0postconditions15functions9last verified2026-04-20coverage score100%Postconditions — what we check
- it · it-async-unhandled-rejectionwarningWhentest function is async or returns a Promise that rejectsThrows
UnhandledPromiseRejectionWarningRequired handlingTest functions that return promises or use async/await MUST handle rejections. Without proper error handling, unhandled promise rejections in tests cause test failures to be reported incorrectly or crash the test runner. Use pattern: it('test', async () => { try { await operation(); } catch (e) { throw e; } }) or rely on Mocha's built-in async handling.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - before · before-async-unhandled-rejectionwarningWhenhook function is async or returns a Promise that rejectsThrows
UnhandledPromiseRejectionWarningRequired handlingBefore hooks that return promises MUST handle rejections properly. Unhandled rejections in before hooks cause test suite failures without clear error messages. Use async/await or return promises that are properly handled.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - after · after-async-unhandled-rejectionwarningWhenhook function is async or returns a Promise that rejectsThrows
UnhandledPromiseRejectionWarningRequired handlingAfter hooks that return promises MUST handle rejections properly. Unhandled rejections in cleanup hooks can leave resources in inconsistent states. Use async/await or return promises that are properly handled.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - beforeEach · beforeeach-async-unhandled-rejectionwarningWhenhook function is async or returns a Promise that rejectsThrows
UnhandledPromiseRejectionWarningRequired handlingBeforeEach hooks that return promises MUST handle rejections properly. Unhandled rejections cause individual test failures without clear attribution.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - afterEach · aftereach-async-unhandled-rejectionwarningWhenhook function is async or returns a Promise that rejectsThrows
UnhandledPromiseRejectionWarningRequired handlingAfterEach hooks that return promises MUST handle rejections properly. Unhandled rejections in cleanup can leave test environment in bad state.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[3] - afterEach · aftereach-resource-leakwarningWhenhook has async cleanup (server.close(), db.disconnect()) but doesn't await itThrows
Mocha hangs, won't exit (requires --exit flag)Required handlingAfterEach hooks with async cleanup MUST await completion or return promises. Common mistake: afterEach(() => { server.close(); }) instead of afterEach(async () => { await server.close(); }). Unclosed resources (servers, database connections, file handles) prevent Mocha from exiting. Frequency: 25-35% of resource cleanup bugs.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[4] - describe · describe-must-be-syncerrorWhendescribe() callback is async or contains awaitThrows
Undefined behavior - async code in describe not awaitedRequired handlingdescribe() callbacks MUST be synchronous. Mocha does NOT await async code in describe blocks. Common mistake: describe('Suite', async () => { const data = await fetchData(); ... }) - data will be undefined. Use before() hook for async setup: before(async () => { data = await fetchData(); }). Frequency: 15-20% of suite setup bugs.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[5] - Mocha.loadFilesAsync · load-files-async-syntax-errorerrorWhenA test file contains a JavaScript or TypeScript syntax error. loadFilesAsync() catches SyntaxError during import and rethrows it with the filename prepended to the stack trace for better diagnostics.Throws
SyntaxError annotated with filename: "SyntaxError[ @/path/to/test.js ] <original message>". The Promise rejects — no test files after the failing file are loaded.Required handlingCaller MUST attach a .catch() or use try/catch with await on loadFilesAsync(): // CORRECT: handle rejection before run() mocha.loadFilesAsync() .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0)) .catch(err => { console.error('Failed to load test files:', err); process.exitCode = 1; }); // CORRECT: async/await style try { await mocha.loadFilesAsync(); mocha.run(failures => process.exitCode = failures ? 1 : 0); } catch (err) { console.error('Test file load failed:', err); process.exitCode = 1; } Without a .catch() or try/catch, a syntax error in any test file causes an UnhandledPromiseRejection that crashes the Node.js process.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - Mocha.loadFilesAsync · load-files-async-module-not-founderrorWhenA test file imports a module that does not exist (e.g., a typo in an import path, a package that was not installed, or a relative import to a file that was deleted or renamed). Node.js throws an ERR_MODULE_NOT_FOUND error during import.Throws
Error with .code === 'ERR_MODULE_NOT_FOUND' and message like "Cannot find module './missing-module'" or "Cannot find package 'not-installed'". The Promise rejects immediately — remaining test files are not loaded.Required handlingCatch the rejection from loadFilesAsync(). The error message identifies which module was not found. Fix the import path or install the missing package. mocha.loadFilesAsync() .then(() => mocha.run(failures => process.exitCode = failures ? 1 : 0)) .catch(err => { if (err.code === 'ERR_MODULE_NOT_FOUND') { console.error('Missing dependency:', err.message); } process.exitCode = 1; });costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - Mocha.loadFilesAsync · load-files-async-unknown-extensionerrorWhenA test file has an unrecognized file extension (e.g., .ts without ts-node or @swc-node/register registered, .tsx, .vue) and Node.js cannot load it via either require() or import(). Throws ERR_UNKNOWN_FILE_EXTENSION.Throws
Error with .code === 'ERR_UNKNOWN_FILE_EXTENSION'. Common when running .ts test files without a TypeScript transpiler registered. The error message is "Unknown file extension '.<ext>' for /path/to/test.ts".Required handlingRegister a TypeScript loader before calling loadFilesAsync(): // Option 1: ts-node/esm loader // node --loader ts-node/esm mocha.mjs // Option 2: @swc-node/register import '@swc-node/register'; await mocha.loadFilesAsync(); // Option 3: Set esmDecorator to transform the path await mocha.loadFilesAsync({ esmDecorator: (file) => /* transform */ }); Catch and provide a clear diagnostic message about the missing loader.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - Mocha.run · run-already-running-throwserrorWhenmocha.run() is called while a previous test run is still in progress. The Mocha instance tracks a running flag and throws synchronously if run() is called twice. This can happen in programmatic orchestration that doesn't await the callback.Throws
Error: "Mocha instance is currently running. Cannot run while running." (synchronous throw)Required handlingOnly call run() once per Mocha instance per run cycle. Use a new Mocha() instance per test run if running tests multiple times (e.g., in watch mode). // CORRECT: wait for run to finish before running again mocha.run(failures => { if (failures) process.exitCode = 1; // Don't call run() again here — use a fresh instance });costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - Mocha.run · run-already-disposed-throwserrorWhenmocha.run() is called on a Mocha instance that has already been disposed. By default, Mocha disposes itself (cleans function references) after each test run when cleanReferencesAfterRun is true (the default). Calling run() again on a disposed instance throws synchronously. This is a common mistake in programmatic usage where developers reuse the same Mocha instance across multiple test runs.Throws
Error with code ERR_MOCHA_INSTANCE_ALREADY_DISPOSED: "Mocha instance is already disposed, cannot start a new test run. Please create a new mocha instance. Be sure to set disable `cleanReferencesAfterRun` when you want to reuse the same mocha instance for multiple test runs."Required handlingFor multiple test runs, either: (a) Create a new Mocha() instance per run (simplest), or (b) Disable auto-dispose and call dispose() manually: // OPTION A: new instance per run (recommended) function runTests() { const mocha = new Mocha({ timeout: 5000 }); mocha.addFile('./test/suite.spec.js'); mocha.run(failures => process.exitCode = failures ? 1 : 0); } // OPTION B: reuse instance — disable auto-dispose const mocha = new Mocha({ cleanReferencesAfterRun: false }); mocha.addFile('./test/suite.spec.js'); mocha.run(failures => { // can call mocha.run() again safely mocha.unloadFiles(); mocha.run(failures2 => process.exitCode = failures2 ? 1 : 0); });costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - Mocha.run · run-silent-failure-no-callbackwarningWhenmocha.run() is called without a callback function, or with a callback that does not set process.exitCode based on the failures count. In CI environments, the process will exit with code 0 even when tests fail, making the build green when it should be red.Throws
Does not throw. Failures are silently discarded. Process exits with code 0 (success) even when N tests failed — CI/CD pipelines report false success.Required handlingAlways provide a callback that checks the failures count and sets process.exitCode: // CORRECT: set exit code based on failures mocha.run(failures => { process.exitCode = failures ? 1 : 0; }); // ALSO CORRECT: explicit exit mocha.run(failures => { if (failures > 0) { console.error(`${failures} test(s) failed`); process.exit(1); } }); // WRONG: no callback — failures silently swallowed mocha.run(); // WRONG: callback ignores failures mocha.run(() => { /* no check */ });costlowin prodsilent failureusers seelost datavisibilitysilent - Mocha.parallelMode · parallel-mode-after-run-throwserrorWhenMocha.parallelMode() is called after mocha.run() has already been invoked. Once run() is called, the Mocha instance transitions out of the INIT state and parallelMode() can no longer be toggled. This is a setup-ordering mistake in programmatic usage — parallelMode must be configured before run() begins executing test files.Throws
Error with code ERR_MOCHA_UNSUPPORTED: "cannot change parallel mode after having called run()"Required handlingAlways call parallelMode() before run(): // CORRECT: configure parallel mode before running const mocha = new Mocha({ timeout: 10000 }); mocha.addFile('./test/**/*.spec.js'); mocha.parallelMode(true); // BEFORE run() mocha.run(failures => process.exitCode = failures ? 1 : 0); // WRONG: parallel mode after run() — throws ERR_MOCHA_UNSUPPORTED mocha.run(failures => { mocha.parallelMode(true); // too late — throws }); Note: parallelMode can also be set via the Mocha constructor options: new Mocha({ parallel: true }) This avoids the ordering issue entirely.costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible - Mocha.parallelMode · parallel-mode-in-browser-throwserrorWhenMocha.parallelMode() is called in a browser environment. Mocha detects the browser via a utils.isBrowser() check. Parallel mode spawns Node.js worker threads/child processes which are unavailable in browsers. Uncommon in typical usage but affects projects that use mocha programmatically in both Node.js and browser contexts (e.g., universal test harnesses or karma integration with the Mocha class directly).Throws
Error with code ERR_MOCHA_UNSUPPORTED: "parallel mode is only supported in Node.js"Required handlingCheck the environment before enabling parallel mode: if (typeof process !== 'undefined' && process.versions?.node) { mocha.parallelMode(true); } // Or just never call parallelMode() in browser-targeted test code. Alternatively, pass parallel: true in MochaOptions constructor only in Node-targeted builds: new Mocha({ parallel: isNode })costlowin prodimmediate exceptionusers seeservice unavailablevisibilityvisible
Sources
Every postcondition cites at least one of these. Numbered to match the footnotes above.
- [1]mochajs.orghttps://mochajs.org/#asynchronous-code
- [2]mochajs.orghttps://mochajs.org/#hooks
- [3]mochajs.org/features/hookshttps://mochajs.org/features/hooks/
- [4]mindfulchase.com/explore/troubleshooting-tipshttps://www.mindfulchase.com/explore/troubleshooting-tips/testing-frameworks/troubleshooting-mocha-flaky-tests,-async-bugs,-and-ci-failures.html
- [5]mochajs.org/next/featureshttps://mochajs.org/next/features/asynchronous-code/
- [6]legacy.mochajs.org/api/mochahttps://legacy.mochajs.org/api/mocha
- [7]github.com/mochajs/mochahttps://github.com/mochajs/mocha/blob/main/lib/nodejs/esm-utils.js#L11-L30
- [8]github.com/mochajs/mochahttps://github.com/mochajs/mocha/blob/main/lib/nodejs/esm-utils.js#L48-L86
- [9]mochajs.orghttps://mochajs.org/#typescript
- [10]github.com/mochajs/mochahttps://github.com/mochajs/mocha/blob/main/lib/mocha.js#L608
- [11]legacy.mochajs.org/api/mochahttps://legacy.mochajs.org/api/mocha#run
- [12]github.com/mochajs/mochahttps://github.com/mochajs/mocha/blob/main/lib/mocha.js
- [13]mochajs.orghttps://mochajs.org/#programmatic-usage
- [14]github.com/mochajs/mochahttps://github.com/mochajs/mocha/blob/main/lib/mocha.js#L1074
- [15]legacy.mochajs.org/api/mochahttps://legacy.mochajs.org/api/mocha#parallelMode
- [16]github.com/mochajs/mochahttps://github.com/mochajs/mocha/blob/main/lib/mocha.js#L1076
- [17]mochajs.org/features/parallel-modehttps://mochajs.org/features/parallel-mode/
Need a different package?
Request a profile