Mocha async test timeouts: distinguishing late rejections from hanging promises
0 reputation · 08 Apr 2021, 18:29 UTC
0 reputation · 08 Apr 2021, 18:29 UTC
Mocha enforces a timeout on every test, with a default of 2000 ms, and the timer starts when the test function is invoked. For async tests, the setting applies to the entire body, so a returned promise that never settles is aborted with a timeout error once the deadline passes.
The unresolved behavior concerns promises that do settle, but only after the deadline has already fired. In that situation the runner reports the same generic timeout message whether the promise was hanging indefinitely or rejected moments too late, and there is no documented configuration that preserves the late rejection reason or separates the two cases. How the timeout budget is accounted across multiple sequential awaits inside a single test is also not specified.
Specific questions:
32275 reputation · 09 Apr 2021, 00:56 UTC
Mocha cannot differentiate a promise that rejects after the deadline from one that hangs indefinitely; once the timeout expires it aborts the test and reports a generic timeout error, losing the original rejection reason.
The timeout budget is set once when this.timeout(ms) is called (or via the --timeout CLI flag) and applies to the entire test function. It does not reset at each await statement, so all sequential awaited operations share the same budget.
this.timeout()Place this.timeout(ms) as the first statement inside the it block, before any asynchronous call. If placed later, the initial async operation is still governed by the default timeout. The setting also works in before, after, beforeEach and afterEach hooks, but hooks do not inherit the timeout value from the surrounding it block.
it blocks: declare this.timeout() at the very start of the function body.To confirm the behavior, create a minimal test:
it('shows timeout priority', function() {
this.timeout(100);
// Rejection occurs after 150ms but test fails at 100ms
setTimeout(() => {
// would resolve with a rejection reason
}, 150);
});
The runner will emit a Timeout of 100ms exceeded error, not the rejection message.
If you need to capture a late rejection, wrap the async work in a Promise.race() with a timer and handle the rejection manually; Mocha’s timeout configuration cannot be altered to preserve post‑deadline rejections.
Note: Mocha’s timeout handling may vary between major versions (e.g., 8.x vs 10.x). Verify the version you are using to ensure the described behavior matches your environment.
Please indicate which Mocha major version you are running, as timeout semantics can differ across releases.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.