7 votes

"SequelizeValidationError: notNull Violation" on a property that should not exist

I am writing unit tests for a node server using Sequelize. When you insert some false data I am getting the error

SequelizeValidationError: notNull Violation: QuestionId cannot be null

Notice the Q capital letter in the QuestionId

test:

describe('answerQuestion', () => {
    it('debe insertar una respuesta y conseguir la siguiente pregunta', (done) => {
        Survey.DBModel.create({lookType: 0}, {logging: false}).then(() => {
            Question.DBModel.create({type: 0, text: 'Test question'}, {logging: false}).then(q1 => {
                Question.DBModel.create({type: 1, text: 'Next question'}, {logging: false}).then(q2 => {
                    console.log('antes');
                    QuestionOption.DBModel.create({text: 'Test option', questionId: 1, nextQuestionId: 2}, {logging: false}).then(() => {
                        console.log('despues');
                        Survey.answerQuestion(1, 1, 1).then(question => {
                            question.should.have.property('id');
                        }, done);
                    }, done);
                }, done);
            }, done);
        }, done);
    });
});

The output of the console "before", but the errors before that comes "after"

question.js

'use strict';
module.exports = function(sequelize, DataTypes) {
  var Question = sequelize.define('Question', {
    id: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER
    },
    type: {
      allowNull: false,
      type: DataTypes.INTEGER
    },
    text: {
      allowNull: false,
      type: DataTypes.STRING
    },
    nextQuestionId: {
      type: DataTypes.INTEGER
    }
  }, {
    classMethods: {
      associate: function(models) {
        models.Question.belongsTo(models.Question, {as: 'nextQuestion', foreignKey: {field: 'nextQuestionId', allowNull: true}});
        models.Question.hasMany(models.Answer, {as: 'answers', foreignKey: {field: 'questionId', allowNull: false}});
        models.Question.hasMany(models.QuestionOption, {as: 'options', foreignKey: {field: 'questionId', allowNull: false}});
        models.Question.hasMany(models.QuestionOption, {as: 'referrers', foreignKey: {field: 'nextQuestionId', allowNull: true}});
      }
    }
  });
  return Question;
};

questionoption.js

'use strict';
module.exports = function(sequelize, DataTypes) {
  var QuestionOption = sequelize.define('QuestionOption', {
    id: {
      allowNull: false,
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER
    },
    questionId: {
      allowNull: false,
      type: DataTypes.INTEGER
    },
    text: {
      allowNull: false,
      type: DataTypes.STRING
    },
    nextQuestionId: {
      type: DataTypes.INTEGER
    }
  }, {
    classMethods: {
      associate: function(models) {
        models.QuestionOption.belongsTo(models.Question, {as: 'question', foreignKey: {field: 'questionId', allowNull: false}});
        models.QuestionOption.belongsTo(models.Question, {as: 'nextQuestion', foreignKey: {field: 'nextQuestionId', allowNull: true}});
      }
    }
  });
  return QuestionOption;
};

These models are quite strongly coupled to each other and have a self-referential and all kinds of cases. All the other models that I feel are not relevant to this, but may be provided if necessary.

Execute SQL on the SQLite database directly, in the same order and with the same properties that the sentences CREATE previous not the exception, and through many tests.

It is evident that Sequelize does not attempt to execute the sentence of creation of QuestionOption. Errors before generating the SQL to execute.

Some strange behaviors are that the associations are meticulously defined in the models and all of them have a smaller case, q to questionId on their definitions. All the associations have also an inverse association defined, so Sequelize should not try to create property names.

All the tables are cleared and re-created before each test (with success).

Adding to the evidence that something weird is going on is that if I remove the questionId: 1 of the sentence of creation of QuestionOption, then becomes the error

SequelizeValidationError: notNull Violation: questionId cannot be null, 
notNull Violation: QuestionId cannot be null

Note in the case of both, one is smaller (which I removed) and one is greater.

Next suspect is the association nextQuestionId, but it has been defined in the model, and each side of the association, as aallowNull: true and I have provided in the sentence of creation.

I am purely baffled at this behavior and questioning if this is perhaps a bug in Sequelize, but I would have to confirm it before reporting it falsely.

Other information that perhaps could be useful is:

  • Tests are run by using the command NODE_ENV = test mocha
  • The creation of database for the test is automatic using sync (code below)
  • All other tests pass, but this is the only one that uses QuestionOption in the test.
  • The method that I am trying to prove it works "in production" (which is running locally in dev with the client connected)
  • Database schema has been verified with a SQLite GUI and all the columns are appropriate (there is No field QuestionId on any table with a Q-capital letter)

The creation of databases for testing

beforeEach((done) => {
    Survey.DBModel.sync({force: true, logging: false}).then(() => {
        Question.DBModel.sync({force: true, logging: false}).then(() => {
            Answer.DBModel.sync({force: true, logging: false}).then(() => {
                QuestionOption.DBModel.sync({force: true, logging: false}).then(() => {
                    done();
                }, done);
            }, done);
        }, done);
    }, done);
});

2voto

Angel Angel Points 7815

I don't like to answer questions which are not domino, (and I don't understand how to explain), but as I see that this question was formulated some time ago I will try to put what can be the error and its solution.

Try changing this line:

QuestionOption.DBModel.create({text: 'Test option', questionId: 1,
                              nextQuestionId: 2}, {logging: false}).then(() => {

by this:

QuestionOption.DBModel.create({text: 'Test option', questionId: 1, 
                              QuestionId: 1 ,
                              nextQuestionId: 2}, {logging: false}).then(() => {

You can see that it has added QuestionId: 1,

Once someone do I fix an error like in a code other than specifying the argument in the function that devolvia, so I think that maybe the above will help.

HolaDevs.com

HolaDevs is an online community of programmers and software lovers.
You can check other people responses or create a new question if you don't find a solution

Powered by:

X