Fredo Corleone
Fredo Corleone

Reputation: 572

Mocha .then(done) doesn't work as expected

This question is not about a problem which I can't solve, it is just a curiosity. I'm not very experienced with Mocha, but there's something interesting I've stumbled upon already.

What I want is to use done() to tell Mocha the promise has been resolved.

The following code DOESN'T work:

beforeEach((done) => {
  user = new User({ name: 'Dummy' })
  user.save()
    .then(done)
})

I know I'm passing the result of the user.save() promise to done, but I think it shouldn't be a problem.

Instead this other code works:

beforeEach((done) => {
  user = new User({ name: 'Dummy' })
  user.save()
    .then(() => done())
})

It seems to me that Mocha done() has some kind of control flow which leads to: Error: done() invoked with non-Error: {"_id":"5b65b9d2669f7b2ec0a3d503","name":"Dummy","__v":0}

Is it because done() wants strictly an error as its argument?

Why done() does even care about what I pass to it?

Can you make some example showing why done() argument to be an Error is useful?

Thanks in advance ;)

Upvotes: 0

Views: 624

Answers (1)

deerawan
deerawan

Reputation: 8443

It is because done() in Mocha only accepts Error argument. In your case, your save() method returns json object not an Error ie new Error('failed save').

If we take a look at mocha test file, we can see that it won't accept other type of arguments.

// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L358

describe('when done() is invoked with a string', function () {
  it('should invoke the callback', function (done) {
    var test = new Runnable('foo', function (done) {
      done('Test error'); // specify done with string/text argument
    });

    test.run(function (err) {
      assert(err.message === 'done() invoked with non-Error: Test error');
      done();
    });
  });
});

But if we see the test when the argument is Error, it works

// https://github.com/mochajs/mocha/blob/master/test/unit/runnable.spec.js#L345

describe('when an error is passed', function () {
  it('should invoke the callback', function (done) {
    var test = new Runnable('foo', function (done) {
      done(new Error('fail'));
    });

    test.run(function (err) {
      assert(err.message === 'fail');
      done();
    });
  });
});

Btw, I suggest that you avoid using done since mocha supports promise by specifying return statement. So, we change the code into

beforeEach(() => {
  user = new User({ name: 'Dummy' })
  return user.save().then(user => {
    // antyhing todo with user
  });
});

Hope it helps.

Upvotes: 1

Related Questions