Mongoose document: Execute hook manually for testing

Viewed 296

I'd like to test some document transformation which is executed in a Mongoose pre save hook. Simplified example:

mySchema.pre('save', function(callback) {
  this.property = this.property + '_modified';
  callback();
});

Test:

var testDoc = new MyDocument({ property: 'foo' });
// TODO -- how to execute the hook?
expect(testDoc.property).to.eql('foo_modified');

How can I manually execute this hook?

2 Answers

Okay, here’s what we did at the end. We replaced the $__save function with a no operation implementation:

// overwrite the $__save with a no op. function, 
// so that mongoose does not try to write to the database
testDoc.$__save = function(options, callback) {
  callback(null, this);
};

This prevents hitting the database, but the pre hook obviously still gets called.

testDoc.save(function(err, doc) {
  expect(doc.property).to.eql('foo_modified');
  done();
});

Mission accomplished.

As of Mongoose 5.9, using the $__save override doesn't seem to work, so here is a replacement that doesn't require you to call the save() method directly:

const runPreSaveHooks = async (doc) => {
  return new Promise((resolve, reject) => {
    doc.constructor._middleware.execPre("save", doc, [doc], (error) => {
      error ? reject(error) : resolve(doc);
    });
  });
};

await runPreSaveHooks(testDoc);
expect(testDoc.property).to.eql('foo_modified');
Related