Saurav Haloi
Saurav Haloi

Reputation: 343

How to enforce before() to complete before executing tests in Mocha?

I am a newbie to the JavaScript ecosystem. I am trying to write couple of API tests for my REST APIs using Mocha/Chai. My requirement is that I have to cleanup my database before running each test cases. So, I wrote the following code in a file called dbCleanup.js

var config = require("config.json");
const pg = require('pg');

var connectionString = config.pgConnectionString
console.log("DB Connection String: ", connectionString)

function dbCleanup() {

    var dbTables = ["projects", "employees"];

    var pgClient = new pg.Client(connectionString);

    var promise = new Promise(function (resolve, reject) {
        pg.connect(connectionString, (err, pgClient, done) => {
            if (err) {
                done();
                console.log(err);
                reject();
            }

            for (i = 0; i < dbTables.length; i++) {
                query = "TRUNCATE " + dbTables[i] + " CASCADE;"
                pgClient.query(query, function (err, res) {
                    if (err) {
                        done();
                        console.error('error running query', err);
                        reject();
                    }
                    resolve();
                });
            }
        });
    });

    pgClient.end()

    return promise;
}

exports.dbCleanup = dbCleanup;

I have another file called globalBefore.js where I have the following code:

var dbCleanup = require('./dbCleanup.js').dbCleanup;

function _beforeClean(done) {
    try {
        dbCleanup()
            .then(done)
    } catch (err) {
        console.error(err);
    }
}

exports.beforeCleanup = _beforeClean;

Now in my Mocha test.js file, I try to call the database cleanup function as follows:

var request = require("request");
var rp = require("request-promise");
var config = require("../config.json");
var expect = require('chai').expect;
var data = require("./data.json");

var globalBefore = require("../globalBefore.js");


describe("POST /employees/", function () {

    console.log("clearing db tables...")
    before(globalBefore.beforeCleanup, function (done) {
        done();
    });

    beforeEach(function (done) {
    ... do some business logic related work here ...
    });


    it.only('Try create an employee', function (done) {
    ... API call to create an employee and use Chai assertions to validate ...
    });
});

The problem I am facing is, Mocha goes ahead with running my tests even before the dbCleanup() function completes. This causes my DB to go kaput and I encounter undesired behavior.

Can anyone from the SO community please help? I tried various options I could find in the web, but not able to fix the issue. As shown in the code fragment, I hoped that using a Promise should have solved the problem

To be more generic, how do I enforce the instructions inside a before clause to complete before Mocha runs the it clauses for the tests?

Thanks!

Upvotes: 0

Views: 940

Answers (1)

user5085788
user5085788

Reputation:

You are using before the wrong way. Try this instead:

before(function (done) {
    globalBefore.beforeCleanup(done);
});

or

before(globalBefore.beforeCleanup);

And in globalBefore.js:

var dbCleanup = require('./dbCleanup.js').dbCleanup;

function _beforeClean(done) {
    dbCleanup().then(done).catch(done);
}

exports.beforeCleanup = _beforeClean;

EXAMPLE (I only changed dbCleanup.js to use a another promise)

dbCleanup.js

function dbCleanup() {

    return new Promise(function (resolve, reject) {
        setTimeout(resolve, 2000);
    });

}

exports.dbCleanup = dbCleanup;

globalBefore.js

var dbCleanup = require('./dbCleanup.js').dbCleanup;

function _beforeClean(done) {
    dbCleanup().then(done).catch(done);
}

exports.beforeCleanup = _beforeClean;

index.js

var globalBefore = require("../globalBefore.js");

describe("POST /employees/", function () {

    this.timeout(5000); // because the promise take 2000ms

    console.log("clearing db tables...")
    before(function (done) {
        console.log('before calling beforeCleanup');
        globalBefore.beforeCleanup(function () {
            console.log('after calling beforeCleanup');
            done(); // done cleaning db
        });
    });

    /* Without the console.logs
    console.log("clearing db tables...");
    before(globalBefore.beforeCleanup)
    */

    beforeEach(function (done) {
        // ... do some business logic related work here ...
        console.log('beforeEach');
        done();
    });


    it.only('Try create an employee', function (done) {
        // ... API call to create an employee and use Chai assertions to validate ...
        console.log('it');
        done();
    });
});

OUTPUT

clearing db tables...

  POST /employees/
before calling beforeCleanup
after calling beforeCleanup
beforeEach
it
    √ Try create an employee


  1 passing (2s)

https://mochajs.org/#hooks

Upvotes: 1

Related Questions