Dan
Dan

Reputation: 2167

Unit test: How to mock mongoose code when using populate?

I have a mongoose model with a static function that finds an employee document by ID and populates referenced manager and interviewer fields.

employeeSchema.statics.findAndPopulateById = function(id) {
  return this.findById(id)
    .populate("manager", "firstname lastname email")
    .populate("interviewer", "email")
    .then(employee => {
      if (!employee) {
        throw new errors.NotFoundError();
      }
      return employee;
    });
}

I understand how to test this function when it doesn't contain the populate chain, but the populate part is throwing me for a loop.

Specifically, I am trying to test that the NotFoundError exception is thrown when no matching record is found, but I am confused how to mock the findById method so that .populate() can be called on the return value.

If I were testing this method without the .populate() chain, I would do something like

let findByIdMock = sandbox.stub(Employee, 'findById');
findByIdMock.resolves(null);

return expect(Employee.findAndPopulateById('123')).to.be.rejectedWith(errors.NotFoundError);

But this approach, of course, doesn't work when populate is involved. I think I should be returning a mocked query or something similar, but I also need to be able to call populate again on that mock or resolve it as a promise.

How do I write a test for this code? Should my function be structured differently?

Upvotes: 2

Views: 2424

Answers (1)

Dan
Dan

Reputation: 2167

Alright this ended up being easier than I anticipated, I just needed to add a call to .exec() between my final .populate() and .then() to make the test below work.

it("should throw not found exception if employee doesn't exist", () => {
  const mockQuery = {
    exec: sinon.stub().resolves(null)
  }
  mockQuery.populate = sinon.stub().returns(mockQuery);

  let findById = sandbox.stub(Employee, 'findById');
  findById.withArgs(mockId).returns(mockQuery);

  return expect(Employee.findAndPopulateById(mockId)).to.be.rejectedWith(errors.NotFoundError);
});

Upvotes: 3

Related Questions