@jazim/mock-mongoose
v1.0.1
Published
Package for mocking Mongoose models that can be utilized with any node.js testing library such as Jest, Mocha, and Vitest etc..
Downloads
1,612
Readme
Mock Mongoose
A Package for mocking Mongoose models that can be utilized with any node.js testing library such as Jest, Mocha, and Vitest etc ..
Installation
With NPM:
$ npm i @jazim/mock-mongoose -D
Import the library
const mockify = require('@jazim/mock-mongoose');
Usage
// user.js
const mongoose = require('mongoose');
const { Schema } = mongoose;
const schema = Schema({
name: String,
email: String,
created: { type: Date, default: Date.now },
});
module.exports = mongoose.model('User', schema);
mockify(Model).toReturn(obj, operation = 'find')
Returns a plain object.
// __tests__/user.test.js
const mockify = require('@jazim/mock-mongoose');
const model = require('./user');
describe('test mongoose User model', () => {
it('should return the doc with findById', () => {
const _doc = {
_id: '507f191e810c19729de860ea',
name: 'name',
email: '[email protected]',
};
mockify(model).toReturn(_doc, 'findOne');
return model.findById({ _id: '507f191e810c19729de860ea' }).then((doc) => {
expect(JSON.parse(JSON.stringify(doc))).toMatchObject(_doc);
});
});
it('should return the doc with update', () => {
const _doc = {
_id: '507f191e810c19729de860ea',
name: 'name',
email: '[email protected]',
};
mockify(model).toReturn(_doc, 'update');
return model
.update({ name: 'changed' }) // this won't really change anything
.where({ _id: '507f191e810c19729de860ea' })
.then((doc) => {
expect(JSON.parse(JSON.stringify(doc))).toMatchObject(_doc);
});
});
});
mockify(Model).toReturn(fn, operation = 'find')
Allows passing a function in order to return the result.
You will be able to inspect the query using the parameter passed to the function. This will be either a Mongoose Query or Aggregate class, depending on your usage.
You can use snapshots to automatically test that the queries sent out are valid.
// __tests__/user.test.js
const mockify = require('@jazim/mock-mongoose');
const model = require('./user');
describe('test mongoose User model', () => {
it('should return the doc with findById', () => {
const _doc = {
_id: '507f191e810c19729de860ea',
name: 'name',
email: '[email protected]',
};
const finderMock = (query) => {
expect(query.getQuery()).toMatchSnapshot('findById query');
if (query.getQuery()._id === '507f191e810c19729de860ea') {
return _doc;
}
};
mockify(model).toReturn(finderMock, 'findOne'); // findById is findOne
return model.findById('507f191e810c19729de860ea').then((doc) => {
expect(JSON.parse(JSON.stringify(doc))).toMatchObject(_doc);
});
});
});
mockify(Model).reset(operation = undefined)
will reset Model mock, if pass an operation, will reset only this operation mock.
it('should reset model mock', () => {
mockify(model).toReturn({ name: '1' });
mockify(model).toReturn({ name: '2' }, 'save');
mockify(model).reset(); // will reset all operations;
mockify(model).reset('find'); // will reset only find operations;
});
you can also chain mockify#ModelName
operations:
mockify(model)
.toReturn({ name: 'name' })
.toReturn({ name: 'a name too' }, 'findOne')
.toReturn({ name: 'another name' }, 'save')
.reset('find');
mockify.resetAll()
will reset all mocks.
beforeEach(() => {
mockify.resetAll();
});
Operations available:
- [x]
find
- for find query - [x]
findOne
- for findOne query - [x]
count
- for count query (deprecated) - [x]
countDocuments
for count query - [x]
estimatedDocumentCount
for count collection documents - [x]
distinct
- for distinct query - [x]
findOneAndUpdate
- for findOneAndUpdate query - [x]
findOneAndRemove
- for findOneAndRemove query - [x]
update
- for update query (DEPRECATED) - [x]
updateOne
- for updateOne query - [x]
updateMany
- for updateMany query - [x]
save
- for create, and save documentsModel.create()
orModel.save()
ordoc.save()
- [x]
remove
- for remove query (DEPRECATED) - [x]
deleteOne
- for deleteOne query - [x]
deleteMany
- for deleteMany query - [x]
aggregate
- for aggregate framework - [x]
insertMany
- forModel.insertMany()
bulk insert, can also pass{ lean: true, rawResult: true }
options. - [x]
orFail
- for findOne().orFail() query or similar ones.
Notes
All operations work with exec
, promise
and callback
.
if you are using
Model.create
and you don't pass a mock with mockify you'll receive the mongoose created doc (with ObjectId and transformations)validations are working as expected.
the returned document is an instance of mongoose Model.
deleteOne
andupdateOne
operation returns original mocked object.you can simulate Error by passing an Error to mockify:
mockify(model).toReturn(new Error('My Error'), 'save'); return model .create({ name: 'name', email: '[email protected]' }) .catch((err) => { expect(err.message).toBe('My Error'); });
you can mock
.populate
in your mocked result just be sure to change theSchema
's path to appropriate type (eg:Object
|Mixed
):User.schema.path('foreignKey', Object); const doc = { email: '[email protected]', foreignKey: { _id: '5ca4af76384306089c1c30ba', name: 'test', value: 'test', }, name: 'Name', saveCount: 1, }; mockify(User).toReturn(doc); const result = await User.find(); expect(result).toMatchObject(doc);
no connection is made to the database (mongoose.connect is mock function)
will work with node 6.4.x. tested with mongoose 4.x and jest 20.x and mocha.
check tests for more, feel free to fork and contribute.
Recent Changes:
mockify.ModelName
is deprecated,mockify(Model)
is the now the recommended usage, withModel
being a Mongoose model class.Alternatively, you may pass a string with the model name.
mockify(Model).toReturn((query) => value)
can now take also take a function as a parameter.The function is called with either a Query or Aggregate object from Mongoose, depending on the request. This allows tests to ensure that proper queries are sent out, and helps with regression testing.