Jarosław Rewers
Jarosław Rewers

Reputation: 1089

Wrapping in setTimeout required for properly working test in Mocha

Im writing tests for my Node app

'use strict';
const babelRegister = require('babel-register');
const babelPolyfill = require('babel-polyfill');
const chai = require('chai');
const sinon = require('sinon');
chai.should();
const bcrypt = require('bcryptjs');
const mongoose = require('mongoose');
const passport = require('passport');
const localStrategy = require('passport-local');

describe('test', function () {

    beforeEach(function (done) {
        if (mongoose.connection.readyState === 0) {
            mongoose.connect('mongodb://localhost:27017/clearanceForm-test', function () {
                console.log("mongodb test connection open");
                done();
            });
        }
    });

    afterEach(function () {
        console.log("test finished");
    });

    it('logs in', function (done) {
        let Schema = mongoose.Schema;
        let test_schema = new Schema({
            username: String,
            password: String,
            group: {type: String, enum: ['clearance_unit_managers', 'clearance_unit_admins']}
        });
        let test_model = mongoose.model('test', test_schema);

        (async function example() {

            const unhashedPassword = Math.random().toString(36);
            const passed = {
                username: Math.random().toString(36),
                password: bcrypt.hashSync(unhashedPassword),
                group: 'clearance_unit_managers'
            };

            let saved = await new test_model(passed).save();
            let found = await test_model.findOne({username: saved.username}).exec();
            setTimeout(function () {
                found.username.should.not.equal(passed.username);
                done();
            });

        })();
    });

});

at the end of the code you can see that I hand to wrap assertion which should fail on purpose in setTimeOut - otherwise (when I pull assertion from setTimeout) I just get Error: timeout of 2000ms exceeded. If I do it without done() test if passing. If assertions are true then everything works ok...

Is it like assertion failure is executed as last in task queue, somehow after done() was already executed in stack.

Could someone explain this to me? Thanks in advance :)

Upvotes: 0

Views: 175

Answers (1)

robertklep
robertklep

Reputation: 203231

Your rather creative way of using async/await swallows the exception thrown by the assertion, which causes done() never to get called and the test to time out.

You can make the entire test function async instead:

it('logs in', async () => {
  ...
  let found = await test_model.findOne({username: saved.username});
  found.username.should.not.equal(passed.username);
});

Or catch the assertion exception explicitly and call done() with the error:

try {
  found.username.should.not.equal(passed.username);
  done();
} catch(e) {
  done(e);
}

(which is ugly)

Upvotes: 1

Related Questions