Mauricio Dziedzinski
Mauricio Dziedzinski

Reputation: 507

Unit testing mongoose validation with promise resolve/reject

I'm struggling to find a way to unit test the validation of a field in mongoose. I currently have the following test:

it('should be invalid if googleId is empty', () => 
  testBook.googleId = '';
  const newBook = new Book(testBook);
  return newBook.validate().catch((err) => {
    should.exist(err.errors.googleId);
  });
});

This test is not working as intended because, if I have a correct validation for googleId, the test will pass because it will assert the err.errors.googleId exists, but if I don't have any validation for googleId, it will also pass because the .catch() never gets called and it assumes the test is passing.

I've tried putting should.fail() inside a .then(), but that way it always ends up in .catch() but with different errors, if there's no validation it will be catched with the should.fail() error, if there's validation it will catch with the model validation error.

What would be the best way to achieve this kind of testing?

Thanks alot!

EDIT: I've tried using the callback of newBook.validate() and it works, but I never use callbacks for model methods, I always tend to use promises, so should I be using the callback in this particular case or there's still a better way to handle it using promises?

Upvotes: 0

Views: 680

Answers (2)

Matt
Matt

Reputation: 74909

There is a chai-as-promised plugin that includes helpers to make Promise testing work more like normal chai expect/should does.

.rejectedWith and .rejected handle errors largely like regular .throw.

const chai = require('chai')
chai.should()
chai.use(require('chai-as-promised'))

it('should be invalid if googleId is empty', function(){
  testBook.googleId = ''
  const newBook = new Book(testBook)
  return newBook.validate()
     .should.be.rejectedWith('Validation Failed')
     .and.eventually.have.nested.property('errors.googleId')
});

Just make sure you load the plugin last if you are loading any other chai plugins otherwise things go haywire.

Upvotes: 1

Mark
Mark

Reputation: 92471

You can use the second parameter to then and put something that throws in the first for example:

return newBook.validate().then(
    resp => throw new Error("Test failed this should not resolve"),
    err =>  should.exist(err.errors.googleId);
});

So now if the newBook.validate() is not rejected the test will fail. Since you aren't using catch() you don't stop it from causing the test to fail like it should. If the promise is rejected like it should be your test passes (assuming it meets the conditions set). This works because unlike catch() the error callback of then() doesn't catch errors thrown in then(). Of course you can put anything in the first callback that throws an error like assert.fail() or whatever your library has.

Upvotes: 2

Related Questions