// Copyright IBM Corp. 2015,2016. All Rights Reserved. // Node module: loopback-datasource-juggler // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT // This test written in mocha+should.js var async = require('async'); var should = require('./init.js'); var db, User, options, ModelWithForceId, whereCount = 0; var j = require('../'); var ValidationError = j.ValidationError; var INITIAL_NAME = 'Bert'; var NEW_NAME = 'Ernie'; var INVALID_DATA = { name: null }; var VALID_DATA = { name: INITIAL_NAME }; describe('optional-validation', function() { before(function(done) { db = getSchema(); ModelWithForceId = db.createModel( 'ModelWithForceId', { name: String }, { forceId: true }); User = db.define('User', { seq: { type: Number, index: true }, name: { type: String, index: true, sort: true }, email: { type: String, index: true }, birthday: { type: Date, index: true }, role: { type: String, index: true }, order: { type: Number, index: true, sort: true }, vip: { type: Boolean }, }, { forceId: true, strict: true }); db.automigrate(['ModelWithForceId', 'User'], done); }); beforeEach(function(done) { User.destroyAll(function() { delete User.validations; User.validatesPresenceOf('name'); done(); }); }); function expectValidationError(done) { return function(err, result) { should.exist(err); err.should.be.instanceOf(Error); err.should.be.instanceOf(ValidationError); done(); }; } function expectCreateSuccess(data, done) { if (done === undefined && typeof data === 'function') { done = data; data = { name: INITIAL_NAME }; } return function(err, instance) { if (err) return done(err); instance.should.be.instanceOf(User); if (data.name) { instance.name.should.eql(data.name || INITIAL_NAME); } else { should.not.exist(instance.name); } done(); }; } function expectChangeSuccess(data, done) { if (done === undefined && typeof data === 'function') { done = data; data = { name: NEW_NAME }; } return function(err, instance) { if (err) return done(err); instance.should.be.instanceOf(User); if (data.name) { instance.name.should.eql(data.name || NEW_NAME); } else { should.not.exist(instance.name); } done(); }; } function createUserAndChangeName(name, cb) { User.create(VALID_DATA, { validate: true }, function(err, d) { d.name = name; cb(err, d); }); } function createUser(cb) { User.create(VALID_DATA, { validate: true }, cb); } function callUpdateOrCreateWithExistingUserId(name, options, cb) { User.create({ 'name': 'Groover' }, function(err, user) { if (err) return cb(err); var data = { name: name }; data.id = user.id; User.updateOrCreate(data, options, cb); }); } function getNewWhere() { return { name: 'DoesNotExist' + (whereCount++) }; } describe('forceId', function() { context('replaceAttributes', function() { it('should not fail if you do not pass the Primary key in data object', function(done) { ModelWithForceId.create({ name: 'foo' }, function(err, created) { if (err) return done(err); created.replaceAttributes({ name: 'bar' }, function(err, data) { done(err); }); }); }); it('should fail if you pass the Primary key in data object', function(done) { ModelWithForceId.create({ name: 'foo' }, function(err, created) { if (err) return done(err); created.replaceAttributes({ name: 'bar', id: 999 }, function(err, data) { should.exist(err); done(); }); }); }); }); }); describe('no model setting', function() { describe('method create', function() { it('should throw on create with validate:true with invalid data', function(done) { User.create(INVALID_DATA, { validate: true }, expectValidationError(done)); }); it('should NOT throw on create with validate:false with invalid data', function(done) { User.create(INVALID_DATA, { validate: false }, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on create with validate:true with valid data', function(done) { User.create(VALID_DATA, { validate: true }, expectCreateSuccess(done)); }); it('should NOT throw on create with validate:false with valid data', function(done) { User.create(VALID_DATA, { validate: false }, expectCreateSuccess(done)); }); it('should throw on create with invalid data', function(done) { User.create(INVALID_DATA, expectValidationError(done)); }); it('should NOT throw on create with valid data', function(done) { User.create(VALID_DATA, expectCreateSuccess(done)); }); }); describe('method findOrCreate', function() { it('should throw on findOrCreate with validate:true with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, { validate: true }, expectValidationError(done)); }); it('should NOT throw on findOrCreate with validate:false with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, { validate: false }, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on findOrCreate with validate:true with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, { validate: true }, expectCreateSuccess(done)); }); it('should NOT throw on findOrCreate with validate:false with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, { validate: false }, expectCreateSuccess(done)); }); it('should throw on findOrCreate with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, expectValidationError(done)); }); it('should NOT throw on findOrCreate with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, expectCreateSuccess(done)); }); }); describe('method updateOrCreate on existing data', function() { it('should throw on updateOrCreate(id) with validate:true with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, { validate: true }, expectValidationError(done)); }); it('should NOT throw on updateOrCreate(id) with validate:false with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, { validate: false }, expectChangeSuccess(INVALID_DATA, done)); }); it('should NOT throw on updateOrCreate(id) with validate:true with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, { validate: true }, expectChangeSuccess(done)); }); it('should NOT throw on updateOrCreate(id) with validate:false with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, { validate: false }, expectChangeSuccess(done)); }); // backwards compatible with validateUpsert it('should NOT throw on updateOrCreate(id) with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, expectChangeSuccess(INVALID_DATA, done)); }); it('should NOT throw on updateOrCreate(id) with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, expectChangeSuccess(done)); }); }); describe('method save', function() { it('should throw on save with {validate:true} with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save({ validate: true }, expectValidationError(done)); }); }); it('should NOT throw on save with {validate:false} with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save({ validate: false }, expectChangeSuccess(INVALID_DATA, done)); }); }); it('should NOT throw on save with {validate:true} with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save({ validate: true }, expectChangeSuccess(done)); }); }); it('should NOT throw on save with {validate:false} with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save({ validate: false }, expectChangeSuccess(done)); }); }); it('should throw on save(cb) with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save(expectValidationError(done)); }); }); it('should NOT throw on save(cb) with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save(expectChangeSuccess(done)); }); }); }); describe('method updateAttributes', function() { it('should throw on updateAttributes with {validate:true} with invalid data', function(done) { createUser(function(err, d) { d.updateAttributes(INVALID_DATA, { validate: true }, expectValidationError(done)); }); }); it('should NOT throw on updateAttributes with {validate:false} with invalid data', function(done) { createUser(function(err, d) { d.updateAttributes(INVALID_DATA, { validate: false }, expectChangeSuccess(INVALID_DATA, done)); }); }); it('should NOT throw on updateAttributes with {validate:true} with valid data', function(done) { createUser(function(err, d) { d.updateAttributes({ 'name': NEW_NAME }, { validate: true }, expectChangeSuccess(done)); }); }); it('should NOT throw on updateAttributes with {validate:false} with valid data', function(done) { createUser(function(err, d) { d.updateAttributes({ 'name': NEW_NAME }, { validate: false }, expectChangeSuccess(done)); }); }); it('should throw on updateAttributes(cb) with invalid data', function(done) { createUser(function(err, d) { d.updateAttributes(INVALID_DATA, expectValidationError(done)); }); }); it('should NOT throw on updateAttributes(cb) with valid data', function(done) { createUser(function(err, d) { d.updateAttributes({ 'name': NEW_NAME }, expectChangeSuccess(done)); }); }); }); }); describe('model setting: automaticValidation: false', function() { before(function(done) { User.settings.automaticValidation = false; done(); }); describe('method create', function() { it('should throw on create with validate:true with invalid data', function(done) { User.create(INVALID_DATA, { validate: true }, expectValidationError(done)); }); it('should NOT throw on create with validate:false with invalid data', function(done) { User.create(INVALID_DATA, { validate: false }, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on create with validate:true with valid data', function(done) { User.create(VALID_DATA, { validate: true }, expectCreateSuccess(done)); }); it('should NOT throw on create with validate:false with valid data', function(done) { User.create(VALID_DATA, { validate: false }, expectCreateSuccess(done)); }); it('should NOT throw on create with invalid data', function(done) { User.create(INVALID_DATA, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on create with valid data', function(done) { User.create(VALID_DATA, expectCreateSuccess(done)); }); }); describe('method findOrCreate', function() { it('should throw on findOrCreate with validate:true with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, { validate: true }, expectValidationError(done)); }); it('should NOT throw on findOrCreate with validate:false with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, { validate: false }, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on findOrCreate with validate:true with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, { validate: true }, expectCreateSuccess(done)); }); it('should NOT throw on findOrCreate with validate:false with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, { validate: false }, expectCreateSuccess(done)); }); it('should NOT throw on findOrCreate with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on findOrCreate with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, expectCreateSuccess(done)); }); }); describe('method updateOrCreate on existing data', function() { it('should throw on updateOrCreate(id) with validate:true with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, { validate: true }, expectValidationError(done)); }); it('should NOT throw on updateOrCreate(id) with validate:false with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, { validate: false }, expectChangeSuccess(INVALID_DATA, done)); }); it('should NOT throw on updateOrCreate(id) with validate:true with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, { validate: true }, expectChangeSuccess(done)); }); it('should NOT throw on updateOrCreate(id) with validate:false with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, { validate: false }, expectChangeSuccess(done)); }); it('should NOT throw on updateOrCreate(id) with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, expectChangeSuccess(INVALID_DATA, done)); }); it('should NOT throw on updateOrCreate(id) with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, expectChangeSuccess(done)); }); }); describe('method save', function() { it('should throw on save with {validate:true} with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save({ validate: true }, expectValidationError(done)); }); }); it('should NOT throw on save with {validate:false} with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save({ validate: false }, expectChangeSuccess(INVALID_DATA, done)); }); }); it('should NOT throw on save with {validate:true} with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save({ validate: true }, expectChangeSuccess(done)); }); }); it('should NOT throw on save with {validate:false} with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save({ validate: false }, expectChangeSuccess(done)); }); }); it('should NOT throw on save(cb) with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save(expectChangeSuccess(INVALID_DATA, done)); }); }); it('should NOT throw on save(cb) with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save(expectChangeSuccess(done)); }); }); }); }); describe('model setting: automaticValidation: true', function() { before(function(done) { User.settings.automaticValidation = true; done(); }); describe('method create', function() { it('should throw on create with validate:true with invalid data', function(done) { User.create(INVALID_DATA, { validate: true }, expectValidationError(done)); }); it('should NOT throw on create with validate:false with invalid data', function(done) { User.create(INVALID_DATA, { validate: false }, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on create with validate:true with valid data', function(done) { User.create(VALID_DATA, { validate: true }, expectCreateSuccess(done)); }); it('should NOT throw on create with validate:false with valid data', function(done) { User.create(VALID_DATA, { validate: false }, expectCreateSuccess(done)); }); it('should throw on create with invalid data', function(done) { User.create(INVALID_DATA, expectValidationError(done)); }); it('should NOT throw on create with valid data', function(done) { User.create(VALID_DATA, expectCreateSuccess(done)); }); }); describe('method findOrCreate', function() { it('should throw on findOrCreate with validate:true with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, { validate: true }, expectValidationError(done)); }); it('should NOT throw on findOrCreate with validate:false with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, { validate: false }, expectCreateSuccess(INVALID_DATA, done)); }); it('should NOT throw on findOrCreate with validate:true with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, { validate: true }, expectCreateSuccess(done)); }); it('should NOT throw on findOrCreate with validate:false with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, { validate: false }, expectCreateSuccess(done)); }); it('should throw on findOrCreate with invalid data', function(done) { User.findOrCreate(getNewWhere(), INVALID_DATA, expectValidationError(done)); }); it('should NOT throw on findOrCreate with valid data', function(done) { User.findOrCreate(getNewWhere(), VALID_DATA, expectCreateSuccess(done)); }); }); describe('method updateOrCreate on existing data', function() { it('should throw on updateOrCreate(id) with validate:true with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, { validate: true }, expectValidationError(done)); }); it('should NOT throw on updateOrCreate(id) with validate:false with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, { validate: false }, expectChangeSuccess(INVALID_DATA, done)); }); it('should NOT throw on updateOrCreate(id) with validate:true with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, { validate: true }, expectChangeSuccess(done)); }); it('should NOT throw on updateOrCreate(id) with validate:false with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, { validate: false }, expectChangeSuccess(done)); }); it('should throw on updateOrCreate(id) with invalid data', function(done) { callUpdateOrCreateWithExistingUserId(null, expectValidationError(done)); }); it('should NOT throw on updateOrCreate(id) with valid data', function(done) { callUpdateOrCreateWithExistingUserId(NEW_NAME, expectChangeSuccess(done)); }); }); describe('method save', function() { it('should throw on save with {validate:true} with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save(options, expectValidationError(done)); }); }); it('should NOT throw on save with {validate:false} with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save({ validate: false }, expectChangeSuccess(INVALID_DATA, done)); }); }); it('should NOT throw on save with {validate:true} with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save({ validate: true }, expectChangeSuccess(done)); }); }); it('should NOT throw on save with {validate:false} with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save({ validate: false }, expectChangeSuccess(done)); }); }); it('should throw on save(cb) with invalid data', function(done) { createUserAndChangeName(null, function(err, d) { d.save(expectValidationError(done)); }); }); it('should NOT throw on save(cb) with valid data', function(done) { createUserAndChangeName(NEW_NAME, function(err, d) { d.save(expectChangeSuccess(done)); }); }); }); }); });