1

I have the following test code in NodeJS:

'use strict';

// Example class to be tested
class AuthController {

    constructor() {
        console.log('Auth Controller test!');
    }

    isAuthorizedAsync(roles, neededRole) {
        return new Promise((resolve, reject) => {
            return resolve(roles.indexOf(neededRole) >= 0);
        });
    }
}

module.exports = AuthController;

And the following mocha test code:

'use strict';

const assert         = require('assert');
const AuthController = require('../../lib/controllers/auth.controller');

describe('isAuthorizedAsync', () => {
    let authController = null;

    beforeEach(done =>  {
        authController = new AuthController();
        done();
    });

    it('Should return false if not authorized', function(done) {
        this.timeout(10000);    

        authController.isAuthorizedAsync(['user'], 'admin')
            .then(isAuth => {
                assert.equal(true, isAuth);
                done();
            })
            .catch(err => {
                throw(err);
                done();
            });
    });    
});

which throws the following error:

 1 failing

1) AuthController
    isAuthorizedAsync
      Should return false if not authorized:
  Error: Timeout of 10000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (c:\supportal\node_modules\ttm-module\test\controllers\auth.controller.spec.js)

I have tried increasing the default mocha test timeout to 10secs and made sure that the promise resolves. I am new to mocha. Am I missing something here?

Rookie
  • 5,179
  • 13
  • 41
  • 65
  • as per my understanding, there's not issue with Mocha config.You need to resolved promise first in test case after that only you can test your suite – Arpit Srivastava Aug 06 '18 at 17:27
  • Ya I made sure that the promise resolves by console logging out a test message in the .then() block. Still seem to be getting this error, so not sure.. – Rookie Aug 06 '18 at 17:28
  • Like this spyOn(authController, 'isAuthorizedAsync').and.returnValue(Promise.resolve(true)); – Arpit Srivastava Aug 06 '18 at 17:29
  • I found a workaround using chai-as-promised as discussed in this SO post: https://stackoverflow.com/questions/26571328/how-do-i-properly-test-promises-with-mocha-and-chai. Is this the right approach? – Rookie Aug 06 '18 at 18:00
  • chai-as-promised is mainly a convenience for people who don't want to do lots of promise chains in their tests. You certainly don't need it for this. You can use it, but I recommend making sure you understand how to do it normally as well. – sripberger Aug 13 '18 at 15:34

1 Answers1

1

The problem here is that you're not using the mocha async API correctly. To cause a failure with a done callback, you're supposed to provide an error as the first argument when you invoke it.

As written, your assertion in the then handler throws, which skips over the first done invocation and goes to the catch handler. That catch handler in turn re-throws that same error, similarly preventing you from ever reaching the second done callback.

What you get is an unhandled promise rejection and no invocation of done, leading to a mocha test timeout, possibly with a warning message about the unhandled rejection, depending on which version of node you're using.

Quickest fix would be to use the done callback correctly:

it('Should return false if not authorized', function(done) {
    authController.isAuthorizedAsync(['user'], 'admin')
        .then(isAuth => {
            assert.equal(true, isAuth);
            done();
        })
        .catch(err => {
            done(err); // Note the difference
        });
});

A much cleaner fix would be to use Mocha's built-in promise support by returning the chained promise. This removes the need to handle the failure case explicitly:

it('Should return false if not authorized', function() {
    return authController.isAuthorizedAsync(['user'], 'admin')
        .then(isAuth => {
            assert.equal(true, isAuth);
        });
});
sripberger
  • 1,682
  • 1
  • 10
  • 21