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

Commit 61490ee6 by Jan Aagaard Meier

Merge pull request #2081 from meetearnest/error-rewrite

Refactoring of Error Handling
2 parents bb1d01cb e9884631
...@@ -28,6 +28,14 @@ Notice: All 1.7.x changes are present in 2.0.x aswell ...@@ -28,6 +28,14 @@ Notice: All 1.7.x changes are present in 2.0.x aswell
- Model names are now used more verbatim in associations. This means that if you have a model named `Task` (plural T), or an association specifying `{ as: 'Task' }`, the tasks will be returned as `relatedModel.Tasks` instead of `relatedModel.tasks`. For more information and how to mitigate this, see https://github.com/sequelize/sequelize/wiki/Upgrading-to-2.0#inflection-replaces-lingo-and-changes-to-naming-conventions - Model names are now used more verbatim in associations. This means that if you have a model named `Task` (plural T), or an association specifying `{ as: 'Task' }`, the tasks will be returned as `relatedModel.Tasks` instead of `relatedModel.tasks`. For more information and how to mitigate this, see https://github.com/sequelize/sequelize/wiki/Upgrading-to-2.0#inflection-replaces-lingo-and-changes-to-naming-conventions
- Removed the freezeAssociations option - use model and assocation names instead to provide the plural form yourself - Removed the freezeAssociations option - use model and assocation names instead to provide the plural form yourself
- Removed sequelize.language option (not supported by inflection) - Removed sequelize.language option (not supported by inflection)
- Error handling has been refactored. Code that listens for :
+ All Error classes properly inherit from Error and a common SequelizeBaseError base
+ Instance Validator returns a single instance of a ValidationError which contains an errors array property. This property contains individual error items for each failed validation.
+ ValidationError includes a `get(path)` method to find all broken validations for a path on an instance. To migrate existing error handling, switch from array indexing to using the get method:
Old: `err.validateCustom[0]`
New: `err.get('validateCustom')[0]`
# v2.0.0-dev12 # v2.0.0-dev12
- [FEATURE] You can now return a promise to a hook rather than use a callback - [FEATURE] You can now return a promise to a hook rather than use a callback
......
...@@ -13,7 +13,11 @@ var error = module.exports = {}; ...@@ -13,7 +13,11 @@ var error = module.exports = {};
* @constructor * @constructor
*/ */
error.BaseError = function() { error.BaseError = function() {
Error.apply(this, arguments); var tmp = Error.apply(this, arguments);
tmp.name = this.name = 'SequelizeBaseError';
Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
this.message = tmp.message;
}; };
util.inherits(error.BaseError, Error); util.inherits(error.BaseError, Error);
...@@ -21,9 +25,45 @@ util.inherits(error.BaseError, Error); ...@@ -21,9 +25,45 @@ util.inherits(error.BaseError, Error);
/** /**
* Validation Error * Validation Error
* *
* @param {string} message Error message
* @param {Array} [errors] Array of ValidationErrorItem objects describing the validation errors
* @constructor * @constructor
*/ */
error.ValidationError = function() { error.ValidationError = function(message, errors) {
error.BaseError.apply(this, arguments); error.BaseError.apply(this, arguments);
this.name = 'SequelizeValidationError';
this.errors = errors || [];
}; };
util.inherits(error.ValidationError, error.BaseError); util.inherits(error.ValidationError, error.BaseError);
/**
* Gets all validation error items for the path specified.
*
* @param {string} path The path to be checked for error items
* @returns {Array} Validation error items for the specified path
*/
error.ValidationError.prototype.get = function(path) {
return this.errors.reduce(function(reduced, error) {
if (error.path === path) {
reduced.push(error);
}
return reduced;
}, []);
};
/**
* Validation Error Item
* Instances of this class are included in the ValidationError errors property.
*
* @param {string} message An error message
* @param {string} type The type of the validation error
* @param {string} path The field that triggered the validation error
* @param {string} value The value that generated the error
* @constructor
*/
error.ValidationErrorItem = function(message, type, path, value) {
this.message = message || '';
this.type = type || null;
this.path = path || null;
this.value = value || null;
};
...@@ -115,10 +115,10 @@ var InstanceValidator = module.exports = function(modelInstance, options) { ...@@ -115,10 +115,10 @@ var InstanceValidator = module.exports = function(modelInstance, options) {
/** /**
* All errors will be stored here from the validations. * All errors will be stored here from the validations.
* *
* @type {Sequelize.error} Will contain keys that correspond to attributes which will * @type {Array} Will contain keys that correspond to attributes which will
* be Arrays of Errors. * be Arrays of Errors.
*/ */
this.errors = new sequelizeError.ValidationError('Validation error'); this.errors = [];
/** @type {boolean} Indicates if validations are in progress */ /** @type {boolean} Indicates if validations are in progress */
this.inProgress = false; this.inProgress = false;
...@@ -139,15 +139,14 @@ InstanceValidator.prototype.validate = function() { ...@@ -139,15 +139,14 @@ InstanceValidator.prototype.validate = function() {
throw new Error('Validations already in progress.'); throw new Error('Validations already in progress.');
} }
this.inProgress = true; this.inProgress = true;
this.errors = new sequelizeError.ValidationError('Validation error');
var self = this; var self = this;
return Promise.settle([ return Promise.settle([
self._builtinValidators(), self._builtinValidators(),
self._customValidators() self._customValidators()
]).then(function() { ]).then(function() {
if (Object.keys(self.errors).length) { if (self.errors.length) {
return self.errors; return new sequelizeError.ValidationError('Validation error', self.errors);
} }
return new Promise(function(resolve) { return new Promise(function(resolve) {
...@@ -361,26 +360,14 @@ InstanceValidator.prototype._validateSchema = function(rawAttribute, field, valu ...@@ -361,26 +360,14 @@ InstanceValidator.prototype._validateSchema = function(rawAttribute, field, valu
var error; var error;
if (rawAttribute.allowNull === false && ((value === null) || (value === undefined))) { if (rawAttribute.allowNull === false && ((value === null) || (value === undefined))) {
error = new sequelizeError.ValidationError(field + ' cannot be null'); error = new sequelizeError.ValidationErrorItem(field + ' cannot be null', 'notNull Violation', field, value);
error.path = field; this.errors.push(error);
error.value = value;
error.type = error.message = 'notNull Violation';
if (!this.errors.hasOwnProperty(field)) {
this.errors[field] = [];
}
this.errors[field].push(error);
} }
if (rawAttribute.type === DataTypes.STRING) { if (rawAttribute.type === DataTypes.STRING) {
if (Array.isArray(value) || (_.isObject(value) && !value._isSequelizeMethod)) { if (Array.isArray(value) || (_.isObject(value) && !value._isSequelizeMethod)) {
error = new sequelizeError.ValidationError(field + ' cannot be an array or an object'); error = new sequelizeError.ValidationErrorItem(field + ' cannot be an array or an object', 'string violation', field, value);
error.path = field; this.errors.push(error);
error.value = value;
error.type = error.message = 'string violation';
if (!this.errors.hasOwnProperty(field)) {
this.errors[field] = [];
}
this.errors[field].push(error);
} }
} }
}; };
...@@ -414,14 +401,9 @@ InstanceValidator.prototype._handleSettledResult = function(field, promiseInspec ...@@ -414,14 +401,9 @@ InstanceValidator.prototype._handleSettledResult = function(field, promiseInspec
* @private * @private
*/ */
InstanceValidator.prototype._pushError = function(isBuiltin, errorKey, rawError) { InstanceValidator.prototype._pushError = function(isBuiltin, errorKey, rawError) {
if (!this.errors.hasOwnProperty(errorKey)) { var message = rawError.message || rawError || 'Validation error';
this.errors[errorKey] = []; var error = new sequelizeError.ValidationErrorItem(message, 'Validation error', errorKey, rawError);
}
var error = new sequelizeError.ValidationError();
error[InstanceValidator.RAW_KEY_NAME] = rawError; error[InstanceValidator.RAW_KEY_NAME] = rawError;
error.message = rawError.message || rawError || 'Validation error';
this.errors[errorKey].push(error); this.errors.push(error);
}; };
...@@ -238,6 +238,13 @@ module.exports = (function() { ...@@ -238,6 +238,13 @@ module.exports = (function() {
sequelizeErrors.ValidationError; sequelizeErrors.ValidationError;
/** /**
* Describes a validation error on an instance path
* @property ValidationErrorItem
*/
Sequelize.prototype.ValidationErrorItem = Sequelize.ValidationErrorItem =
sequelizeErrors.ValidationErrorItem;
/**
* Returns the specified dialect. * Returns the specified dialect.
* *
* @return {String} The specified dialect. * @return {String} The specified dialect.
......
...@@ -425,16 +425,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -425,16 +425,16 @@ 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'); expect(err.get('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.smth[0].message).to.match(/notNull Violation/) expect(err.get('smth')[0].type).to.match(/notNull Violation/)
} }
else if (dialect === "sqlite") { else if (dialect === "sqlite") {
expect(err.smth[0].message).to.match(/notNull Violation/) expect(err.get('smth')[0].type).to.match(/notNull Violation/)
} else { } else {
expect(err.smth[0].message).to.match(/notNull Violation/) expect(err.get('smth')[0].type).to.match(/notNull Violation/)
} }
done() done()
}) })
...@@ -480,7 +480,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -480,7 +480,7 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
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].message).to.match(/Validation isURL failed/) expect(err.get('str')[0].message).to.match(/Validation isURL failed/)
done() done()
}) })
...@@ -1054,10 +1054,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { ...@@ -1054,10 +1054,10 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () {
expect(errors).to.be.an('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].message).to.equal('notNull Violation') expect(errors[0].errors.get('name')[0].type).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].message).to.equal('Validation len failed') expect(errors[1].errors.get('code')[0].message).to.equal('Validation len failed')
done() done()
}) })
}) })
......
...@@ -941,9 +941,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -941,9 +941,9 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
this.User.create({aNumber: 0, validateTest: 'hello'}).error(function(err){ this.User.create({aNumber: 0, validateTest: 'hello'}).error(function(err){
expect(err).to.exist expect(err).to.exist
expect(err).to.be.instanceof(Object) expect(err).to.be.instanceof(Object)
expect(err.validateTest).to.be.instanceof(Array) expect(err.get('validateTest')).to.be.instanceof(Array)
expect(err.validateTest[0]).to.exist expect(err.get('validateTest')[0]).to.exist
expect(err.validateTest[0].message).to.equal('Validation isInt failed') expect(err.get('validateTest')[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
...@@ -953,10 +953,10 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -953,10 +953,10 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
.error(function(err){ .error(function(err){
expect(err).to.exist expect(err).to.exist
expect(err).to.be.instanceof(Object) expect(err).to.be.instanceof(Object)
expect(err.validateCustom).to.exist expect(err.get('validateCustom')).to.exist
expect(err.validateCustom).to.be.instanceof(Array) expect(err.get('validateCustom')).to.be.instanceof(Array)
expect(err.validateCustom[0]).to.exist expect(err.get('validateCustom')[0]).to.exist
expect(err.validateCustom[0].message).to.equal('Length failed.') expect(err.get('validateCustom')[0].message).to.equal('Length failed.')
done() done()
}) })
}) })
...@@ -966,10 +966,10 @@ describe(Support.getTestDialectTeaser("DAO"), function () { ...@@ -966,10 +966,10 @@ describe(Support.getTestDialectTeaser("DAO"), function () {
user.updateAttributes({validateTest: 'hello'}).error(function(err){ user.updateAttributes({validateTest: 'hello'}).error(function(err){
expect(err).to.exist expect(err).to.exist
expect(err).to.be.instanceof(Object) expect(err).to.be.instanceof(Object)
expect(err.validateTest).to.exist expect(err.get('validateTest')).to.exist
expect(err.validateTest).to.be.instanceof(Array) expect(err.get('validateTest')).to.be.instanceof(Array)
expect(err.validateTest[0]).to.exist expect(err.get('validateTest')[0]).to.exist
expect(err.validateTest[0].message).to.equal('Validation isInt failed') expect(err.get('validateTest')[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
......
...@@ -196,7 +196,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -196,7 +196,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
failingUser.validate().done( function(err, _errors) { failingUser.validate().done( function(err, _errors) {
expect(_errors).not.to.be.null; expect(_errors).not.to.be.null;
expect(_errors).to.be.an.instanceOf(Error); expect(_errors).to.be.an.instanceOf(Error);
expect(_errors.name[0].message).to.equal(message); expect(_errors.get('name')[0].message).to.equal(message);
done(); done();
}); });
}); });
...@@ -296,7 +296,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -296,7 +296,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), 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.an.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.name[0].message).to.equal('Validation notEmpty failed'); expect(err.get('name')[0].message).to.equal('Validation notEmpty failed');
done() done()
}) })
}) })
...@@ -318,7 +318,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -318,7 +318,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
Model.create({name: 'World'}).success(function() { 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.an.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.name[0].message).to.equal('Validation notEmpty failed') expect(err.get('name')[0].message).to.equal('Validation notEmpty failed')
done() done()
}) })
}) })
...@@ -395,7 +395,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -395,7 +395,7 @@ 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.an.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id[0].message).to.equal('Validation isInt failed') expect(err.get('id')[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
...@@ -416,7 +416,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -416,7 +416,7 @@ 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.an.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.username[0].message).to.equal('Username must be an integer!') expect(err.get('username')[0].message).to.equal('Username must be an integer!')
done() done()
}) })
}) })
...@@ -443,7 +443,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -443,7 +443,7 @@ 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.an.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id[0].message).to.equal('ID must be an integer!') expect(err.get('id')[0].message).to.equal('ID must be an integer!')
done() done()
}) })
}) })
...@@ -453,7 +453,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -453,7 +453,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
user.validate().success(function(err) { user.validate().success(function(err) {
expect(err).to.be.an.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id[0].message).to.equal('ID must be an integer!') expect(err.get('id')[0].message).to.equal('ID must be an integer!')
done() done()
}) })
}) })
...@@ -462,7 +462,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -462,7 +462,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
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.an.instanceOf(Error) expect(err).to.be.an.instanceOf(Error)
expect(err.id[0].message).to.equal('ID must be an integer!') expect(err.get('id')[0].message).to.equal('ID must be an integer!')
done() done()
}) })
}) })
...@@ -538,7 +538,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -538,7 +538,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
failingUser.validate().success(function(error) { failingUser.validate().success(function(error) {
expect(error).to.be.an.instanceOf(Error) expect(error).to.be.an.instanceOf(Error)
expect(error.name[0].message).to.equal("name should equal '2'") expect(error.get('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(err) { successfulUser.validate().success(function(err) {
...@@ -569,7 +569,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -569,7 +569,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
User.sync().success(function () { User.sync().success(function () {
User.build({ name : "error" }).validate().success(function(error) { User.build({ name : "error" }).validate().success(function(error) {
expect(error).to.be.an.instanceOf(self.sequelize.ValidationError) expect(error).to.be.an.instanceOf(self.sequelize.ValidationError)
expect(error.name[0].message).to.equal("Invalid username") expect(error.get('name')[0].message).to.equal("Invalid username")
User.build({ name : "no error" }).validate().success(function(errors) { User.build({ name : "no error" }).validate().success(function(errors) {
expect(errors).not.to.be.defined expect(errors).not.to.be.defined
...@@ -596,7 +596,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -596,7 +596,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
.success(function(error) { .success(function(error) {
expect(error).not.to.be.null expect(error).not.to.be.null
expect(error).to.be.an.instanceOf(Error) expect(error).to.be.an.instanceOf(Error)
expect(error.age[0].message).to.equal("must be positive") expect(error.get('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() {
...@@ -634,7 +634,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -634,7 +634,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
.success(function(error) { .success(function(error) {
expect(error).not.to.be.null expect(error).not.to.be.null
expect(error).to.be.an.instanceOf(Error) expect(error).to.be.an.instanceOf(Error)
expect(error.xnor[0].message).to.equal('xnor failed'); expect(error.get('xnor')[0].message).to.equal('xnor failed');
Foo Foo
.build({ field1: 33, field2: null }) .build({ field1: 33, field2: null })
.validate() .validate()
...@@ -671,7 +671,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -671,7 +671,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
.success(function(error) { .success(function(error) {
expect(error).not.to.be.null expect(error).not.to.be.null
expect(error).to.be.an.instanceOf(Error) expect(error).to.be.an.instanceOf(Error)
expect(error.xnor[0].message).to.equal('xnor failed') expect(error.get('xnor')[0].message).to.equal('xnor failed')
Foo Foo
.build({ field1: 33, field2: null }) .build({ field1: 33, field2: null })
...@@ -720,8 +720,8 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -720,8 +720,8 @@ 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.get('field')).to.have.length(1)
expect(errors.field[0].message).to.equal("Validation isIn failed") expect(errors.get('field')[0].message).to.equal("Validation isIn failed")
}) })
}) })
...@@ -764,7 +764,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -764,7 +764,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
.done(function(errors){ .done(function(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[0].message).to.eql('Validation isImmutable failed') expect(errors.get('name')[0].message).to.eql('Validation isImmutable failed')
done() done()
}) })
}) })
...@@ -801,7 +801,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -801,7 +801,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
User.build({ User.build({
email: ['iama', 'dummy.com'] email: ['iama', 'dummy.com']
}).validate().success(function (errors) { }).validate().success(function (errors) {
expect(errors.email[0]).to.be.an.instanceof(Sequelize.ValidationError) expect(errors).to.be.an.instanceof(Sequelize.ValidationError)
done() done()
}) })
}) })
...@@ -816,7 +816,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -816,7 +816,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
User.build({ User.build({
email: {lol: true} email: {lol: true}
}).validate().success(function (errors) { }).validate().success(function (errors) {
expect(errors.email[0]).to.be.an.instanceof(Sequelize.ValidationError) expect(errors).to.be.an.instanceof(Sequelize.ValidationError)
done() done()
}) })
}) })
...@@ -862,7 +862,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -862,7 +862,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
salt: '42' salt: '42'
}).validate().then(function (errors) { }).validate().then(function (errors) {
expect(errors).not.to.be.undefined expect(errors).not.to.be.undefined
expect(errors.password[0].message).to.equal('Please choose a longer password') expect(errors.get('password')[0].message).to.equal('Please choose a longer password')
}), }),
User.build({ User.build({
password: 'loooooooong', password: 'loooooooong',
...@@ -896,7 +896,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() { ...@@ -896,7 +896,7 @@ describe(Support.getTestDialectTeaser("DaoValidator"), function() {
name: 'a' name: 'a'
}).validate() }).validate()
}).then(function (errors) { }).then(function (errors) {
expect(errors.name[0].message).to.equal('Validation isExactly7Characters failed') expect(errors.get('name')[0].message).to.equal('Validation isExactly7Characters failed')
}) })
}) })
}) })
......
...@@ -2,20 +2,19 @@ ...@@ -2,20 +2,19 @@
var chai = require('chai') var chai = require('chai')
, expect = chai.expect , expect = chai.expect
, Support = require(__dirname + '/support') , Support = require(__dirname + '/support')
, Sequelize = Support.Sequelize , Sequelize = Support.Sequelize;
// , sinon = require('sinon')
chai.config.includeStack = true chai.config.includeStack = true;
describe(Support.getTestDialectTeaser("Sequelize Errors"), function () { describe(Support.getTestDialectTeaser("Sequelize Errors"), function () {
describe('API Surface', function() { describe('API Surface', function() {
it('Should have the Error constructors exposed', function() { it('Should have the Error constructors exposed', function() {
expect(Sequelize).to.have.property('Error') expect(Sequelize).to.have.property('Error');
expect(Sequelize).to.have.property('ValidationError') expect(Sequelize).to.have.property('ValidationError');
var sequelize = new Sequelize(); var sequelize = new Sequelize();
expect(sequelize).to.have.property('Error') expect(sequelize).to.have.property('Error');
expect(sequelize).to.have.property('ValidationError') expect(sequelize).to.have.property('ValidationError');
}) });
it('Sequelize Errors instances should be instances of Error', function() { it('Sequelize Errors instances should be instances of Error', function() {
var error = new Sequelize.Error(); var error = new Sequelize.Error();
var validationError = new Sequelize.ValidationError(); var validationError = new Sequelize.ValidationError();
...@@ -25,10 +24,32 @@ describe(Support.getTestDialectTeaser("Sequelize Errors"), function () { ...@@ -25,10 +24,32 @@ describe(Support.getTestDialectTeaser("Sequelize Errors"), function () {
var instError = new sequelize.Error(); var instError = new sequelize.Error();
var instValidationError = new sequelize.ValidationError(); var instValidationError = new sequelize.ValidationError();
expect(error).to.be.instanceOf(Error) expect(error).to.be.instanceOf(Sequelize.Error);
expect(validationError).to.be.instanceOf(Error) expect(error).to.be.instanceOf(Error);
expect(instError).to.be.instanceOf(Error) expect(error).to.have.property('name', 'SequelizeBaseError');
expect(instValidationError).to.be.instanceOf(Error)
}) expect(validationError).to.be.instanceOf(Sequelize.ValidationError);
expect(validationError).to.be.instanceOf(Error);
expect(validationError).to.have.property('name', 'SequelizeValidationError');
expect(instError).to.be.instanceOf(Sequelize.Error);
expect(instError).to.be.instanceOf(Error);
expect(instValidationError).to.be.instanceOf(Sequelize.ValidationError);
expect(instValidationError).to.be.instanceOf(Error);
});
it('SequelizeValidationError should find errors by path', function() {
var errorItems = [
new Sequelize.ValidationErrorItem('invalid', 'type', 'first_name', null),
new Sequelize.ValidationErrorItem('invalid', 'type', 'last_name', null)
];
var validationError = new Sequelize.ValidationError('Validation error', errorItems);
expect(validationError).to.have.property('get');
expect(validationError.get).to.be.a('function');
var matches = validationError.get('first_name');
expect(matches).to.be.instanceOf(Array);
expect(matches).to.have.lengthOf(1);
expect(matches[0]).to.have.property('message', 'invalid')
});
}) })
}) });
...@@ -482,7 +482,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -482,7 +482,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[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral') expect(err.get('mood')[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -519,7 +519,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -519,7 +519,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[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ) expect(err.get('mood')[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -570,7 +570,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -570,7 +570,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[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ) expect(err.get('mood')[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -619,7 +619,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -619,7 +619,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[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ) expect(err.get('mood')[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -716,7 +716,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -716,7 +716,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[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ) expect(err.get('mood')[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -738,7 +738,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -738,7 +738,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[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' ) expect(err.get('mood')[0].message).to.equal( 'Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral' )
done() done()
}) })
}) })
...@@ -853,7 +853,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -853,7 +853,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[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral') expect(err.get('mood')[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -877,7 +877,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -877,7 +877,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[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral') expect(err.get('mood')[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -958,7 +958,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -958,7 +958,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[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral') expect(err.get('mood')[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -972,7 +972,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -972,7 +972,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[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral') expect(err.get('mood')[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -1079,7 +1079,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -1079,7 +1079,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[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral') expect(err.get('mood')[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral')
done() done()
}) })
}) })
...@@ -1103,7 +1103,7 @@ describe(Support.getTestDialectTeaser("Hooks"), function () { ...@@ -1103,7 +1103,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[0].message).to.equal('Value "ecstatic" for ENUM mood is out of allowed scope. Allowed values: happy, sad, neutral') expect(err.get('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[0].message).to.equal('Value "happy" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver') expect(err.get('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[0].message).to.equal('Value "SAD" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver') expect(err.get('mood')[0].message).to.equal('Value "SAD" for ENUM mood is out of allowed scope. Allowed values: HAPPY, sad, WhatEver')
done() done()
}) })
}) })
......
...@@ -278,9 +278,9 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -278,9 +278,9 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
.catch(function(err) { .catch(function(err) {
expect(err).to.be.ok expect(err).to.be.ok
expect(err).to.be.an("object") expect(err).to.be.an("object")
expect(err.validateTest).to.be.an("array") expect(err.get('validateTest')).to.be.an("array")
expect(err.validateTest[0]).to.be.ok expect(err.get('validateTest')[0]).to.be.ok
expect(err.validateTest[0].message).to.equal('Validation isInt failed') expect(err.get('validateTest')[0].message).to.equal('Validation isInt failed')
done() done()
}); });
}) })
...@@ -290,10 +290,10 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -290,10 +290,10 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
.catch(function(err) { .catch(function(err) {
expect(err).to.be.ok expect(err).to.be.ok
expect(err).to.be.an("object") expect(err).to.be.an("object")
expect(err.validateCustom).to.be.ok expect(err.get('validateCustom')).to.be.ok
expect(err.validateCustom).to.be.an("array") expect(err.get('validateCustom')).to.be.an("array")
expect(err.validateCustom[0]).to.be.ok expect(err.get('validateCustom')[0]).to.be.ok
expect(err.validateCustom[0].message).to.equal('Length failed.') expect(err.get('validateCustom')[0].message).to.equal('Length failed.')
done() done()
}) })
}) })
...@@ -304,10 +304,10 @@ describe(Support.getTestDialectTeaser("Promise"), function () { ...@@ -304,10 +304,10 @@ describe(Support.getTestDialectTeaser("Promise"), function () {
}).catch(function(err) { }).catch(function(err) {
expect(err).to.be.ok expect(err).to.be.ok
expect(err).to.be.an("object") expect(err).to.be.an("object")
expect(err.validateTest).to.be.ok expect(err.get('validateTest')).to.be.ok
expect(err.validateTest).to.be.an("array") expect(err.get('validateTest')).to.be.an("array")
expect(err.validateTest[0]).to.be.ok expect(err.get('validateTest')[0]).to.be.ok
expect(err.validateTest[0].message).to.equal('Validation isInt failed') expect(err.get('validateTest')[0].message).to.equal('Validation isInt failed')
done() done()
}) })
}) })
......
...@@ -783,7 +783,7 @@ describe(Support.getTestDialectTeaser("Sequelize"), function () { ...@@ -783,7 +783,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[0].message).to.equal('Value "fnord" for ENUM status is out of allowed scope. Allowed values: scheduled, active, finished') expect(err.get('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!