Root Hook Plugins
In some cases, you may want a hook before (or after) every test in every file.
These are called root hooks.
Previous to v8.0.0, the way to accomplish this was to use --file
combined with root hooks (see Root Hooks Are Not Global).
This still works in v8.0.0, but not when running tests in parallel mode!
For that reason, running root hooks using this method is strongly discouraged, and may be deprecated in the future.
A Root Hook Plugin is a JavaScript file loaded via --require
which “registers” one or more root hooks to be used across all test files.
In browsers you can set root hooks directly via a rootHooks
object: mocha.setup({ rootHooks: {beforeEach() {...}} })
, see mocha.setup()
Defining a Root Hook Plugin
A Root Hook Plugin file is a script which exports (via module.exports
) a mochaHooks
property.
It is loaded via --require <file>
.
Here’s a simple example which defines a root hook, written using CJS and ESM syntax.
With CommonJS
With ES Modules
We’re using the .mjs
extension in these examples.
Available Root Hooks
Root hooks work with any interface, but the property names do not change.
In other words, if you are using the tdd
interface, suiteSetup
maps to beforeAll
, and setup
maps to beforeEach
.
Available root hooks and their behavior:
beforeAll
:- In serial mode (Mocha’s default), before all tests begin, once only
- In parallel mode, run before all tests begin, for each file
beforeEach
:- In both modes, run before each test
afterAll
:- In serial mode, run after all tests end, once only
- In parallel mode, run after all tests end, for each file
afterEach
:- In both modes, run after every test
As with other hooks, this
refers to the current context object:
Multiple Root Hooks in a Single Plugin
Multiple root hooks can be defined in a single plugin, for organizational purposes. For example:
Root Hook Plugins Can Export a Function
If you need to perform some logic—such as choosing a root hook conditionally, based on the environment—mochaHooks
can be a function which returns the expected object.
If you need to perform an async operation, mochaHooks
can be Promise
-returning:
Multiple Root Hook Plugins
Multiple root hook plugins can be registered by using --require
multiple times.
For example, to register the root hooks in hooks-a.js
and hooks-b.js
, use --require hooks-a.js --require hooks-b.js
.
These will be registered (and run) in order.
Migrating Tests to use Root Hook Plugins
To migrate your tests using root hooks to a root hook plugin:
- Find your root hooks (hooks defined outside of a suite—usually
describe()
callback). - Create a new file, e.g.,
test/hooks.js
. - Move your root hooks into
test/hooks.js
. - In
test/hooks.js
, make your hooks a member of an exportedmochaHooks
property. - Use
--require test/hooks.js
(even better: use a config file with{"require": "test/hooks.js"}
) when running your tests.
For example, given the following file, test/test.spec.js
, containing root hooks:
Your test/hooks.js
(for this example, a CJS module) should contain:
Your original test/test.spec.js
should now contain:
Running mocha --require test/hooks.js test/test.spec.js
will run as before (and is now ready to be used with --parallel
).
Migrating a Library to use Root Hook PLugins
If you’re a library maintainer, and your library uses root hooks, you can migrate by refactoring your entry point:
- Your library should always export a
mochaHooks
object. - To maintain backwards compatibility, run your root hooks if and only if
global.beforeEach
(or other relevant hook) exists. - Instruct your users to
--require <your-package>
when runningmocha
.