Mocha 12 is now available
Mocha 12 is ready for use in production environments.
npm i -D mocha@12.0.0pnpm add -D mocha@12.0.0yarn add -D mocha@12.0.0Below is a migration guide, including breaking changes, notable new features, and some bugfixes we’re proud of.
We will continue to support critical bugfixes in Mocha 11 while customers upgrade to Mocha 12. We’ve also deployed v11.mochajs.org for users who rely on Mocha 11 in the long-term.
Breaking changes
Section titled “Breaking changes”The changes in Mocha 12 should require few, if any, changes in user applications. Most end-users should not be affected by Mocha 12’s breaking changes. A small subset of programmatic integrators may need to perform small updates to work with some API updates.
Minimum Node.js version increases
Section titled “Minimum Node.js version increases”Mocha 12 updates the minimum Node.js versions supported to ^20.19.0 || >=22.12.0.
Those new minimum versions are intentionally the lowest Node.js versions that support require(esm).
We intentionally chose those versions so that programmatic integrators can continue to require("mocha"), though we do recommend updating to ECMAScript Modules (ESM) if possible.
Accordingly, Mocha’s minimum supported browser versions are those that were stable as of Node.js 20.0.0’s release on April 18, 2023: Chrome 112, Edge 112, Firefox 112, and Safari 16.4.
We know that Node 20 is now EOL, but we didn’t want to jump 2 LTS versions in one release. Mocha 13 will drop support for Node 20.
See #5358 🧹 Versioning: Bump minimum Node.js version from 18.18.0 to 20.19.0 and feat!: bump minimum Node.js version from 18.18.0 to 20.19.0 (#5477) for more details.
ECMAScript Modules (ESM) package
Section titled “ECMAScript Modules (ESM) package”Mocha is now an ECMAScript Modules (ESM) package. Moving to ESM allows the internal code to integrate better with more modern dev tooling. For example, static analysis tools such as ESLint, Knip, and TypeScript are better able to analyze ESM, which will help us detect bugs and unused code in future versions of Mocha.
Most users should not see any change from the ESM migration. We have identified some edge cases from programmatic usage of Mocha that require some changes.
See #5400 🛠️ Repo: Switch from CJS to ESM internally for more details.
Removed legacy entrypoint
Section titled “Removed legacy entrypoint”One _mocha entry point had been kept in older versions of Mocha as a workaround for old coverage providers.
It is now removed.
Swapping path/to/bin/_mocha with mocha should work the same:
node path/to/bin/_mochanode path/to/bin/mochaOther package entrypoints for Mocha should work as before.
Mocha 12’s package.json uses "main"
to allow users to continue importing all source files.
In Mocha 13, we will switch to the modern "exports" field
and limit our API to relevant files for a clearer contract with users.
See #5970 🛠️ Repo: Convert bin/ and top-level entry points to ESM and #6017 feat!: remove bin/_mocha and convert bin/ and entry points to ESM for more details.
require('mocha') now returns an object
Section titled “require('mocha') now returns an object”Running require('mocha') in CommonJS (CJS) code used to return the Mocha function directly.
It now returns an object, with a Mocha property.
To work around this, change:
const Mocha = require('mocha');const { Mocha } = require ('mocha');See #6245 🐛 Bug: require(‘mocha’) now returns an object, not a function (12.0.0-rc.6) for more details.
Native Node.js CLI parsing
Section titled “Native Node.js CLI parsing”Through Mocha 11, yargs and its related packages parsed command-line input to Mocha.
Mocha now uses native Node.js util.parseArgs.
The new approach should be functionally the same,
with potential minor formatting differences
in human-facing output like --help.
These were marked as breaking changes out of an abundance of caution.
- feat!: replace yargs-parser in CLI option loading (#6124)
- feat!: replace yargs-unparser in CLI respawn paths (#6125)
- refactor!: replace yargs with Node.js util.parseArgs (#6164)
--forbid-only defaults to process.env.CI
Section titled “--forbid-only defaults to process.env.CI”Mocha’s --forbid-only CLI flag fails test runs if an exclusive test (.only) is declared.
Using the flag is useful to make sure exclusive tests aren’t accidentally kept in changes.
--forbid-only previously defaulted to false.
Its new default is whether an environment variable named CI is truthy.
This matches other test runner behaviors such as Vitest’s allowOnly.
If you intentionally want to use .only in CI,
explicitly set --no-forbid-only to restore the previous default behavior.
npx mocha --no-forbid-onlySee #5299 🚀 Feature: Exit with code 1 when .only is used by default in CI (–forbid-only) and feat!: change the default of –forbid-only to check for process.env.CI- #5496 for more details.
Replacing util.inherits with classes
Section titled “Replacing util.inherits with classes”Through Mocha 11, reporters inherited behavior from a base object through the legacy Node.js util.inherits.
util.inherits has subtly different behavior from ES2015 JavaScript classes
and was deprecated in Node.js many years ago.
Reporters now inherit through canonical JavaScript class syntax.
This means that the syntax for custom reporters has changed,
but the core behavior is the same. See
third-party reporters
for updated instructions.
See #5025 🐛 Remove util.inherits / convert to classes for more details.
Internal cleanups
Section titled “Internal cleanups”The following cleanups should be functionally the same for users, but are marked as breaking changes out of an abundance of caution.
- Replace
hedependency with manual HTML encoding (#6129):hewas used for HTML encoding in some reporters, and in the exportedescapefunction. - Remove unused legacy
errors.jsfunctions (#5835): The public functioncreateInvalidPluginErrorhad been deprecated for years. Callers should usecreateInvalidLegacyPluginErrorinstead, which has the same contract and behavior.
Deprecated CLI flag removals
Section titled “Deprecated CLI flag removals”The following two flags have both been deprecated for a long time. They have not had any impact on behavior for years. They are now removed from the codebase.
Notable new features
Section titled “Notable new features”Executing FIFOs as test files
Section titled “Executing FIFOs as test files”A “FIFO” (first-in, first-out) is a file piped directly to a command in a terminal. It’s also referred to as a “named pipe.” This can be convenient for quickly running small pieces of code in Mocha:
npx mocha --preserve-symlinks <(echo 'it("t", () => require("node:assert").equal(1, 1))')See #5511 🚀 Feature: execute tests from FIFOs and feat: allow FIFOs as test files for more details.
ESM export for browsers
Section titled “ESM export for browsers”Mocha has long supported working in browsers.
But until recently, users did not have a canonical way to import from within a <script type="module">.
Mocha 12 now canonically supports an ESM browser import:
<script type="module"> import * as mocha from "./node_modules/mocha/mocha.js";
mocha.setup("bdd"); await import("./unit-test.js"); mocha.run();</script>See #5211 🚀 Feature: Ability to import mocha from ESM in the browser and feat: add mocha.mjs export (#5527) for more details.
Added --fail-hook-affected-tests CLI flag
Section titled “Added --fail-hook-affected-tests CLI flag”Mocha allows declaring “hooks” like before() and afterEach() to run logic before and/or after tests.
Through Mocha 11, by default, thrown errors in those hooks didn’t fail their related tests.
This sometimes masked important failures in shared test logic.
Mocha 12 introduces a new --fail-hook-affected-tests CLI flag that causes failures in hooks to fail their affected tests:
npx mocha --fail-hook-affected-testsWe recommend enabling this flag. It will be enabled by default in a future major version of Mocha.
See #4392 🚀 Feature: Failures in before() and beforeAll() should cause all impacted tests to be reported as failed and feat: add –fail-hook-affected-tests option to report skipped tests as failed (#5519) for more details.
Notable fixes
Section titled “Notable fixes”Default imported interfaces and reporters
Section titled “Default imported interfaces and reporters”Mocha allows users to load in custom interfaces and reporters for test runs.
Previously they had to be exported with CommonJS (CJS) semantics.
However, ECMAScript Modules (ESM) semantics prefer export default ... (module.exports.default = ...).
This use case is now supported for both interfaces and reporters.
See #5562 🐛 Bug: Can’t ESM (default) import custom interfaces and reporters and fix: allow importing ESM interface and reporters for more details.
Adding URLs with loadFilesAsync
Section titled “Adding URLs with loadFilesAsync”Mocha’s Node.js API includes a loadFilesAsync method to import and run specified test files.
It previously only supported local pathnames of files as added by the addFile method.
Attempting to load in a file with a standard file://... URL would throw an error.
This is now corrected to work as expected.
See #4993 🐛 Bug: esm-utils (mocha.addFile) should support URL and fix: support file: URLs in loadFilesAsync (#5833) for more details.
Grepping with modern RegExp flags
Section titled “Grepping with modern RegExp flags”Mocha supports a grep CLI flag and grep Node.js API method for matching files on disk with regular expressions.
Mocha’s internal logic validates those regular expressions, but only supported a few flags. JavaScript now supports u,
s,
and v RegExp flags.
The validation logic now supports those flags.
See #5826 🐛 Bug: Mocha#grep fails to parse modern RegExp flags (u, s, v) from string input and fix: support modern RegExp flags in Mocha (#5825) for more details.
Diff hangs on large object comparisons
Section titled “Diff hangs on large object comparisons”If a thrown error in a test contains .actual and .expected properties, Mocha will show a rich stringified diff of the differences.
This is implemented by common assertion libraries such as Chai.
Previously, if one or both of those properties contained very complex and/or large objects, Mocha’s diff generation could hang indefinitely during stringification. Mocha 12 fixes this.
See #1624 🐛 Bug: Comparing buffers hangs when computing the diff report and fix: prevent diff hang on large/complex objects (#5898) for more details.
Non-zero exit codes on setup and teardown errors
Section titled “Non-zero exit codes on setup and teardown errors”Mocha provides global fixtures so that test suites may run code once on setup or teardown. Previously, if an error was thrown in a global fixture, it would be ignored and Mocha would continue to run tests. This could mask important failures in shared test logic. Mocha 12 will now exit with a non-zero status code on global fixture errors.
See #5208 🐛 Bug: Error in mochaGlobalTeardown is swallowed and exits with code 0 and fix: surface global setup/teardown errors with a non-zero exit code (#5994) for more details.
Thank you!
Section titled “Thank you!”Mocha development could not continue without the support of contributors who have opened issues, submitted PRs, and commented in discussions. During development of Mocha 12, we merged 100+ PRs from community members! We are also very grateful to our many financial donors.
Mocha continues to thrive thanks to all of these generous contributions. Thank you.
Questions, comments, concerns?
Section titled “Questions, comments, concerns?”As always, you can open an issue on GitHub or message us on Discord for support. 🤎