0

I am using express-cassandra to perform CRUD operations. When I run the service and call create API using postman, everything works as expected.

However, it gives me an error "models.instance.table is not a constructor" when I call the same controller function using chai test cases.

Following are the code snippets :

dbClient.js : initialising connection with Cassandra

var models = require('express-cassandra');
var settings = require('../../settings.js');
var config = settings.UserService.database.cql;

//Tell express-cassandra to use the models-directory, and
//use bind() to load the models using cassandra configurations.
models.setDirectory( __dirname).bind(
    {
        clientOptions: {
            contactPoints: [config.host],
            protocolOptions: { port: config.port },
            keyspace: config.databaseName,
            queryOptions: {consistency: models.consistencies.one}
        },
        ormOptions: {
            //If your keyspace doesn't exist it will be created automatically
            //using the default replication strategy provided here.
            defaultReplicationStrategy : {
                class: 'SimpleStrategy',
                replication_factor: 1
            },
            migration: 'safe',
            createKeyspace: true
        }
    },
    function(err) {
        if(err) console.log(err);
        else console.log(models.timeuuid());
    }
);

module.exports =  models ;

QuestionnaireMasterModel.js : defining the model

"use strict";
module.exports = {
  fields: {
    id: {
      type: "uuid",
      default: { "$db_function": "uuid()" }
    },

    questionnaire_type: "varchar",

    question: "varchar",

    response_option: {
      type: "list",
      typeDef: "<varchar>"
    },

    owner_rolecode: "varchar",

    is_active: "boolean",

    created: {
      type: "timestamp",
      default: { "$db_function": "toTimestamp(now())" }
    },

    updated: {
      type: "timestamp",
      default: { "$db_function": "toTimestamp(now())" }
    }
  },

  key: ["id"],

  table_name: "questionnaire_master"
}

questionnaire_master.js : controller function which creates a new entry

var questionnaireMasterController = {};
var models = require('../models/dbCLient');
//var questionnaireMasterModel = require('../models/QuestionnaireMasterModel');
var responseEntity = require('../utility/response_entity');


questionnaireMasterController.createQuestionnaire = function (params, callback) {
 var uuid = models.uuid();
 var question = new models.instance.QuestionnaireMaster({
  id : uuid,
  questionnaire_type : params.questionnaire_type,
  question: params.question,
  response_option : params.response_option,
  owner_rolecode : params.owner_rolecode,  
  is_active: true
 });
 question.save(function (err) {
  if (err) {
   if(err.name = 'apollo.model.validator.invalidvalue')
    responseEntity.sendResponse(422, 'Invalid input paramters', null, {name : err.name, message : err.message},callback);
   else 
    responseEntity.sendResponse(501, 'Error Occured', null, {name : err.name, message : err.message},callback);
   console.log("err ::: ",err);
   return;
  }
  responseEntity.sendResponse(201,"Question created successfully", { id: uuid }, null ,callback);
  console.log('Yuppiie!');
 }); 
}

// User controller functions and expose it to app
module.exports = questionnaireMasterController;

createQuestionnaire() is called when API is called. Works fine.

questionnaire_master_test.js : test case which gives me error

var chai = require('chai');
var expect = chai.expect;
var chaiHttp = require('chai-http');
var randomstring = require("randomstring");
var questionnaireMasterController = require('../controller/questionnaire_master.js')

chai.use(chaiHttp);

var supertest = require('supertest');

describe('Check for create Patient', function () {    
    it('Should create a new question in questionnaire master table', function (done) {
        var question = {
            "questionnaire_type": "Select one",
            "question": "This is dummy question",
            "response_option": ["dummyoption1", "dummyoption2"],
            "owner_rolecode": "01",
            "is_active": true           
        };
        questionnaireMasterController.createQuestionnaire(question, function (result) {
            JSON.stringify(result);
            expect(result.code).to.be.a('number').eq(201);
            done();
        });
    });    
});

createQuestionnaire() is again called from questionnaire_master_test.js. Returns the following error :

TypeError: models.instance.QuestionnaireMaster is not a constructor
      at Object.questionnaireMasterController.createQuestionnaire (controller\questionnaire_master.js:9:877)
      at Context.<anonymous> (test\questionnaire_master_test.js:20:39)
pva
  • 1
  • 1

3 Answers3

0

That error is typically thrown when the models are not loaded. In this case, it's likely due to the directory path provided to the models.setDirectory(__dirname) call in your dbClient.js file. By default, __dirname will point to the current modules directory (in this case, the directory containing dbClient.js).

Your apps directory structure is not entirely clear from the post, but I suspect your models are in a different directory than your dbClient.js module. If that's true, you'll want to edit your call to setDirectory() to reflect the correct path to your models folder.

For example, if your app structure is...

c:\repos\approot\dbClient.js

c:\repos\approot\models\QuestionnaireMasterModel.js

then change the path provided to setDirectory...

models.setDirectory(__dirname + '/models').bind(...)

jfarleyx
  • 775
  • 1
  • 5
  • 9
0

This is due to non-blocking nature of code, it tries to execute save before models are loaded.

I faced similar issue & Just for the testing purpose, I set the timeout in test script and then executed the save and data insertion worked perfectly fine.

I did something like this :

setTimeout(function(){ client.save(model.instance.person,param); }, 3000);
Ankit
  • 25
  • 3
  • Not a good idea. You can use bind's callback function https://stackoverflow.com/questions/43345943/express-cassandra-auto-load-models-from-a-directory-models-instance-person-is – Va5ili5 May 05 '19 at 22:22
  • Although you are quite right about the non-blocking nature of the code! – Va5ili5 May 05 '19 at 22:26
0

You should use bind's callback function as described here: Express Cassandra Auto-Load Models from a Directory - models.instance.Person is not a constructor

models.setDirectory( __dirname + '/models').bind(
{
...
},
function(err) { // add your code here }
);
Va5ili5
  • 749
  • 8
  • 20