Testing Mongoose plugin with Jest and shared data

Grrrr just spent the better half of 2 hours trying to figure out why my Jest tests were not working for a Mongoose plugin I’m developing. It turns out that the schema configuration I was sharing between the tests was the culprit.

let Mongoose = require('mongoose');
let Schema = Mongoose.Schema;
const _ = require('lodash');
var mongooseI18n = require('../src/mongoose/mongoose-i18n-localize');

Mongoose.set('debug', true);

const simpleSchemaConfig = {
  firstName: { type: String, i18n: true, required: true },
  lastName: { type: String, i18n: false, required: true }
};

describe('Mongoose i18n localize', () => {
  beforeEach(() => {
    // Clear compiled models to avoid OverwriteModelError
    Mongoose.models = {};
  });
  
  it('should throw an exception if the locales array is not defined', () => {
    const SimpleTestSchema = new Schema(simpleSchemaConfig);
    expect(() => {
      SimpleTestSchema.plugin(mongooseI18n, {
        defaultLocale: 'nl',
        allLocalesRequired: false
      });
    }).toThrow('The required option locales array not provided or empty');
  });

  it('should throw an exception if the locales array is an empty array', () => {
    const SimpleTestSchema = new Schema(simpleSchemaConfig);
    expect(() => {
      SimpleTestSchema.plugin(mongooseI18n, {
        locales: [],
        defaultLocale: 'nl',
        allLocalesRequired: false
      });
    }).toThrow('The required option locales array not provided or empty');
  });

  ...

});

The plugin makes changes to the schema configuration and these changes were made to the shared config. The fix I used was to make a copy of the shared config with lodash’s cloneDeep function. The only change I needed to make was the schema initialization.

const SimpleTestSchema = new Schema(_.cloneDeep(simpleSchemaConfig));

Now my tests run like a charm 🙂

Bonus

When I initially ran into the above problem, I was also initializing the schema globally. I thought that was the problem, so I moved the following statement to each test case.

const SimpleTestSchema = new Schema(simpleSchemaConfig);

That caused the exception OverwriteModelError, because I was trying to initialize a compiled model. The fix for this problem was to remove all models between test cases using beforeEach. The following code does the trick.

beforeEach(() => {
  // Clear compiled models to avoid OverwriteModelError
  Mongoose.models = {};
});

Hope this helps someone.

Adding fuzzy search to Feathers NeDB

Out of the box Feathers NeDB does not support fuzzy search. There is a hook that provides this functionality: feathers-nedb-fuzzy-search. It is really simple and straitforward to install and use.

  • Install
    npm install feathers-nedb-fuzzy-search --save
  • Configure
    Enable it for specifc services or alternatively enable it for all services in app.hooks.

    const search = require('feathers-nedb-fuzzy-search') 
    messages.hooks({
      before: {
        find: search()
      }
    })
  • Usage
    const messages = app.service('messages')
    messages.find({
      query: {
        $search: 'some string to search for'
      }
    })

    or

    http://mydomain.com/api/?search=Hello

Happy coding.

Adding hot reload to featherjs

Feathers is a very cool framework to quickly and easily setup API’s. Version 3 comes with a very cool CLI that generates all the scafolding code for you and makes it extremely easy to add services, hooks, etc. One thing that is missing is hot reloading to simplify the development proces. This is were nodemon comes to the rescue.

nodemon is a tool that helps developing node.js based applications by automatically restarting the node application when file changes in the directory are detected.

Setting nodemon up with Feather and Webpack si a simple two step proces.

  1. Install nodemon
    npm install --save-dev nodemon
  2. Add one line to the scripts section of Webpacks package.json file
    ...
      },
      "scripts": {
        "test": "npm run eslint && npm run mocha",
        "dev": "node ./node_modules/nodemon/bin/nodemon.js src/",
        "eslint": "eslint src/. test/. --config .eslintrc.json",
        "start": "node src/",
        "mocha": "mocha test/ --recursive"
      }
    ...

Now start Feathers using the following command.

npm run dev

That’s it, simple right?

Creating a simple REST server

For testing purposes I needed a quick and dirty way to create a REST server to server data. I found a very basic and easy to use REST server that stores data inside a JSON file. It is called json-server. Any changes you make will be saved to the JSON file.

Getting it up and running is very easy.

Install json-server:

npm install -g json-server

Create a JSON file containing the data, e.g. db.json:

{
    "products": [{
        "id": 1, "name": "coat", "price": 100.00
    }, {
        "id": 2, "name": "hat", "price": 30.00 
    }, { 
        "id": 3, "name": "umbrella", "price": 10.00 
    }]
}

Start json-server:

json-server --watch db.json

Now go to http://localhost:3000/products/1 and you will get:

{ "id": 1, "name": "coat", "price": 100.00 }

Check out the json-server GitHub page for all the other cool stuff you can do.

Happy coding.