Preventing Hidden Failures in Mocha Tests with --forbid-only and --forbid-pending
Accidental `it.only` and silent pending specs can make a test run look green while hiding real bugs. Mocha’s `--forbid-only` and `--forbid-pending` flags turn these slips into CI failures, keeping your test suite honest. Learn how to adopt them safely.
12 Aug 2025, 03:10 UTC

Why the Problem Matters
When you add a new test, you sometimes want to focus on a single spec to debug faster. The it.only helper makes Mocha run only that spec, hiding the rest of the suite. If you forget to remove it, the build will still report 0 failures and the merge will pass, but hidden failures stay buried. The same thing happens with pending specs (declared without a callback or marked .skip): they are reported but never executed, so they silently reduce coverage and can mask real issues.
In a fast‑moving team, these accidental leftovers are a common source of flaky or broken releases. The solution is simple: let Mocha itself refuse to run when it detects an exclusive or pending test.
Mocha’s Built‑in Gates
Mocha exposes two CLI flags that make the runner exit with a non‑zero status when it finds a problem:
--forbid-only– aborts if anyit.onlyordescribe.onlyis present.--forbid-pending– aborts if any pending spec is detected (e.g.,it('todo')orit.skip).
These flags do not change the test output; they simply cause Mocha to exit with code 1, which CI interprets as a failure. The test run still lists the offending specs, making it easy to locate and fix the issue.
Adopting a Two‑Script Strategy
Most developers run npm test locally and want a fast, forgiving loop. CI, on the other hand, should be strict. A common pattern is to keep two scripts in package.json:
{
"scripts": {
"test": "mocha",
"test:ci": "mocha --forbid-only --forbid-pending"
}
}
Local runs stay lightweight; CI runs the stricter test:ci script. Your CI pipeline would execute npm run test:ci and fail on any exit status other than zero.
Example: Add a temporary it.only('focus', () => {}) to a passing suite and run npx mocha --forbid-only. You should see an error like "Exclusive test detected" and the process exit with code 1. Removing the flag restores a green run. The same test with --forbid-pending will flag a pending spec.
Trade‑offs and Caveats
While the gates are powerful, they can be disruptive for teams that use it.skip or xit as TODO markers. If you have platform‑specific tests that are intentionally skipped on some branches, --forbid-pending will break the build. To mitigate churn:
- Replace skipped tests with issue‑tracked TODO comments and a short test that fails explicitly.
- Scope
--forbid-pendingto a dedicated audit job that runs on a nightly schedule instead of every PR. - Regularly audit pending specs and either implement them or remove the placeholder.
Another risk is that piping Mocha through other tools (e.g., grep or custom reporters) without set -o pipefail can mask the non‑zero exit. Ensure your CI shells honor pipefail or run Mocha directly.
Practical Checklist Before Enabling the Gates
- Run
npx mocha --forbid-onlylocally on your test suite and fix any accidentalonlyusage. - Run
npx mocha --forbid-pendingand address pending specs. - Add
"test:ci": "mocha --forbid-only --forbid-pending"topackage.json. - Configure your CI to execute
npm run test:ciand enforce non‑zero exit as a failure. - Schedule a periodic audit job or review pending specs in PRs to keep the suite clean.
Conclusion
Accidental it.only and pending specs are silent saboteurs that can let real bugs slip into production. Mocha’s --forbid-only and --forbid-pending flags give you a simple, declarative guard that turns these mistakes into CI failures. By keeping developer runs fast and CI strict, you maintain a healthy test suite without sacrificing speed. Add the gates, audit your pending specs, and let your CI do the hard work of catching hidden failures.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.