不要怂,就是干,撸起袖子干!

Commit f449abc9 by Mick Hansen

Merge pull request #1476 from thanpolas/refactor-dao-validator

Refactor dao validator
2 parents f435d6b3 0e112da3
...@@ -21,5 +21,6 @@ ...@@ -21,5 +21,6 @@
"laxcomma": true, "laxcomma": true,
"es5": true, "es5": true,
"quotmark": false, "quotmark": false,
"undef": true,
"strict": false "strict": false
} }
...@@ -7,6 +7,9 @@ Notice: All 1.7.x changes are present in 2.0.x aswell ...@@ -7,6 +7,9 @@ Notice: All 1.7.x changes are present in 2.0.x aswell
- [FEATURE] 1:1 and 1:m marks columns as foreign keys, and sets them to cascade on update and set null on delete. If you are working with an existing DB which does not allow null values, be sure to override those options, or disable them completely by passing constraints: false to your assocation call (`M1.belongsTo(M2, { constraints: false})`). - [FEATURE] 1:1 and 1:m marks columns as foreign keys, and sets them to cascade on update and set null on delete. If you are working with an existing DB which does not allow null values, be sure to override those options, or disable them completely by passing constraints: false to your assocation call (`M1.belongsTo(M2, { constraints: false})`).
#### Backwards compatability changes #### Backwards compatability changes
- The `notNull` validator has been removed, use the Schema's `allowNull` property.
- All Validation errors now return a sequelize.ValidationError which inherits from Error.
- selectedValues has been removed for performance reasons, if you depend on this, please open an issue and we will help you work around it. - selectedValues has been removed for performance reasons, if you depend on this, please open an issue and we will help you work around it.
- foreign keys will now correctly be based on the alias of the model - foreign keys will now correctly be based on the alias of the model
- if you have any 1:1 relations where both sides use an alias, you'll need to set the foreign key, or they'll each use a different foreign key based on their alias. - if you have any 1:1 relations where both sides use an alias, you'll need to set the foreign key, or they'll each use a different foreign key based on their alias.
......
...@@ -195,6 +195,7 @@ module.exports = (function() { ...@@ -195,6 +195,7 @@ module.exports = (function() {
if (primaryKeyDeleted) { if (primaryKeyDeleted) {
targetAttribute.primaryKey = sourceAttribute.primaryKey = true targetAttribute.primaryKey = sourceAttribute.primaryKey = true
} else { } else {
var uniqueKey = [this.through.tableName, this.identifier, this.foreignIdentifier, 'unique'].join('_') var uniqueKey = [this.through.tableName, this.identifier, this.foreignIdentifier, 'unique'].join('_')
targetAttribute.unique = sourceAttribute.unique = uniqueKey targetAttribute.unique = sourceAttribute.unique = uniqueKey
......
...@@ -1332,13 +1332,24 @@ module.exports = (function() { ...@@ -1332,13 +1332,24 @@ module.exports = (function() {
} }
if (this._timestampAttributes.createdAt) { if (this._timestampAttributes.createdAt) {
tail[this._timestampAttributes.createdAt] = {type: DataTypes.DATE, allowNull: false} tail[this._timestampAttributes.createdAt] = {
type: DataTypes.DATE,
allowNull: false,
_autoGenerated: true,
}
} }
if (this._timestampAttributes.updatedAt) { if (this._timestampAttributes.updatedAt) {
tail[this._timestampAttributes.updatedAt] = {type: DataTypes.DATE, allowNull: false} tail[this._timestampAttributes.updatedAt] = {
type: DataTypes.DATE,
allowNull: false,
_autoGenerated: true,
}
} }
if (this._timestampAttributes.deletedAt) { if (this._timestampAttributes.deletedAt) {
tail[this._timestampAttributes.deletedAt] = {type: DataTypes.DATE} tail[this._timestampAttributes.deletedAt] = {
type: DataTypes.DATE,
_autoGenerated: true,
}
} }
var existingAttributes = Utils._.clone(self.rawAttributes) var existingAttributes = Utils._.clone(self.rawAttributes)
......
var Validator = require("validator") var Validator = require("validator")
, Utils = require("./utils") , Utils = require("./utils")
, sequelizeError = require("./errors") , sequelizeError = require("./errors")
, Promise = require("bluebird")
// Backwards compat for people using old validation function function noop() {}
// We cannot use .extend, since it coerces the first arg to string
Validator.notNull = function (val) { // Deprecate this.
return [null, undefined].indexOf(val) === -1 Validator.notNull = function () {
throw new Error('Warning "notNull" validation has been deprecated in favor of Schema based "allowNull"');
} }
// https://github.com/chriso/validator.js/blob/1.5.0/lib/validators.js // https://github.com/chriso/validator.js/blob/1.5.0/lib/validators.js
...@@ -76,53 +78,80 @@ Validator.extend('is', function(str, pattern, modifiers) { ...@@ -76,53 +78,80 @@ Validator.extend('is', function(str, pattern, modifiers) {
return this.regex(str, pattern, modifiers); return this.regex(str, pattern, modifiers);
}) })
/**
* The Main DAO Validator.
*
* @param {sequelize.Model} modelInstance The model instance.
* @param {Object=} options A dict with options.
* @constructor
*/
var DaoValidator = module.exports = function(modelInstance, options) { var DaoValidator = module.exports = function(modelInstance, options) {
options = options || {} options = options || {}
options.skip = options.skip || []
// assign defined and default options
this.options = Utils._.defaults(options, {
skip: [],
});
this.modelInstance = modelInstance this.modelInstance = modelInstance
this.chainer = new Utils.QueryChainer() this.chainer = new Utils.QueryChainer()
this.options = options
/** /**
* Expose validator.js to allow users to extend * Expose validator.js to allow users to extend
* @name Validator * @name Validator
*/ */
this.Validator = Validator this.Validator = Validator
/**
* All errors will be stored here from the validations.
*
* @type {Sequelize.error} Will contain keys that correspond to attributes which will
* be Arrays of Errors.
*/
this.errors = new sequelizeError.ValidationError('Validation error')
/** @type {boolean} Indicates if validations are in progress */
this.inProgress = false;
} }
/** @define {string} The error key for arguments as passed by custom validators */ /** @define {string} The error key for arguments as passed by custom validators */
DaoValidator.RAW_KEY_NAME = '__raw' DaoValidator.RAW_KEY_NAME = '__raw'
/**
* The main entry point for the Validation module, invoke to start the dance.
*
* @return {sequelize.Utils.CustomEventEmitter} That thing...
*/
DaoValidator.prototype.validate = function() { DaoValidator.prototype.validate = function() {
var self = this if (this.inProgress) {
throw new Error('Validations already in progress.');
}
this.inProgress = true;
this.errors = new sequelizeError.ValidationError('Validation error')
var self = this
return new Utils.CustomEventEmitter(function(emitter) { return new Utils.CustomEventEmitter(function(emitter) {
validateAttributes.call(self) Promise.settle([
validateModel.call(self) self._builtinValidators(),
self._customValidators(),
self ]).then(function () {
.chainer if (Object.keys(self.errors).length) {
.run() emitter.emit('success', self.errors)
.success(function () { } else {
emitter.emit('success') emitter.emit('success')
}) }
.error(function(err) {
var error = new sequelizeError.ValidationError('Validation error')
error[DaoValidator.RAW_KEY_NAME] = []
Utils._.each(err, function (value) {
error[DaoValidator.RAW_KEY_NAME].push(value[DaoValidator.RAW_KEY_NAME])
delete value[DaoValidator.RAW_KEY_NAME]
Utils._.extend(error, value)
})
emitter.emit('success', error)
}) })
}).run() }).run()
} }
/**
* Invoke the Validation sequence:
* - Before Validation Model Hooks
* - Validation
* - After Validation Model Hooks
*
* @return {sequelize.Utils.CustomEventEmitter} An eventemitter.
*/
DaoValidator.prototype.hookValidate = function() { DaoValidator.prototype.hookValidate = function() {
var self = this var self = this
...@@ -149,143 +178,238 @@ DaoValidator.prototype.hookValidate = function() { ...@@ -149,143 +178,238 @@ DaoValidator.prototype.hookValidate = function() {
}).run() }).run()
} }
// private /**
var validateModel = function() { * Will run all the built-in validators.
Utils._.each(this.modelInstance.__options.validate, function(_validator, validatorType) { *
var validator = prepareValidationOfAttribute.call(this, undefined, _validator, validatorType, { omitValue: true }) * @return {Promise(Array.<Promise.PromiseInspection>)} A promise from .settle().
* @private
*/
DaoValidator.prototype._builtinValidators = function() {
var self = this
this.chainer.add(new Utils.CustomEventEmitter(function(emitter) { // promisify all attribute invocations
var next = function(err) { var validators = [];
Utils._.forIn(this.modelInstance.rawAttributes, function(rawAttribute, field) {
if (self.options.skip.indexOf(field) >= 0) {
return
}
if (err) { var value = self.modelInstance.dataValues[field]
var error = {};
error[DaoValidator.RAW_KEY_NAME] = err
var msg = ((err instanceof Error) ? err.message : err) if (!rawAttribute._autoGenerated && !rawAttribute.autoIncrement) {
error[validatorType] = [msg] // perform validations based on schema
emitter.emit('error', error) self._validateSchema(rawAttribute, field, value)
} else {
emitter.emit('success')
} }
if (self.modelInstance.validators.hasOwnProperty(field)) {
validators.push(self._builtinAttrValidate.call(self, value, field))
} }
})
validator.args.unshift(next); return Promise.settle(validators)
validator.fn.apply(null, validator.args)
}.bind(this)).run())
}.bind(this))
} }
var validateAttributes = function() { /**
var self = this * Will run all the custom validators.
, errors = {} *
* @return {Promise(Array.<Promise.PromiseInspection>)} A promise from .settle().
* @private
*/
DaoValidator.prototype._customValidators = function() {
Utils._.each(this.modelInstance.rawAttributes, function(rawAttribute, field) { var validators = [];
var value = self.modelInstance.dataValues[field] var self = this;
, hasAllowedNull = ((rawAttribute === undefined || rawAttribute.allowNull === true) && ((value === null) || (value === undefined))) Utils._.each(this.modelInstance.__options.validate, function(validator,
, isSkipped = self.options.skip.length > 0 && self.options.skip.indexOf(field) !== -1 validatorType) {
if (self.modelInstance.validators.hasOwnProperty(field) && !hasAllowedNull && !isSkipped) { var valprom = self._invokeCustomValidator(validator, validatorType)
errors = Utils._.merge(errors, validateAttribute.call(self, value, field)) // errors are handled in settling, stub this
} .catch(noop)
validators.push(valprom)
}) })
return errors return Promise.settle(validators)
} }
var validateAttribute = function(value, field) { /**
// for each validator * Validate a single attribute with all the defined built-in validators.
Utils._.each(this.modelInstance.validators[field], function(details, validatorType) { *
var validator = prepareValidationOfAttribute.call(this, value, details, validatorType) * @param {*} value Anything.
* @param {string} field The field name.
this.chainer.add(new Utils.CustomEventEmitter(function(emitter) { * @return {Promise} A promise, will always resolve,
var next = function(err) { * auto populates error on this.error local object.
if (err) { * @private
var error = {} */
error[field] = [err] DaoValidator.prototype._builtinAttrValidate = function(value, field) {
emitter.emit('error', error) var self = this;
} else { // check if value is null (if null not allowed the Schema pass will capture it)
emitter.emit('success') if (value === null || typeof value === 'undefined') {
} return Promise.resolve();
} }
validator.args.unshift(next); // Promisify each validator
validator.fn.apply(null, validator.args) var validators = [];
}.bind(this)).run()) Utils._.forIn(this.modelInstance.validators[field], function(test,
}.bind(this)) // for each validator for this field validatorType) {
}
var prepareValidationOfAttribute = function(value, details, validatorType, options) { // Check for custom validator.
var isCustomValidator = false // if true then it's a custom validation method if (typeof test === 'function') {
, validatorFunction = null // the validation function to call return validators.push(self._invokeCustomValidator(test, validatorType,
, validatorArgs = [] // extra arguments to pass to validation function true, value, field))
, errorMessage = "" // the error message to return if validation fails }
if (typeof details === 'function') {
// it is a custom validator function?
isCustomValidator = true
var callArgs = [] var validatorPromise = self._invokeBuiltinValidator(value, test, validatorType);
var validatorArity = details.length // errors are handled in settling, stub this
validatorPromise.catch(noop)
validators.push(validatorPromise)
});
return Promise.settle(validators)
.then(this._handleSettledResult.bind(this, field))
};
/**
* Prepare and invoke a custom validator.
*
* @param {Function} validator The custom validator.
* @param {string} validatorType the custom validator type (name).
* @param {boolean=} optAttrDefined Set to true if custom validator was defined
* from the Attribute
* @return {Promise} A promise.
* @private
*/
DaoValidator.prototype._invokeCustomValidator = Promise.method(function(validator, validatorType,
optAttrDefined, optValue, optField) {
var validatorFunction = null // the validation function to call
var isAsync = false
var omitValue = !!(options || {}).omitValue var validatorArity = validator.length;
if (!omitValue) { // check if validator is async and requires a callback
callArgs.push(value) var asyncArity = 1;
var errorKey = validatorType;
var invokeArgs;
if (optAttrDefined) {
asyncArity = 2;
invokeArgs = optValue;
errorKey = optField;
}
if (validatorArity === asyncArity) {
isAsync = true;
} }
// check if validator is async and requires a callback
var isAsync = omitValue && validatorArity === 1 ||
!omitValue && validatorArity === 2
validatorFunction = function(next) {
if (isAsync) { if (isAsync) {
callArgs.push(next) if (optAttrDefined) {
validatorFunction = Promise.promisify(validator.bind(this.modelInstance, invokeArgs))
} else {
validatorFunction = Promise.promisify(validator.bind(this.modelInstance))
} }
return validatorFunction()
try { .catch(this._pushError.bind(this, false, errorKey))
details.apply(this.modelInstance, callArgs) } else {
} catch(ex) { return Promise.try(validator.bind(this.modelInstance, invokeArgs))
return next(ex) .catch(this._pushError.bind(this, false, errorKey))
} }
})
/**
* Prepare and invoke a build-in validator.
*
* @param {*} value Anything.
* @param {*} test The test case.
* @param {string} validatorType One of known to Sequelize validators.
* @return {Object} An object with specific keys to invoke the validator.
* @private
*/
DaoValidator.prototype._invokeBuiltinValidator = Promise.method(function(value,
test, validatorType) {
if (!isAsync) { // check if Validator knows that kind of validation test
next() if (typeof Validator[validatorType] !== 'function') {
throw new Error('Invalid validator function: ' + validatorType)
} }
}.bind(this)
} else {
// extract extra arguments for the validator // extract extra arguments for the validator
validatorArgs = details.hasOwnProperty("args") ? details.args : details var validatorArgs = test.hasOwnProperty('args') ? test.args : test;
// extract the error msg
var errorMessage = test.hasOwnProperty('msg') ? test.msg :
'Validation ' + validatorType + ' failed'
if (!Array.isArray(validatorArgs)) { if (!Array.isArray(validatorArgs)) {
validatorArgs = [validatorArgs] validatorArgs = [validatorArgs]
} else { } else {
validatorArgs = validatorArgs.slice(0); validatorArgs = validatorArgs.slice(0);
} }
if (!Validator[validatorType].apply(Validator, [value].concat(validatorArgs))) {
throw errorMessage
}
});
// extract the error msg
errorMessage = details.hasOwnProperty("msg") ? details.msg : 'Validation ' + validatorType + ' failed'
// check if Validator knows that kind of validation test /**
if (!Utils._.isFunction(Validator[validatorType])) { * Will validate a single field against its schema definition (isnull).
throw new Error("Invalid validator function: " + validatorType) *
* @param {Object} rawAttribute As defined in the Schema.
* @param {string} field The field name.
* @param {*} value anything.
* @private
*/
DaoValidator.prototype._validateSchema = function(rawAttribute,
field, value) {
if (rawAttribute.allowNull === false && ((value === null) ||
(value === undefined))) {
var error = new sequelizeError.ValidationError(field + ' cannot be null')
error.path = field
error.value = value
error.type = error.message = 'notNull Violation'
if (!this.errors.hasOwnProperty(field)) {
this.errors[field] = [];
} }
this.errors[field].push(error);
}
};
// bind to validator obj
validatorFunction = function(next) {
var args = Array.prototype.slice.call(arguments, 1)
if (Validator[validatorType].apply(Validator, [value].concat(args))) { /**
next() * Handles the returned result of a Promise.settle.
} else { *
next(errorMessage) * If errors are found it populates this.error.
} *
* @param {string} field The attribute name.
* @param {Array.<Promise.PromiseInspection>} Promise inspection objects.
* @private
*/
DaoValidator.prototype._handleSettledResult = function(field, promiseInspections) {
var self = this;
promiseInspections.forEach(function(promiseInspection) {
if (promiseInspection.isRejected()) {
var rejection = promiseInspection.error();
self._pushError(true, field, rejection);
} }
});
};
/**
* Signs all errors retaining the original.
*
* @param {boolean} isBuiltin Determines if error is from builtin validator.
* @param {string} errorKey The error key to assign on this.errors object.
* @param {Error|string} rawError The original error.
* @private
*/
DaoValidator.prototype._pushError = function(isBuiltin, errorKey, rawError) {
if (!this.errors.hasOwnProperty(errorKey)) {
this.errors[errorKey] = [];
} }
return { var error = new sequelizeError.ValidationError()
fn: validatorFunction,
msg: errorMessage, error[DaoValidator.RAW_KEY_NAME] = rawError
args: validatorArgs, error.message = rawError.message || rawError || 'Validation error'
isCustom: isCustomValidator
}
}
this.errors[errorKey].push(error);
};
...@@ -11,7 +11,7 @@ var error = module.exports = {} ...@@ -11,7 +11,7 @@ var error = module.exports = {}
* @constructor * @constructor
*/ */
error.BaseError = function() { error.BaseError = function() {
Error.call(this) Error.apply(this, arguments)
}; };
util.inherits(error.BaseError, Error) util.inherits(error.BaseError, Error)
...@@ -22,6 +22,6 @@ util.inherits(error.BaseError, Error) ...@@ -22,6 +22,6 @@ util.inherits(error.BaseError, Error)
* @constructor * @constructor
*/ */
error.ValidationError = function() { error.ValidationError = function() {
error.BaseError.call(this) error.BaseError.apply(this, arguments)
}; };
util.inherits(error.ValidationError, error.BaseError) util.inherits(error.ValidationError, error.BaseError)
...@@ -376,21 +376,33 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -376,21 +376,33 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
UserNull.create({ username: 'foo2', smth: null }).error(function(err) { UserNull.create({ username: 'foo2', smth: null }).error(function(err) {
expect(err).to.exist expect(err).to.exist
expect(err.smth[0].path).to.equal('smth');
if (Support.dialectIsMySQL()) { if (Support.dialectIsMySQL()) {
// We need to allow two different errors for MySQL, see: // We need to allow two different errors for MySQL, see:
// http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_trans_tables // http://dev.mysql.com/doc/refman/5.0/en/server-sql-mode.html#sqlmode_strict_trans_tables
expect(err.message).to.match(/(Column 'smth' cannot be null|Field 'smth' doesn't have a default value)/) expect(err.smth[0].message).to.match(/notNull Violation/)
} }
else if (dialect === "sqlite") { else if (dialect === "sqlite") {
expect(err.message).to.match(/.*SQLITE_CONSTRAINT.*/) expect(err.smth[0].message).to.match(/notNull Violation/)
} else { } else {
expect(err.message).to.match(/.*column "smth" violates not-null.*/) expect(err.smth[0].message).to.match(/notNull Violation/)
} }
done()
})
})
})
it("raises an error if created object breaks definition contraints", function(done) {
var UserNull = this.sequelize.define('UserWithNonNullSmth', {
username: { type: Sequelize.STRING, unique: true },
smth: { type: Sequelize.STRING, allowNull: false }
})
this.sequelize.options.omitNull = false
UserNull.sync({ force: true }).success(function() {
UserNull.create({ username: 'foo', smth: 'foo' }).success(function() { UserNull.create({ username: 'foo', smth: 'foo' }).success(function() {
UserNull.create({ username: 'foo', smth: 'bar' }).error(function(err) { UserNull.create({ username: 'foo', smth: 'bar' }).error(function(err) {
expect(err).to.exist expect(err).to.exist
if (dialect === "sqlite") { if (dialect === "sqlite") {
expect(err.message).to.match(/.*SQLITE_CONSTRAINT.*/) expect(err.message).to.match(/.*SQLITE_CONSTRAINT.*/)
} }
...@@ -399,13 +411,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -399,13 +411,11 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
} else { } else {
expect(err.message).to.match(/.*duplicate key value violates unique constraint.*/) expect(err.message).to.match(/.*duplicate key value violates unique constraint.*/)
} }
done() done()
}) })
}) })
}) })
}) })
})
it("raises an error if saving an empty string into a column allowing null or URL", function(done) { it("raises an error if saving an empty string into a column allowing null or URL", function(done) {
var StringIsNullOrUrl = this.sequelize.define('StringIsNullOrUrl', { var StringIsNullOrUrl = this.sequelize.define('StringIsNullOrUrl', {
...@@ -417,18 +427,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -417,18 +427,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
StringIsNullOrUrl.sync({ force: true }).success(function() { StringIsNullOrUrl.sync({ force: true }).success(function() {
StringIsNullOrUrl.create({ str: null }).success(function(str1) { StringIsNullOrUrl.create({ str: null }).success(function(str1) {
expect(str1.str).to.be.null expect(str1.str).to.be.null
StringIsNullOrUrl.create({ str: 'http://sequelizejs.org' }).success(function(str2) { StringIsNullOrUrl.create({ str: 'http://sequelizejs.org' }).success(function(str2) {
expect(str2.str).to.equal('http://sequelizejs.org') expect(str2.str).to.equal('http://sequelizejs.org')
StringIsNullOrUrl.create({ str: '' }).error(function(err) { StringIsNullOrUrl.create({ str: '' }).error(function(err) {
expect(err).to.exist expect(err).to.exist
expect(err.str[0]).to.match(/Validation isURL failed/) expect(err.str[0].message).to.match(/Validation isURL failed/)
done() done()
}) })
}) })
}) }).error(done)
}) })
}) })
...@@ -944,9 +952,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -944,9 +952,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
var Tasks = this.sequelize.define('Task', { var Tasks = this.sequelize.define('Task', {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
validate: { allowNull: false,
notNull: { args: true, msg: 'name cannot be null' }
}
}, },
code: { code: {
type: Sequelize.STRING, type: Sequelize.STRING,
...@@ -963,13 +969,13 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -963,13 +969,13 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
{name: 'bar', code: '1'} {name: 'bar', code: '1'}
], { validate: true }).error(function(errors) { ], { validate: true }).error(function(errors) {
expect(errors).to.not.be.null expect(errors).to.not.be.null
expect(errors).to.be.instanceof(Array) expect(errors).to.be.an('Array')
expect(errors).to.have.length(2) expect(errors).to.have.length(2)
expect(errors[0].record.code).to.equal('1234') expect(errors[0].record.code).to.equal('1234')
expect(errors[0].errors.name[0]).to.equal('name cannot be null') expect(errors[0].errors.name[0].message).to.equal('notNull Violation')
expect(errors[1].record.name).to.equal('bar') expect(errors[1].record.name).to.equal('bar')
expect(errors[1].record.code).to.equal('1') expect(errors[1].record.code).to.equal('1')
expect(errors[1].errors.code[0]).to.equal('Validation len failed') expect(errors[1].errors.code[0].message).to.equal('Validation len failed')
done() done()
}) })
}) })
...@@ -980,8 +986,8 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -980,8 +986,8 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
validate: { validate: {
notNull: { args: true, msg: 'name cannot be null' } notEmpty: true,
} },
}, },
code: { code: {
type: Sequelize.STRING, type: Sequelize.STRING,
......
...@@ -57,7 +57,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -57,7 +57,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
expect(u2.username).to.equal(bio) expect(u2.username).to.equal(bio)
done() done()
}) })
}) }).error(function(err) {
done(err);
});
}) })
}) })
...@@ -853,7 +855,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -853,7 +855,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
expect(err).to.be.instanceof(Object) expect(err).to.be.instanceof(Object)
expect(err.validateTest).to.be.instanceof(Array) expect(err.validateTest).to.be.instanceof(Array)
expect(err.validateTest[0]).to.exist expect(err.validateTest[0]).to.exist
expect(err.validateTest[0]).to.equal('Validation isInt failed') expect(err.validateTest[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
...@@ -866,7 +868,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -866,7 +868,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
expect(err.validateCustom).to.exist expect(err.validateCustom).to.exist
expect(err.validateCustom).to.be.instanceof(Array) expect(err.validateCustom).to.be.instanceof(Array)
expect(err.validateCustom[0]).to.exist expect(err.validateCustom[0]).to.exist
expect(err.validateCustom[0]).to.equal('Length failed.') expect(err.validateCustom[0].message).to.equal('Length failed.')
done() done()
}) })
}) })
...@@ -879,7 +881,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -879,7 +881,7 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
expect(err.validateTest).to.exist expect(err.validateTest).to.exist
expect(err.validateTest).to.be.instanceof(Array) expect(err.validateTest).to.be.instanceof(Array)
expect(err.validateTest[0]).to.exist expect(err.validateTest[0]).to.exist
expect(err.validateTest[0]).to.equal('Validation isInt failed') expect(err.validateTest[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
...@@ -1050,6 +1052,44 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -1050,6 +1052,44 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
}) })
}) })
}) })
describe('many to many relations', function() {
var udo;
beforeEach(function(done) {
var self = this
this.User = this.sequelize.define('UserWithUsernameAndAgeAndIsAdmin', {
username: DataTypes.STRING,
age: DataTypes.INTEGER,
isAdmin: DataTypes.BOOLEAN
}, {timestamps: false})
this.Project = this.sequelize.define('NiceProject',
{ title: DataTypes.STRING }, {timestamps: false})
this.Project.hasMany(this.User)
this.User.hasMany(this.Project)
this.User.sync({ force: true }).success(function() {
self.Project.sync({ force: true }).success(function() {
self.User.create({ username: 'fnord', age: 1, isAdmin: true })
.success(function(user) {
udo = user
done()
})
})
})
})
it.skip('Should assign a property to the instance', function(done) {
// @thanpolas rethink this test, it doesn't make sense, a relation has
// to be created first in the beforeEach().
var self = this;
this.User.find({id: udo.id})
.success(function(user) {
user.NiceProjectId = 1;
expect(user.NiceProjectId).to.equal(1);
done();
})
})
})
describe('toJSON', function() { describe('toJSON', function() {
beforeEach(function(done) { beforeEach(function(done) {
......
...@@ -68,10 +68,6 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -68,10 +68,6 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
fail: "a", fail: "a",
pass: "9.2" pass: "9.2"
} }
, notNull : {
fail: null,
pass: 0
}
, isNull : { , isNull : {
fail: 0, fail: 0,
pass: null pass: null
...@@ -201,8 +197,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -201,8 +197,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
failingUser.validate().done( function(err, _errors) { failingUser.validate().done( function(err, _errors) {
expect(_errors).to.not.be.null expect(_errors).to.not.be.null
expect(_errors).to.be.an.instanceOf(Error); expect(_errors).to.be.an.instanceOf(Error)
expect(_errors.name).to.deep.eql([message]) expect(_errors.name[0].message).to.equal(message)
done() done()
}) })
}) })
...@@ -231,7 +227,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -231,7 +227,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
expect(arguments).to.have.length(0) expect(arguments).to.have.length(0)
done() done()
}).error(function(err) { }).error(function(err) {
expect(err).to.be.deep.equal({}) expect(err).to.deep.equal({})
done() done()
}) })
}) })
...@@ -291,8 +287,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -291,8 +287,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
var Model = this.sequelize.define('model', { var Model = this.sequelize.define('model', {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
allowNull: false,
validate: { validate: {
notNull: true, // won't allow null
notEmpty: true // don't allow empty strings notEmpty: true // don't allow empty strings
} }
} }
...@@ -301,8 +297,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -301,8 +297,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
Model.sync({ force: true }).success(function() { Model.sync({ force: true }).success(function() {
Model.create({name: 'World'}).success(function(model) { Model.create({name: 'World'}).success(function(model) {
model.updateAttributes({name: ''}).error(function(err) { model.updateAttributes({name: ''}).error(function(err) {
expect(err).to.be.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.name).to.deep.equal(['Validation notEmpty failed']); expect(err.name[0].message).to.equal('Validation notEmpty failed');
done() done()
}) })
}) })
...@@ -313,18 +309,18 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -313,18 +309,18 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
var Model = this.sequelize.define('model', { var Model = this.sequelize.define('model', {
name: { name: {
type: Sequelize.STRING, type: Sequelize.STRING,
allowNull: false,
validate: { validate: {
notNull: true, // won't allow null
notEmpty: true // don't allow empty strings notEmpty: true // don't allow empty strings
} }
} }
}) })
Model.sync({ force: true }).success(function() { Model.sync({ force: true }).success(function() {
Model.create({name: 'World'}).success(function(model) { Model.create({name: 'World'}).success(function() {
Model.update({name: ''}, {id: 1}).error(function(err) { Model.update({name: ''}, {id: 1}).error(function(err) {
expect(err).to.be.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.name).to.deep.equal(['Validation notEmpty failed']); expect(err.name[0].message).to.equal('Validation notEmpty failed')
done() done()
}) })
}) })
...@@ -400,8 +396,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -400,8 +396,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
User.create({id: 'helloworld'}).error(function(err) { User.create({id: 'helloworld'}).error(function(err) {
expect(err).to.be.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id).to.deep.equal(['Validation isInt failed']); expect(err.id[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
...@@ -421,8 +417,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -421,8 +417,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
User.create({username: 'helloworldhelloworld'}).error(function(err) { User.create({username: 'helloworldhelloworld'}).error(function(err) {
expect(err).to.be.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.username).to.deep.equal(['Username must be an integer!']); expect(err.username[0].message).to.equal('Username must be an integer!')
done() done()
}) })
}) })
...@@ -448,8 +444,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -448,8 +444,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
it('should emit an error when we try to enter in a string for the id key with validation arguments', function(done) { it('should emit an error when we try to enter in a string for the id key with validation arguments', function(done) {
this.User.create({id: 'helloworld'}).error(function(err) { this.User.create({id: 'helloworld'}).error(function(err) {
expect(err).to.be.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id).to.deep.equal(['ID must be an integer!']); expect(err.id[0].message).to.equal('ID must be an integer!')
done() done()
}) })
}) })
...@@ -458,8 +454,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -458,8 +454,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
var user = this.User.build({id: 'helloworld'}) var user = this.User.build({id: 'helloworld'})
user.validate().success(function(err) { user.validate().success(function(err) {
expect(err).to.be.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id).to.deep.equal(['ID must be an integer!']); expect(err.id[0].message).to.equal('ID must be an integer!')
done() done()
}) })
}) })
...@@ -467,13 +463,59 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -467,13 +463,59 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
it('should emit an error when we try to .save()', function(done) { it('should emit an error when we try to .save()', function(done) {
var user = this.User.build({id: 'helloworld'}) var user = this.User.build({id: 'helloworld'})
user.save().error(function(err) { user.save().error(function(err) {
expect(err).to.be.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id).to.deep.equal(['ID must be an integer!']); expect(err.id[0].message).to.equal('ID must be an integer!')
done() done()
}) })
}) })
}) })
}) })
describe('Pass all paths when validating', function() {
beforeEach(function(done) {
var self = this
var Project = this.sequelize.define('Project', {
name: {
type: Sequelize.STRING,
allowNull: false,
validate: {
isIn: [['unknown', 'hello', 'test']]
}
},
creatorName: {
type: Sequelize.STRING,
allowNull: false,
},
cost: {
type: Sequelize.INTEGER,
allowNull: false,
},
})
var Task = this.sequelize.define('Task', {
something: Sequelize.INTEGER
})
Project.hasOne(Task)
Task.belongsTo(Project)
Project.sync({ force: true }).success(function() {
Task.sync({ force: true }).success(function() {
self.Project = Project
self.Task = Task
done()
})
})
})
it('produce 3 errors', function(done) {
this.Project.create({}).error(function(err) {
expect(err).to.be.an.instanceOf(Error)
expect(Object.keys(err)).to.have.length(3)
done()
})
})
})
}) })
it('correctly validates using custom validation methods', function(done) { it('correctly validates using custom validation methods', function(done) {
...@@ -495,15 +537,16 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -495,15 +537,16 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
var failingUser = User.build({ name : "3" }) var failingUser = User.build({ name : "3" })
failingUser.validate().success(function(error) { failingUser.validate().success(function(error) {
expect(error).to.be.instanceOf(Error); expect(error).to.be.an.instanceOf(Error)
expect(error.name).to.deep.equal(["name should equal '2'"])
expect(error.name[0].message).to.equal("name should equal '2'")
var successfulUser = User.build({ name : "2" }) var successfulUser = User.build({ name : "2" })
successfulUser.validate().success(function() { successfulUser.validate().success(function() {
expect(arguments).to.have.length(0) expect(arguments).to.have.length(0)
done() done()
}).error(function(err) { }).error(function(err) {
expect(err).to.deep.equal({}) expect(err[0].message).to.equal()
done() done()
}) })
}) })
...@@ -525,8 +568,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -525,8 +568,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
.validate() .validate()
.success(function(error) { .success(function(error) {
expect(error).not.to.be.null expect(error).not.to.be.null
expect(error).to.be.instanceOf(Error); expect(error).to.be.an.instanceOf(Error)
expect(error.age).to.deep.equal(["must be positive"]) expect(error.age[0].message).to.equal("must be positive")
User.build({ age: null }).validate().success(function() { User.build({ age: null }).validate().success(function() {
User.build({ age: 1 }).validate().success(function() { User.build({ age: 1 }).validate().success(function() {
...@@ -563,9 +606,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -563,9 +606,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
.validate() .validate()
.success(function(error) { .success(function(error) {
expect(error).not.to.be.null expect(error).not.to.be.null
expect(error).to.be.instanceOf(Error) expect(error).to.be.an.instanceOf(Error)
expect(error.xnor).to.deep.equal(['xnor failed']); expect(error.xnor[0].message).to.equal('xnor failed');
Foo Foo
.build({ field1: 33, field2: null }) .build({ field1: 33, field2: null })
.validate() .validate()
...@@ -601,8 +643,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -601,8 +643,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
.validate() .validate()
.success(function(error) { .success(function(error) {
expect(error).not.to.be.null expect(error).not.to.be.null
expect(error).to.be.instanceOf(Error) expect(error).to.be.an.instanceOf(Error)
expect(error.xnor).to.deep.equal(['xnor failed']); expect(error.xnor[0].message).to.equal('xnor failed')
Foo Foo
.build({ field1: 33, field2: null }) .build({ field1: 33, field2: null })
...@@ -652,7 +694,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -652,7 +694,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
failingBar.validate().success(function(errors) { failingBar.validate().success(function(errors) {
expect(errors).not.to.be.null expect(errors).not.to.be.null
expect(errors.field).to.have.length(1) expect(errors.field).to.have.length(1)
expect(errors.field[0]).to.equal("Validation isIn failed") expect(errors.field[0].message).to.equal("Validation isIn failed")
}) })
}) })
......
...@@ -464,7 +464,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -464,7 +464,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('should return an error based on user', function(done) { it('should return an error based on user', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ]) expect(err.mood[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -501,7 +501,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -501,7 +501,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('should return an error based on the hook', function(done) { it('should return an error based on the hook', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ]) expect(err.mood[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -552,7 +552,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -552,7 +552,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('should return an error based on user', function(done) { it('should return an error based on user', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ]) expect(err.mood[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -601,7 +601,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -601,7 +601,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('should return an error based on the hook', function(done) { it('should return an error based on the hook', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ]) expect(err.mood[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -698,7 +698,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -698,7 +698,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('should return the user from the callback', function(done) { it('should return the user from the callback', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ]) expect(err.mood[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -720,7 +720,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -720,7 +720,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('should return the error without the user within callback', function(done) { it('should return the error without the user within callback', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ]) expect(err.mood[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -835,7 +835,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -835,7 +835,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('#create', function(done) { it('#create', function(done) {
this.User.create({mood: 'creative'}).error(function(err) { this.User.create({mood: 'creative'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal( [ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ] ) expect(err.mood[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -859,7 +859,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -859,7 +859,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('#create', function(done) { it('#create', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal( [ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ] ) expect(err.mood[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -940,7 +940,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -940,7 +940,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal( [ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ] ) expect(err.mood[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -954,7 +954,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -954,7 +954,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal( [ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ] ) expect(err.mood[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -1061,7 +1061,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -1061,7 +1061,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('#create', function(done) { it('#create', function(done) {
this.User.create({mood: 'creative'}).error(function(err) { this.User.create({mood: 'creative'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal( [ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ] ) expect(err.mood[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -1085,7 +1085,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -1085,7 +1085,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () {
it('#create', function(done) { it('#create', function(done) {
this.User.create({mood: 'happy'}).error(function(err) { this.User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal( [ 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ] ) expect(err.mood[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
......
...@@ -124,11 +124,11 @@ if (Support.dialectIsMySQL()) { ...@@ -124,11 +124,11 @@ if (Support.dialectIsMySQL()) {
User.sync({ force: true }).success(function() { User.sync({ force: true }).success(function() {
User.create({mood: 'happy'}).error(function(err) { User.create({mood: 'happy'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "happy" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver' ]) expect(err.mood[0].message).to.equal('Value "happy" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver')
var u = User.build({mood: 'SAD'}) var u = User.build({mood: 'SAD'})
u.save().error(function(err) { u.save().error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.mood).to.deep.equal([ 'Value "SAD" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver' ]) expect(err.mood[0].message).to.equal('Value "SAD" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver')
done() done()
}) })
}) })
......
...@@ -277,7 +277,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -277,7 +277,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
expect(err).to.be.an("object") expect(err).to.be.an("object")
expect(err.validateTest).to.be.an("array") expect(err.validateTest).to.be.an("array")
expect(err.validateTest[0]).to.be.ok expect(err.validateTest[0]).to.be.ok
expect(err.validateTest[0]).to.equal('Validation isInt failed') expect(err.validateTest[0].message).to.equal('Validation isInt failed')
done() done()
}); });
}) })
...@@ -290,7 +290,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -290,7 +290,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
expect(err.validateCustom).to.be.ok expect(err.validateCustom).to.be.ok
expect(err.validateCustom).to.be.an("array") expect(err.validateCustom).to.be.an("array")
expect(err.validateCustom[0]).to.be.ok expect(err.validateCustom[0]).to.be.ok
expect(err.validateCustom[0]).to.equal('Length failed.') expect(err.validateCustom[0].message).to.equal('Length failed.')
done() done()
}) })
}) })
...@@ -304,7 +304,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -304,7 +304,7 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
expect(err.validateTest).to.be.ok expect(err.validateTest).to.be.ok
expect(err.validateTest).to.be.an("array") expect(err.validateTest).to.be.an("array")
expect(err.validateTest[0]).to.be.ok expect(err.validateTest[0]).to.be.ok
expect(err.validateTest[0]).to.equal('Validation isInt failed') expect(err.validateTest[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
......
...@@ -86,6 +86,10 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () { ...@@ -86,6 +86,10 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
if (dialect === 'mariadb') { if (dialect === 'mariadb') {
expect(err.message).to.match(/Access denied for user/) expect(err.message).to.match(/Access denied for user/)
} else if (dialect === 'postgres') { } else if (dialect === 'postgres') {
// When the test is run with only it produces:
// Error: Error: Failed to authenticate for PostgresSQL. Please double check your settings.
// When its run with all the other tests it produces:
// Error: invalid port number: "99999"
expect(err.message).to.match(/invalid port number/) expect(err.message).to.match(/invalid port number/)
} else { } else {
expect(err.message).to.match(/Failed to authenticate/) expect(err.message).to.match(/Failed to authenticate/)
...@@ -713,7 +717,7 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () { ...@@ -713,7 +717,7 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () {
it("doesn't save an instance if value is not in the range of enums", function(done) { it("doesn't save an instance if value is not in the range of enums", function(done) {
this.Review.create({status: 'fnord'}).error(function(err) { this.Review.create({status: 'fnord'}).error(function(err) {
expect(err).to.be.instanceOf(Error); expect(err).to.be.instanceOf(Error);
expect(err.status).to.deep.equal([ 'Value "fnord" for ENUM status is out of allowed scope. Allowed values: scheduled, active, finished' ]) expect(err.status[0].message).to.equal('Value "fnord" for ENUM status is out of allowed scope. Allowed values: scheduled, active, finished')
done() done()
}) })
}) })
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!