Async Error Handling in Mocha with Chai tests
Last updated: 25.02.2024
Context:
- Environment: ESM, Node.js 20, TypeScript project.
- Dependencies:
- Mocha version:
"mocha": "10.3.0"
- Chai version:
"chai": "4.4.1"
- Mocha version:
Problem:
Consider a service attempting to create a new database resource. If initial business validation fails, an error is thrown. To test this behavior, you might write:
it('should raise a validation error when title is too short', async () => {
const service = taskService()
expect(service.createNewTask({ title: ' FV' })).to.throw(
'Validation failed, double check your form please and try again'
)
})
Test will fail with following error:
1) task service
should raise a validation error when title is too short:
AssertionError: expected Promise{…} to be a function
at Context.<anonymous> (src/tasks/services/task-service.spec.ts:46:54)
at process.processImmediate (node:internal/timers:478:21)
Root cause:
The test incorrectly attempts to use expect().to.throw
with a promise returned by an async function, which is not supported by Chai's expect
directly.
Solution:
- install
chai-as-promised
and use it in your test
import { expect, use } from "chai";
import chaiAsPromised from "chai-as-promised";
import { taskService } from "./task-service.js";
use(chaiAsPromised);
Switch assertion to to.be.rejectedWith
and await the assertion
it("should raise a validation error when title is too short", async () => {
const service = taskService();
await expect(service.createNewTask({ title: " FV" })).to.be.rejectedWith(
"Validation failed, please double check your form and try again"
);
});
You can read more about chai as promised: here
There is also Github issue about native support for promise in Chai: here
Alternative:
You could also leverage the approach without chai-as-promised
simply by wrapping the test in try catch block
it("should raise a validation error when title is too short", async () => {
const service = taskService();
try {
await service.createNewTask({ title: " FV" });
} catch (err) {
// Note: error is unknown here, use type-guard or ts-ignore
expect(err.message).to.equal(
"Validation failed, please double check your form and try again"
);
}
});