Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Models not loading properly when trying to use Mocha testing

I'm trying to use mocha to test my express app. My folder structure is:

myapp
|-app
|--models
|-test
|--mocha-blanket.js
|--mocha
|--karma
|-server.js

server.js is my express server. I had that before in options.require, but the documentation said to use a blanket.js. My mocha-blanket.js is:

var path = require('path');
var srcDir = path.join(__dirname, '..', 'app');

require('blanket')({
  // Only files that match the pattern will be instrumented
  pattern: srcDir
});

My Gruntfile has:

mochaTest:
  options:
    reporter: "spec"
    require: 'test/mocha-blanket.js'
    # require: "server.js"
  coverage:
    options:
      reporter: 'html-cov',
      captureFile: 'mocha-coverage.html'
    src: ["test/mocha/**/*.js"]

The error I'm getting is:

>> Mocha exploded!
>> MissingSchemaError: Schema hasn't been registered for model "Company".
>> Use mongoose.model(name, schema)
>>     at Mongoose.model (/myapp/node_modules/mongoose/lib/index.js:315:13)
>>     at Object.<anonymous> (/myapp/test/mocha/controllers/company.js:4:22)
>>     at Module._compile (module.js:456:26)
>>     at Module._extensions..js (module.js:474:10)

I'm sure I'm doing something (or a lot of things) incorrectly. But I'm not sure what. Any ideas?

like image 690
Shamoon Avatar asked Feb 14 '14 20:02

Shamoon


2 Answers

I think your testing code isn't properly initializing your application, specifically initialization of the Mongoose schema and models.

In mocha/controllers/company.js, you're probably using code similar to this:

var Company = mongoose.model('Company');

However, that will raise the error that you're getting if the initialization of the Company model (where you hook up the model with the schema) was skipped.

To give a very short standalone example, this code will fail with the same error:

var mongoose = require('mongoose');
var Company  = mongoose.model('Company');

This code, with the added initialization, works fine:

var mongoose = require('mongoose');

mongoose.model('Company', new mongoose.Schema());

var Company = mongoose.model('Company');
like image 51
robertklep Avatar answered Oct 23 '22 06:10

robertklep


You get this error because you have not explicitly 'loaded' your models to mongoose. I have solved this issue with: 1 Models init script:

module.exports = {
  storage:{
    sample: require('models/storage/sample'),
    other models scoped to "storage" connection...
  },
  accounts: {
    company: require('models/accounts/company'),
    etc...
  }
};

this is kicked off once on each mongoose.createConnection callback:

var accounts = mongoose.createConnection(config.get('mongoose:accounts:uri'), config.get('mongoose:accounts:options'), function(err){
  if (err) throw err;
  console.log('connection to accounts database open');
  require('models/init').accounts;
});

it runs all your models declaration code and later in tests you have all your models registered.

Ensure database connection middleware. This guy makes you sure that connections are open and init scripts run successfully.

var storage = require('models').storage;
var accounts = require('models').accounts;

module.exports = function ensureDbConnectionMiddleware(req, res, next){
  var count = 0;
  var interval = setInterval(function(){
    if (storage._readyState === 1 && accounts._readyState === 1){
      clearInterval(interval);
      return process.nextTick(function(){
        next();
      });
    }else{
      if (count++ > 50){
        res.json({status: 0, message: 'Database offline'});
        throw new Error('Database is offline');
      }
    }
  }, 100);
};

Later in tests

var should = require('should');
var express = require('express');
var app = express();
app.use(express.bodyParser());
app.use(require('middleware/ensureDbConnection'));
require('routes')(app);
//etc...

I'm not sure if this is the best solution, but it works quite well. It certainly has one major caveat: you have to keep all this stuff in sync. However, you can try to delegate this to grunt.

like image 2
Eugene Kostrikov Avatar answered Oct 23 '22 05:10

Eugene Kostrikov