node.jssinonchaichai-as-promised

Sinon Stub gives unexpected UnhandledPromiseRejectionWarning


I have a function like so:

    static async performDatabaseConnectivityHealthCheck(logger) {

    let con;
    let ret;

    try {

        con = mysql.createConnection({
            host: config.db.host,
            user: config.db.user,
            password: config.db.password,
            database: config.db.db,
        });

        const { retData } = await sqlFileReader.read('./src/database/sql/healthcheck.sql', [config.db.db], con, logger);

        // Do something with retData.....

    }
    catch (error) {
        logger.error(error.message);
        throw error;
    }
    finally {
        if (con) {
            con.end();
        }
    }
    return ret;

}

And a test like so:

    it('throws a \'Database Healthcheck Error\' error when the Database Healthcheck gives the wrong data', async () => {

//Some irrelevant details here including providing rars for rars.logger in the following...

    sandbox.stub(sqlFileReader, 'read').returns(Promise.reject(new Error("ER_PROCACCESS_DENIED_ERROR: execute command denied to user 'dchambers'@'%' for routine 'uk_txtloan.connection_ids'")));

    expect(async () => {
        await RiskAffordabilityReportService.performDatabaseConnectivityHealthCheck(rars.logger);
    }).to.throw('ER_PROCACCESS_DENIED_ERROR: execute command denied to user \'dchambers\'@\'%\' for routine \'uk_txtloan.connection_ids\'');

});

I have two issues. Firstly, the sandbox.stub line gives the following warning, which I am confused about since I ask that the Promise is rejected!

UnhandledPromiseRejectionWarning: Error: ER_PROCACCESS_DENIED_ERROR: execute command denied to user 'dchambers'@'%' for routine 'uk_txtloan.connection_ids'

Secondly, the test doesn't pass:

AssertionError: expected [Function] to throw an error.

I'm mainly wondering about the warning. I have tried the following syntax and they give the same error:

sandbox.stub(sqlFileReader, 'read').throws(new Error("ER_PROCACCESS_DENIED_ERROR: execute command denied to user 'dchambers'@'%' for routine 'uk_txtloan.connection_ids'"));

sandbox.stub(sqlFileReader, 'read').resolves(Promise.reject(new Error("ER_PROCACCESS_DENIED_ERROR: execute command denied to user 'dchambers'@'%' for routine 'uk_txtloan.connection_ids'")));

sandbox.stub(sqlFileReader, 'read').rejects(new Error("ER_PROCACCESS_DENIED_ERROR: execute command denied to user 'dchambers'@'%' for routine 'uk_txtloan.connection_ids'"));

What is the proper way to eliminate the warning? Bonus: Make the test pass.


Solution

  • Unhandled promise rejection error is thrown in recent Promise implementations if rejected promise wasn't handled, i.e. wasn't chained with catch(...) or then(..., ...).

    Chai to.throw assertion wraps a function with try..catch, but no error is thrown in async function. async function is syntactic sugar for a function that returns a promise. Uncaught error inside async function results in returning a rejected promise. Instead, it should be asserted with chai-as-promised assertion:

    expect(RiskAffordabilityReportService.performDatabaseConnectivityHealthCheck(rars.logger))
    .to.be.rejectedWith(
      Error,
      'ER_PROCACCESS_DENIED_ERROR: execute command denied to user \'dchambers\'@\'%\' for routine \'uk_txtloan.connection_ids\''
    );