简体   繁体   中英

Handle promise rejection with Chai

I have the following validation function checking if a user exists:

validate.user = async (user, password) => {
    const matches = await bcrypt.compare(password, user.password);
    if (matches) return user;
    if (!matches) {
        return validate.logAndThrow('User password does not match');
    }
    return validate.logAndThrow('Error in bcrypt compare');
};

The following test using Chai should test this:

chai.use(sinonChai);
const { expect } = chai;

    describe('#user', () => {
        it('show throw if user is undefined', () => {
            expect(() => validate.user(undefined, 'pass')).to.throw('User does not exist');
        });

The error does get thrown, however mocha shows the following in the console:

2) show throw if user is undefined (node:18587) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: User does not exist

So my question is, how I can rewrite the test such that it does catch promise rejections?

Im not totally sure it is mocha that throws that unhandled rejection.

I think it is your bcrypt.compare which is async by nature and uses callbacks. await can't really be used out of the box with async functions.

but you can promisify the async calls with nodes util library like this:

const util = require('util');
const bcrypt = require('bcrypt');

const bcryptCompare = util.promisify(bcrypt.compare);

Now you can use await bcryptCompare(password, user.password); like you intended. please note that i changed the constant after the await call.

Also to handle rejections with async/await you should use try/catch like this:

let matches;
try {
    matches = await bcryptCompare(password, user.password);
} catch(bcryptError) {
    throw new Error(bcryptError);
}

For testing promise-based functions (async) use chai-as-promised plugin:

expect(validate.user(undefined, 'pass')).to.be.rejectedWith(Error, 'User does not exist');

In this case you do not put () => validate.user() into expect because it will not return a promise. async functions always return a promise , so it's enough to just call your method inside expect (without wrapping it into a method).

I hope this is clear :) If you have any questions - feel free to ask.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM