Search code examples
node.jstestingmongoosemocha.jssinon

stub of .save() returns nothing and times out


I need to assert return of naturalController.add() with the fixture.

I have the function add in my controller in promise, and in my model has a .pre() (which seems to me the origin of the problem) that is called before the .save() I have no idea what is happens, someone can help me?

What the test does:

  1. Instantiates a controller loading the default model.
  2. Calls the .add() method with a promise with valid data(it passes ajv which I omitted).
  3. The class instantiates a new document (I think the problem is around here).
  4. The class calls the .save() method of the document instance(everything stops here and I get a time out at mocha).

At another test everything works fine. I can add as many documents as I wish through postman and integration tests.

Testing:

import sinon from 'sinon';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
import Bluebird from 'bluebird';
import NaturalPersonModel from './../../../src/models/naturalPersonModel';
import naturalPersonFixture from '../../fixtures/naturalPersonFixture';

describe('NaturalController', function() {
      var stubSave,
        naturalController = new NaturalController();

      context('#add', function() {

        beforeEach(function() {
          stubSave = sinon.stub(NaturalPersonModel.prototype, "save");
        });

        afterEach(function() {
          stubSave.restore();
        });

        it('resolve when data is ok', function() {
          stubSave.returns(Bluebird.resolve(naturalPersonFixture.save));
          return naturalController.add(naturalPersonFixture.add)
            .then(function(value) {
              chai.assert(value === naturalPersonFixture.save);
            });
        });
      });
    });

class code:

import Bluebird from 'bluebird';
import NaturalPerson from './../models/naturalPersonModel';

class NaturalController {
  constructor() {
    this.naturalPersonModel = NaturalPerson;
  }

      add(data) {
            var newNP = new this.naturalPersonModel(data);
            return newNP.save()
            .catch(function(reason){
              throw new Error(reason);
            });
      }
    }
export default NaturalController;

model:

var mongoose = require('mongoose');
mongoose.Promise = require('bluebird');
import Bluebird from 'bluebird';
var autoIncrement = require('mongoose-auto-increment');
autoIncrement.initialize(mongoose.connection);

var naturalPersonSchemaBr = new mongoose.Schema({
  naturalPersonData:{
    personUUID: String,
    nome: {type: String,required:true},
    sobrenome: {type: String,required:true},
    cpf: {type: String,required:true,unique:true},
    rg: {type: String,required:true},
    purchase:{
      firstBuyStoreUUID: Number,
      firstSellerUUID: Number
    }
  }
});
naturalPersonSchemaBr.methods.capitalizeFn = function(obj, list) {
   String.prototype.capitalize = function() {
     return this.split(' ').map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(' ');
   };
   list.forEach((attr) => {
     if (obj[attr] && typeof(obj[attr]) === 'string') {
       obj[attr] = obj[attr].toLowerCase().capitalize();
     }
   });
 };

 naturalPersonSchemaBr.plugin(autoIncrement.plugin, {
   model: 'NaturalPerson',
   field: 'UUIDcounter',
   startAt: 1,
   incrementBy: 1
 });

naturalPersonSchemaBr.pre('save', function(next) {
  var user = this;
  user.naturalPersonData.personUUID = "NP"+ user.UUIDcounter;
  console.log("user",user);
  var list = ['nome','sobrenome','cpf','rg'];
  naturalPersonSchemaBr.methods.capitalizeFn(user.naturalPersonData,list);
  return next();
});
module.exports = mongoose.model('NaturalPerson', naturalPersonSchemaBr);

Solution

  • You must be doing something wrong, because your test seems to work :-) The test code had some errors, making it not immediately runnable, such as the fixture code being missing, but I just replaced the import naturalPersonFixture .. with a constant, seeing that it was just an object from the context.

    I uploaded all the files as a gist for easy download and playing with. The example was far from minimal, but I still got it working by doing this:

    1. Install Mongo
    2. Run mongod --dbpath /tmp/testdb
    3. npm i mongoose mongoose-auto-increment mocha chai-as-promised sinon bluebird babel-plugin-transform-object-rest-spread babel-cli babel-eslint babel-plugin-transform-class-properties babel-plugin-transform-react-jsx babel-preset-es2015 babel-root-slash-import
    4. Set up babel (see gist link)
    5. Run the test: mocha --compilers js:babel-register -s 4 test.js

    Not exactly minimal! But it worked :D

    $  mocha --compilers js:babel-register  test.js
    
    
      NaturalController
        #add
          ✓ resolve when data is ok (5ms)
    
    
      1 passing (78ms)