Skip to content

Mocha ​

This guide covers Mocha 10.0 or newer. You need Node.js 22.12 or newer to run test-inventory and an existing JavaScript or TypeScript test suite. The scanner reads your source without executing your tests or starting a browser. These are minimum supported versions; CI comparisons list tested versions.

Choose another framework · Use an AI client

Install ​

sh
npm install --save-dev test-inventory

Scan your suite ​

Run from the folder containing your project's package.json:

sh
npx test-inventory --framework mocha --pretty --output inventory.json

To select files explicitly, use quoted globs. This example matches the fix-gateway fixture used below; adjust the globs to your suite's layout:

sh
npx test-inventory "test/**/*.spec.js" --framework mocha --output inventory.json

The command replaces inventory.json once the new output is complete. It does not change your test files.

Check the result ​

Print the counts and diagnostics from the saved file:

sh
node -e "const i = require('./inventory.json'); console.log(i.summary); console.log(i.diagnostics)"

For matching tests, summary.fileCount and summary.testCount should be greater than zero. Review diagnostics even when the command exits with 0: errors can mean tests are missing. If the result is empty or unexpected, use troubleshooting.

The inventory describes source declarations, not execution results. Conditional skips are not proof that a run skipped the test. Loops and tables are one record by default; supported cases can be expanded with --expand-cases. Expected-to-fail tests execute and check for failure; they are not disabled tests.

Tests created by unreadable helpers can be missing without a diagnostic. A dependency hash does not prove complete coverage of runtime dependencies. Read the shared limits before using scans to make CI decisions.

Find skipped tests ​

sh
npx test-inventory --framework mocha --state skip --fields fullName,state,condition,reason --pretty

This uses the same file selection as the first scan. If you supplied globs, --root or --framework-version, repeat those options here.

This selects source declarations marked skip; it is not a report of a test run. See query recipes for other inventory queries.

Example ​

fix-gateway sends orders to venues over FIX and is tested with Mocha, in plain CommonJS. Its config is .mocharc.yml:

Excerpt: yaml
# Unit specs and the exchange specs, which share the session helpers in test/helpers.
spec: 'test/**/*.spec.js'
timeout: '5s'
retries: 1

The specs set timeouts and retries through Mocha's this, in describes and tests written as functions, and skip themselves at run time:

