103

I have a callback function in before() which is for cleaning database. Is everything in before() guaranteed to finish before it() starts?

before(function(){
   db.collection('user').remove({}, function(res){}); // is it guaranteed to finish before it()? 
});

it('test spec', function(done){
  // do the test
});

after(function(){
});
Blackus
  • 6,883
  • 5
  • 40
  • 51
Nicolas S.Xu
  • 13,794
  • 31
  • 84
  • 129
  • 1
    This should work. You just need to make sure you return a promise from your `before` handler. E.g. `before(function () { return db.collection...}` – broofa Jan 23 '18 at 21:08

3 Answers3

140

For new mocha versions :

You can now return a promise to mocha, and mocha will wait for it to complete before proceeding. For example, the following test will pass :

let a = 0;
before(() => {
  return new Promise((resolve) => {
    setTimeout(() => {
      a = 1;
      resolve();
    }, 200);
  });
});
it('a should be set to 1', () => {
  assert(a === 1);
});

You can find the documentation here

For older mocha versions :

If you want your asynchronous request to be completed before everything else happens, you need to use the done parameter in your before request, and call it in the callback.

Mocha will then wait until done is called to start processing the following blocks.

before(function (done) {
   db.collection('user').remove({}, function (res) { done(); }); // It is now guaranteed to finish before 'it' starts.
})

it('test spec', function (done) {
  // execute test
});

after(function() {});

You should be careful though, as not stubbing the database for unit testing may strongly slow the execution, as requests in a database may be pretty long compared to simple code execution.

For more information, see the Mocha documentation.

Clément Berthou
  • 1,928
  • 1
  • 13
  • 12
  • Note that if the asynchronous operation takes too long, you will get a failure message that isn't very helpful: https://stackoverflow.com/a/48087201/1827734 – BrDaHa Jan 04 '18 at 01:50
  • Mocha now supports promises in hooks - https://mochajs.org/#working-with-promises . No need to use `done`. Just return a promise. – broofa Jan 23 '18 at 21:08
  • You can also : `before(function () { return db.collection('user').remove({}); })` since `remove()` returns a promise, no need to wrap it in a `new Promise()` – Brent Greeff May 29 '19 at 13:27
11

Hopefully your db.collection() should return a promise. If yes then you can also use async keyword in before()

// Note: I am using Mocha 5.2.0.
before(async function(){
   await db.collection('user').remove({}, function(res){}); // it is now guaranteed to finish before it()
});
Mandeep Singh
  • 335
  • 3
  • 10
  • 6
    How about for `after()`? My `await` works fine when I call it in `before()` (it deletes a DB entry), but if I put the exact same thing into `after()`, it does not delete anything by the time a second `describe()...it()` begins and fails due to the data not being removed. – Juha Untinen Oct 12 '19 at 21:25
-1

you can use an IIFE (Immediately Invoked Function Expression).

Here is an example:

before(function () {
    (async () => {
        try {
            await mongoose.connect(mongo.url, { useNewUrlParser: true, useUnifiedTopology: true });
        } catch (err) {
            console.log(err);
        }
    })();
});
Yarden Porat
  • 15
  • 1
  • 3