loopback-datasource-juggler/test/hooks.test.js

459 lines
12 KiB
JavaScript
Raw Normal View History

// Copyright IBM Corp. 2013,2019. All Rights Reserved.
2016-04-01 22:25:16 +00:00
// Node module: loopback-datasource-juggler
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
2016-08-22 19:55:22 +00:00
'use strict';
2013-04-06 10:57:12 +00:00
// This test written in mocha+should.js
/* global getSchema:false */
2018-12-07 14:54:29 +00:00
const should = require('./init.js');
2013-04-06 10:57:12 +00:00
2018-12-07 15:22:36 +00:00
const j = require('../'),
2014-01-24 17:09:53 +00:00
Schema = j.Schema,
AbstractClass = j.AbstractClass,
2018-12-07 15:22:36 +00:00
Hookable = j.Hookable;
2018-12-07 15:22:36 +00:00
let db, User;
2016-04-01 11:48:17 +00:00
describe('hooks', function() {
before(function(done) {
2014-01-24 17:09:53 +00:00
db = getSchema();
2014-01-24 17:09:53 +00:00
User = db.define('User', {
2016-08-19 17:46:59 +00:00
email: {type: String, index: true},
2014-01-24 17:09:53 +00:00
name: String,
password: String,
2016-04-01 11:48:17 +00:00
state: String,
});
db.automigrate('User', done);
2014-01-24 17:09:53 +00:00
});
2016-04-01 11:48:17 +00:00
describe('initialize', function() {
afterEach(function() {
2014-01-24 17:09:53 +00:00
User.afterInitialize = null;
});
2016-04-01 11:48:17 +00:00
it('should be triggered on new', function(done) {
User.afterInitialize = function() {
2014-01-24 17:09:53 +00:00
done();
};
new User;
});
2016-04-01 11:48:17 +00:00
it('should be triggered on create', function(done) {
2018-12-07 14:54:29 +00:00
let user;
2016-04-01 11:48:17 +00:00
User.afterInitialize = function() {
2014-01-24 17:09:53 +00:00
if (this.name === 'Nickolay') {
this.name += ' Rozental';
}
};
2016-08-19 17:46:59 +00:00
User.create({name: 'Nickolay'}, function(err, u) {
2014-01-24 17:09:53 +00:00
u.id.should.be.ok;
u.name.should.equal('Nickolay Rozental');
done();
});
});
2014-01-24 17:09:53 +00:00
});
2016-04-01 11:48:17 +00:00
describe('create', function() {
2014-01-24 17:09:53 +00:00
afterEach(removeHooks('Create'));
2016-04-01 11:48:17 +00:00
it('should be triggered on create', function(done) {
2014-01-24 17:09:53 +00:00
addHooks('Create', done);
User.create();
});
2016-04-01 11:48:17 +00:00
it('should not be triggered on new', function() {
User.beforeCreate = function(next) {
2014-01-24 17:09:53 +00:00
should.fail('This should not be called');
next();
};
2018-12-07 14:54:29 +00:00
const u = new User;
2014-01-24 17:09:53 +00:00
});
2016-04-01 11:48:17 +00:00
it('should be triggered on new+save', function(done) {
2014-01-24 17:09:53 +00:00
addHooks('Create', done);
(new User).save();
});
2016-04-01 11:48:17 +00:00
it('afterCreate should not be triggered on failed create', function(done) {
2018-12-07 14:54:29 +00:00
const old = User.dataSource.connector.create;
2016-04-01 11:48:17 +00:00
User.dataSource.connector.create = function(modelName, id, cb) {
2014-01-24 17:09:53 +00:00
cb(new Error('error'));
2016-04-01 11:48:17 +00:00
};
2014-01-24 17:09:53 +00:00
2016-04-01 11:48:17 +00:00
User.afterCreate = function() {
throw new Error('shouldn\'t be called');
};
2016-04-01 11:48:17 +00:00
User.create(function(err, user) {
User.dataSource.connector.create = old;
done();
});
});
2016-04-01 11:48:17 +00:00
it('afterCreate should not be triggered on failed beforeCreate', function(done) {
User.beforeCreate = function(next, data) {
// Skip next()
next(new Error('fail in beforeCreate'));
};
2018-12-07 14:54:29 +00:00
const old = User.dataSource.connector.create;
2016-04-01 11:48:17 +00:00
User.dataSource.connector.create = function(modelName, id, cb) {
throw new Error('shouldn\'t be called');
2016-04-01 11:48:17 +00:00
};
2016-04-01 11:48:17 +00:00
User.afterCreate = function() {
throw new Error('shouldn\'t be called');
2014-01-24 17:09:53 +00:00
};
2016-04-01 11:48:17 +00:00
User.create(function(err, user) {
2014-01-24 17:09:53 +00:00
User.dataSource.connector.create = old;
done();
});
});
});
2016-04-01 11:48:17 +00:00
describe('save', function() {
2014-01-24 17:09:53 +00:00
afterEach(removeHooks('Save'));
2016-04-01 11:48:17 +00:00
it('should be triggered on create', function(done) {
2014-01-24 17:09:53 +00:00
addHooks('Save', done);
User.create();
});
2016-04-01 11:48:17 +00:00
it('should be triggered on new+save', function(done) {
2014-01-24 17:09:53 +00:00
addHooks('Save', done);
(new User).save();
});
2016-04-01 11:48:17 +00:00
it('should be triggered on updateAttributes', function(done) {
User.create(function(err, user) {
2014-01-24 17:09:53 +00:00
addHooks('Save', done);
2016-08-19 17:46:59 +00:00
user.updateAttributes({name: 'Anatoliy'});
2014-01-24 17:09:53 +00:00
});
});
2016-04-01 11:48:17 +00:00
it('should be triggered on save', function(done) {
User.create(function(err, user) {
2014-01-24 17:09:53 +00:00
addHooks('Save', done);
user.name = 'Hamburger';
user.save();
});
});
2016-04-01 11:48:17 +00:00
it('should save full object', function(done) {
User.create(function(err, user) {
User.beforeSave = function(next, data) {
2014-01-24 17:09:53 +00:00
data.should.have.keys('id', 'name', 'email',
2016-04-01 11:48:17 +00:00
'password', 'state');
2014-01-24 17:09:53 +00:00
done();
};
user.save();
});
});
2016-04-01 11:48:17 +00:00
it('should save actual modifications to database', function(done) {
User.beforeSave = function(next, data) {
2014-01-24 17:09:53 +00:00
data.password = 'hash';
next();
};
2016-04-01 11:48:17 +00:00
User.destroyAll(function() {
2014-01-24 17:09:53 +00:00
User.create({
email: 'james.bond@example.com',
2016-04-01 11:48:17 +00:00
password: '53cr3t',
}, function() {
2014-01-24 17:09:53 +00:00
User.findOne({
2016-08-19 17:46:59 +00:00
where: {email: 'james.bond@example.com'},
2016-04-01 11:48:17 +00:00
}, function(err, jb) {
2014-01-24 17:09:53 +00:00
jb.password.should.equal('hash');
done();
});
});
2014-01-24 17:09:53 +00:00
});
});
2013-03-27 14:53:46 +00:00
2016-04-01 11:48:17 +00:00
it('should save actual modifications on updateAttributes', function(done) {
User.beforeSave = function(next, data) {
2014-01-24 17:09:53 +00:00
data.password = 'hash';
next();
};
2016-04-01 11:48:17 +00:00
User.destroyAll(function() {
2014-01-24 17:09:53 +00:00
User.create({
2016-04-01 11:48:17 +00:00
email: 'james.bond@example.com',
}, function(err, u) {
u.updateAttribute('password', 'new password', function(e, u) {
2014-01-24 17:09:53 +00:00
should.not.exist(e);
should.exist(u);
u.password.should.equal('hash');
User.findOne({
2016-08-19 17:46:59 +00:00
where: {email: 'james.bond@example.com'},
2016-04-01 11:48:17 +00:00
}, function(err, jb) {
2014-01-24 17:09:53 +00:00
jb.password.should.equal('hash');
done();
2013-03-27 14:53:46 +00:00
});
2014-01-24 17:09:53 +00:00
});
2013-03-27 14:53:46 +00:00
});
2014-01-24 17:09:53 +00:00
});
});
2016-04-01 11:48:17 +00:00
it('beforeSave should be able to skip next', function(done) {
User.create(function(err, user) {
User.beforeSave = function(next, data) {
next(null, 'XYZ');
};
user.save(function(err, result) {
result.should.be.eql('XYZ');
done();
});
});
});
2014-01-24 17:09:53 +00:00
});
2016-04-01 11:48:17 +00:00
describe('update', function() {
2014-01-24 17:09:53 +00:00
afterEach(removeHooks('Update'));
2016-04-01 11:48:17 +00:00
it('should not be triggered on create', function() {
User.beforeUpdate = function(next) {
2014-01-24 17:09:53 +00:00
should.fail('This should not be called');
next();
};
User.create();
});
2016-04-01 11:48:17 +00:00
it('should not be triggered on new+save', function() {
User.beforeUpdate = function(next) {
2014-01-24 17:09:53 +00:00
should.fail('This should not be called');
next();
};
(new User).save();
});
2016-04-01 11:48:17 +00:00
it('should be triggered on updateAttributes', function(done) {
User.create(function(err, user) {
2014-01-24 17:09:53 +00:00
addHooks('Update', done);
2016-08-19 17:46:59 +00:00
user.updateAttributes({name: 'Anatoliy'});
2014-01-24 17:09:53 +00:00
});
});
2016-04-01 11:48:17 +00:00
it('should be triggered on save', function(done) {
User.create(function(err, user) {
2014-01-24 17:09:53 +00:00
addHooks('Update', done);
user.name = 'Hamburger';
user.save();
});
});
2016-04-01 11:48:17 +00:00
it('should update limited set of fields', function(done) {
User.create(function(err, user) {
User.beforeUpdate = function(next, data) {
2014-01-24 17:09:53 +00:00
data.should.have.keys('name', 'email');
done();
};
2016-08-19 17:46:59 +00:00
user.updateAttributes({name: 1, email: 2});
2014-01-24 17:09:53 +00:00
});
});
2016-04-01 11:48:17 +00:00
it('should not trigger after-hook on failed save', function(done) {
User.afterUpdate = function() {
should.fail('afterUpdate shouldn\'t be called');
2014-01-24 17:09:53 +00:00
};
2016-04-01 11:48:17 +00:00
User.create(function(err, user) {
2018-12-07 14:54:29 +00:00
const save = User.dataSource.connector.save;
2016-04-01 11:48:17 +00:00
User.dataSource.connector.save = function(modelName, id, cb) {
2014-01-24 17:09:53 +00:00
User.dataSource.connector.save = save;
cb(new Error('Error'));
2016-04-01 11:48:17 +00:00
};
2014-01-24 17:09:53 +00:00
2016-04-01 11:48:17 +00:00
user.save(function(err) {
2014-01-24 17:09:53 +00:00
done();
});
2014-01-24 17:09:53 +00:00
});
});
});
2016-04-01 11:48:17 +00:00
describe('destroy', function() {
2014-01-24 17:09:53 +00:00
afterEach(removeHooks('Destroy'));
2013-03-31 10:17:25 +00:00
2016-04-01 11:48:17 +00:00
it('should be triggered on destroy', function(done) {
2018-12-07 14:54:29 +00:00
let hook = 'not called';
2016-04-01 11:48:17 +00:00
User.beforeDestroy = function(next) {
2014-01-24 17:09:53 +00:00
hook = 'called';
next();
};
2016-04-01 11:48:17 +00:00
User.afterDestroy = function(next) {
2014-01-24 17:09:53 +00:00
hook.should.eql('called');
next();
};
2016-04-01 11:48:17 +00:00
User.create(function(err, user) {
2014-01-24 17:09:53 +00:00
user.destroy(done);
});
});
2016-04-01 11:48:17 +00:00
it('should not trigger after-hook on failed destroy', function(done) {
2018-12-07 14:54:29 +00:00
const destroy = User.dataSource.connector.destroy;
2016-04-01 11:48:17 +00:00
User.dataSource.connector.destroy = function(modelName, id, cb) {
2014-01-24 17:09:53 +00:00
cb(new Error('error'));
};
2016-04-01 11:48:17 +00:00
User.afterDestroy = function() {
should.fail('afterDestroy shouldn\'t be called');
};
User.create(function(err, user) {
user.destroy(function(err) {
2014-01-24 17:09:53 +00:00
User.dataSource.connector.destroy = destroy;
done();
});
2014-01-24 17:09:53 +00:00
});
});
});
2016-04-01 11:48:17 +00:00
describe('lifecycle', function() {
2018-12-07 14:54:29 +00:00
let life = [], user;
2016-04-01 11:48:17 +00:00
before(function(done) {
User.beforeSave = function(d) {
2014-01-24 17:09:53 +00:00
life.push('beforeSave');
d();
};
2016-04-01 11:48:17 +00:00
User.beforeCreate = function(d) {
2014-01-24 17:09:53 +00:00
life.push('beforeCreate');
d();
};
2016-04-01 11:48:17 +00:00
User.beforeUpdate = function(d) {
2014-01-24 17:09:53 +00:00
life.push('beforeUpdate');
d();
};
2016-04-01 11:48:17 +00:00
User.beforeDestroy = function(d) {
2014-01-24 17:09:53 +00:00
life.push('beforeDestroy');
d();
};
2016-04-01 11:48:17 +00:00
User.beforeValidate = function(d) {
2014-01-24 17:09:53 +00:00
life.push('beforeValidate');
d();
};
2016-04-01 11:48:17 +00:00
User.afterInitialize = function() {
2014-01-24 17:09:53 +00:00
life.push('afterInitialize');
};
2016-04-01 11:48:17 +00:00
User.afterSave = function(d) {
2014-01-24 17:09:53 +00:00
life.push('afterSave');
d();
};
2016-04-01 11:48:17 +00:00
User.afterCreate = function(d) {
2014-01-24 17:09:53 +00:00
life.push('afterCreate');
d();
};
2016-04-01 11:48:17 +00:00
User.afterUpdate = function(d) {
2014-01-24 17:09:53 +00:00
life.push('afterUpdate');
d();
};
2016-04-01 11:48:17 +00:00
User.afterDestroy = function(d) {
2014-01-24 17:09:53 +00:00
life.push('afterDestroy');
d();
};
2016-04-01 11:48:17 +00:00
User.afterValidate = function(d) {
2014-01-24 17:09:53 +00:00
life.push('afterValidate');
d();
};
2016-04-01 11:48:17 +00:00
User.create(function(e, u) {
2014-01-24 17:09:53 +00:00
user = u;
life = [];
done();
});
});
2016-04-01 11:48:17 +00:00
beforeEach(function() {
2014-01-24 17:09:53 +00:00
life = [];
});
2016-04-01 11:48:17 +00:00
it('should describe create sequence', function(done) {
User.create(function() {
2014-01-24 17:09:53 +00:00
life.should.eql([
'afterInitialize',
'beforeValidate',
'afterValidate',
'beforeCreate',
'beforeSave',
'afterSave',
2016-04-01 11:48:17 +00:00
'afterCreate',
2014-01-24 17:09:53 +00:00
]);
done();
});
});
2016-04-01 11:48:17 +00:00
it('should describe new+save sequence', function(done) {
2018-12-07 14:54:29 +00:00
const u = new User;
2016-04-01 11:48:17 +00:00
u.save(function() {
2014-01-24 17:09:53 +00:00
life.should.eql([
'afterInitialize',
'beforeValidate',
'afterValidate',
'beforeCreate',
'beforeSave',
'afterSave',
2016-04-01 11:48:17 +00:00
'afterCreate',
2014-01-24 17:09:53 +00:00
]);
done();
});
});
2016-04-01 11:48:17 +00:00
it('should describe updateAttributes sequence', function(done) {
2016-08-19 17:46:59 +00:00
user.updateAttributes({name: 'Antony'}, function() {
2014-01-24 17:09:53 +00:00
life.should.eql([
'beforeValidate',
'afterValidate',
'beforeSave',
'beforeUpdate',
'afterUpdate',
'afterSave',
]);
done();
});
});
2016-04-01 11:48:17 +00:00
it('should describe isValid sequence', function(done) {
2014-01-24 17:09:53 +00:00
should.not.exist(
user.constructor._validations,
'Expected user to have no validations, but she have',
);
2016-04-01 11:48:17 +00:00
user.isValid(function(valid) {
2014-01-24 17:09:53 +00:00
valid.should.be.true;
life.should.eql([
'beforeValidate',
2016-04-01 11:48:17 +00:00
'afterValidate',
2014-01-24 17:09:53 +00:00
]);
done();
});
});
2016-04-01 11:48:17 +00:00
it('should describe destroy sequence', function(done) {
user.destroy(function() {
2014-01-24 17:09:53 +00:00
life.should.eql([
'beforeDestroy',
2016-04-01 11:48:17 +00:00
'afterDestroy',
2014-01-24 17:09:53 +00:00
]);
done();
});
});
2014-01-24 17:09:53 +00:00
});
});
function addHooks(name, done) {
2018-12-07 15:22:36 +00:00
const random = String(Math.floor(Math.random() * 1000));
let called = false;
2016-04-01 11:48:17 +00:00
User['before' + name] = function(next, data) {
2014-01-24 17:09:53 +00:00
called = true;
data.email = random;
next();
};
2016-04-01 11:48:17 +00:00
User['after' + name] = function(next) {
2014-01-24 17:09:53 +00:00
(new Boolean(called)).should.equal(true);
this.should.have.property('email', random);
2014-01-24 17:09:53 +00:00
done();
};
}
function removeHooks(name) {
2016-04-01 11:48:17 +00:00
return function() {
2014-01-24 17:09:53 +00:00
User['after' + name] = null;
User['before' + name] = null;
};
}