UNPKG

@lykmapipo/mongoose-test-helpers

Version:
314 lines (289 loc) 7.57 kB
/** * @module mongoose-test-helpers * @description Re-usable test helpers for mongoose * @author lally elias <lallyelias87@mail.com> * @since 0.1.0 * @version 0.1.0 * @license MIT * @example * * import { setup, clear, drop } from '@lykmapipo/mongoose-test-helpers'; * before(done => { setup(done) }); * after(done => { clear(done) }); * after(done => { drop(done) }); */ /* setup test environment */ /* dependencies */ import _ from 'lodash'; import { chai, expect, fake, faker, mock, restore, should, sinon, spy, stub, } from '@lykmapipo/test-helpers'; import { parallel } from 'async'; import { connect as connectDatabase, isConnected, isModel, disconnect, clear, drop, model as getModel, createModel, enableDebug, disableDebug, } from '@lykmapipo/mongoose-connection'; import { isInstance } from '@lykmapipo/mongoose-common'; import mongooseFaker from '@lykmapipo/mongoose-faker'; /* setup sinon mongoose */ import './sinon_mongoose'; process.env.NODE_ENV = 'test'; process.env.DEBUG = true; process.env.MONGODB_URI = 'mongodb://127.0.0.1/test'; /** * @function connect * @name connect * @description Opens the default mongoose connection * @param {string} [url] valid mongodb conenction string. if not provided it * will be obtained from process.env.MONGODB_URI * @param {Function} done a callback to invoke on success or failure * @author lally elias <lallyelias87@mail.com> * @since 0.1.0 * @version 0.1.0 * @example * * connect(done); * connect(<url>, done); */ export const connect = (url, done) => { // ensure test database const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1/test'; // normalize arguments const $url = _.isFunction(url) ? MONGODB_URI : url; const $done = _.isFunction(url) ? url : done; // establish mongoose connection connectDatabase($url, $done); }; /** * @function disconnect * @name disconnect * @description Close all mongoose connection * @param {Function} done a callback to invoke on success or failure * @author lally elias <lallyelias87@mail.com> * @since 0.1.0 * @version 0.1.0 * @example * * disconnect(done); */ export { disconnect }; /** * @function clear * @name clear * @description Clear provided collection or all if none give * @param {string[] | string} modelNames name of models to clear * @param {Function} done a callback to invoke on success or failure * @author lally elias <lallyelias87@mail.com> * @since 0.1.0 * @version 0.1.0 * @example * * clear('User', 'Profile', done); * clear(done); */ export { clear }; /** * @function drop * @name drop * @description Deletes the given database, including all collections, * documents, and indexes * @param {Function} done a callback to invoke on success or failure * @author lally elias <lallyelias87@mail.com> * @since 0.1.0 * @version 0.1.0 * @example * * drop(done); */ export { drop }; /** * @function create * @name create * @param {...any} instances valid mongoose model instances and * optional callback at end * @description Persist given model instances * @returns {object|object[]} created model instances * @author lally elias <lallyelias87@mail.com> * @since 0.1.0 * @version 0.1.0 * @example * * create(user, done); * create(user, profile, done); * create(user, profile, done); */ export const create = (...instances) => { // collect provided instances let $instances = [].concat(...instances); // obtain callback const $done = _.last( _.filter([...$instances], (instance) => { return !isInstance(instance); }) ); // collect actual model instances $instances = _.filter([...$instances], (instance) => { return isInstance(instance); }); // compact and ensure unique instances by _id $instances = _.uniqBy(_.compact([...$instances]), '_id'); // map instances to save // TODO for same model use insertMany const connected = isConnected(); let saves = _.map([...$instances], (instance) => { if (connected && instance.save) { const save = (next) => { const fn = instance.post || instance.save; fn.call(instance, (error, saved) => { next(error, saved); }); }; return save; } return undefined; }); // compact saves saves = _.compact([...saves]); // save return parallel(saves, $done); }; /** * @function createTestModel * @name createTestModel * @description Create a test model for testing * @param {object} [schema] model schema definition * @param {...Function} [plugins] list of plugins to apply to schema * @returns {object} valid mongoose model * @author lally elias <lallyelias87@mail.com> * @since 0.4.0 * @version 0.1.0 * @example * * const User = createTestModel(); * const User = createTestModel({ name: { type: String } }, autopopulate); */ export const createTestModel = (schema, ...plugins) => { // ensure schema definition const definition = _.merge( {}, { name: { type: String, index: true, searchable: true, taggable: true, fake: (f) => f.name.findName(), }, }, schema ); // obtain options const options = _.first([...plugins], _.isPlainObject); // register dynamic model const testModel = createModel( definition, { timestamps: true, ...options }, ..._.filter([...plugins, mongooseFaker], _.isFunction) ); // return created model return testModel; }; /** * @function mockModel * @name mockModel * @description Mock existing mongoose model * @param {object} model valid mongoose model * @returns {object} valid mock of provided mongoose model * @author lally elias <lallyelias87@mail.com> * @since 0.5.0 * @version 0.1.0 * @example * * const Mock = mockModel(User); * const find = Mock.expects('find').yields(null, [{...}]); * * User.find((error, results) => { * Mock.verify(); * Mock.restore(); * expect(find).to.have.been.calledOnce; * expect(error).to.not.exist; * expect(results).to.exist; * expect(results).to.have.have.length(1); * done(error, results); * }); */ export const mockModel = (model) => { const mocked = isModel(model) ? sinon.mock(model) : undefined; return mocked; }; /** * @function mockInstance * @name mockInstance * @description Mock provided model instance * @param {object} instance valid model instance * @returns {object} valid mock of provided model instance * @author lally elias <lallyelias87@mail.com> * @since 0.5.0 * @version 0.1.0 * @example * * const mock = mockInstance(new User()); * const save = mock.expects('save').yields(null, {...}); * * user.save((error, results) => { * Mock.verify(); * Mock.restore(); * expect(save).to.have.been.calledOnce; * expect(error).to.not.exist; * expect(result).to.exist; * done(error, results); * }); */ export const mockInstance = (instance) => { const mocked = isInstance(instance) ? sinon.mock(instance) : undefined; return mocked; }; /** * @function getModel * @name getModel * @description Try obtain already registered * @author lally elias <lallyelias87@mail.com> * @since 0.1.0 * @version 0.1.0 * @example * * const User = getModel('User'); * const User = model('User'); */ export const model = getModel; export { getModel }; /* shortcuts */ export { enableDebug }; export { disableDebug }; export { chai }; export { expect }; export { fake }; export { faker }; export { mock }; export { restore }; export { should }; export { sinon }; export { spy }; export { stub };