Excerpt: js
// test/session.spec.js
describe('FIX session', () => {
  // ...
  context('heartbeats', function () {
    this.retries(3);
    // ...
    it('answers a test request with a heartbeat', function () {
      this.timeout(250);
      // ...
  describe('logon to a live venue', function () {
    before(function () {
      if (!process.env.FIX_HOST) this.skip();
    });
sh
npx test-inventory "test/**/*.spec.js" --framework mocha --output inventory.json

Without the glob and --framework, the scan finds the same files from .mocharc.yml, and Mocha from package.json. The test's own timeout wins over the config's '5s', and the retries come from its describe:

json
{
  "fullName": "FIX session > heartbeats > answers a test request with a heartbeat",
  "timeout": 250,
  "timeoutSource": "test",
  "retries": 3,
  "retriesSource": "suite"
}

this.skip() in the before hook skips the describe's tests when the condition holds:

json
{
  "fullName": "FIX session > logon to a live venue > logs on with a sequence reset",
  "state": "skip",
  "stateSource": "suite",
  "isConditional": true,
  "condition": "!process.env.FIX_HOST"
}

Other Mocha examples: Puppeteer on Mocha.

Configuration and limits ​

The scan reads the first .mocharc.cjs, .js, .mjs, .yaml, .yml, .jsonc or .json in the root or an ancestor, combined with the nearest package.json mocha key. List options such as spec, extension and ignore are joined; other file values win. Without either config, Mocha's defaults apply.

Explicit scan globs count as supplied specs, less ignore, because project scripts often pass Mocha its files. The config's timeout, retries and forbid-only are read. Runtime or package-provided settings remain unknown. this.skip() is read from source; whether a conditional call actually skips a test needs a run.

Exact file selection

For Mocha: from the root, each spec entry as a glob, a file, a file named without its extension, or a folder, whose files with one of the extensions, js, cjs and mjs by default, are taken, those in folders below too with recursive, without those ignore matches as written, so that a pattern starting with ./ matches nothing; and the file entries, which Mocha loads first, and to which ignore doesn't apply. An extension may have several parts, as spec.js. The default spec is ./test. Scanned with globs, every file they match counts as run, without those ignore matches, as a project's scripts often give Mocha the spec on its command line, which no config shows. The config's timeout, which may be a string such as '5s', and retries apply to every test.

Supported syntax ​

Mocha 10.0 and newer.

Where test comes from ​

FormExample
Globalsdescribe, context, it, specify, xdescribe, xcontext, xit and xspecify used without an import or declaration; with ui: tdd in the config, suite and test
Named import, also renamedimport { describe, it } from 'mocha'
The moduleimport * as mocha from 'mocha', a default import, or require('mocha'), whole, destructured or in place
Kept in a variableconst onCi = process.env.CI ? it.skip : it: only what both branches share applies, also to a choice written in place, as (process.env.CI ? it.skip : it)(...)
Local helpers fileimport { it } from './helpers' or require('./helpers'), followed through local imports, and helper functions that declare tests, read at each call

xit, xspecify, xdescribe and xcontext are .skip. Mocha's QUnit and exports interfaces, and a ui that names a package, are reported on the config with a config-value-unknown warning, and the files are read as BDD.

Calls ​

CallRead as
it(title, fn), specify(title, fn)A test.
it(title) without a functionA skipped test: Mocha reports it as pending.
.only, .skipisOnly, or a skipped test or describe. Any other member, as it.concurrent, is an invalid-chain error: Mocha stops before it runs any test, in this file or any other.
describe(title, fn), context(title, fn)A describe. An async callback is allowed, as Mocha allows it.
describe(title) without a functionA test-without-body error: Mocha stops before it runs any test. describe.skip(title) is allowed.
it(), describe() without a titleA test-without-body error: Mocha stops before it runs any test.
before, after, beforeEach, afterEach, with or without a titleHooks, counted as beforeAll, afterAll, beforeEach and afterEach; with ui: tdd, suiteSetup, suiteTeardown, setup and teardown.
this.timeout(ms), this.retries(n) in a describe written as a functiontimeout and retries on its tests and those of the describes inside it. A timeout may be a number or a string such as '2s'; 0, and one of 2,147,483,647 ms or more, turns it off.
this.timeout(ms), this.retries(n) in a test written as a functionThe test's own timeout and retries. In a hook, this.timeout() sets the hook's own timeout, which no record holds.
it(...).timeout(ms), it(...).retries(n), describe(...).timeout(ms)The same settings on the test the call returns. On a describe, only the timeout, and only from Mocha 12, which reads it as each test runs; before, a describe's tests take its timeout when they are added. describe(...).retries(n) reaches none of its tests.
this.skip() in a test or a before or beforeEach hook written as a functionThe test, or the tests the hook runs for, skipped; under a condition, isConditional.

this is Mocha's context only directly in the test's, hook's or describe's own function: in an arrow function, or a function inside it, this.timeout() and this.skip() are not read. A test takes its describe's retries, and before Mocha 12 its timeout, when it is added, so a test written above this.retries() in the same describe doesn't get them; the scan applies them to every test of the describe. A beforeEach or other hook written at the top level of one spec file runs around the tests of every file, but is counted only in that file. A loop that declares tests, such as ['XNAS', 'XLON'].forEach((mic) => it(...)), is one record with caseCount, as for the other runners. Root hooks, which a file the config lists in require exports as mochaHooks, run around every test, but are not counted in hooks; the file is in each test's dependencies.

The shared syntax rules also apply.

Next ​

Documentation for test-inventory 0.10.1. Released under the MIT License.