Skip to content

Commit

Permalink
test: add tests for passing the CLS transaction to hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
ephys committed Jan 12, 2022
1 parent bfb54d4 commit 6294414
Showing 1 changed file with 191 additions and 0 deletions.
191 changes: 191 additions & 0 deletions test/integration/cls.test.js
Expand Up @@ -140,6 +140,197 @@ if (current.dialect.supports.transactions) {
});
});

// reason for this test: https://github.com/sequelize/sequelize/issues/12973
describe('Model Hook integration', () => {
function testHooks({ method, hooks: hookNames, optionPos, execute }) {
it(`passes the transaction to hooks {${hookNames.join(',')}} when calling ${method}`, async function () {
await this.sequelize.transaction(async transaction => {
const hooks = Object.create(null);

for (const hookName of hookNames) {
hooks[hookName] = sinon.spy();
}

for (const [hookName, spy] of Object.entries(hooks)) {
this.User[hookName](spy);
}

await Reflect.apply(execute, this, [this.User]);

const spyMatcher = [];
// ignore all arguments until we get to the option bag.
for (let i = 0; i < optionPos; i++) {
spyMatcher.push(sinon.match.any);
}

// find the transaction in the option bag
spyMatcher.push(sinon.match.has('transaction', transaction));

for (const [hookName, spy] of Object.entries(hooks)) {
expect(
spy,
`hook ${hookName} did not receive the transaction from CLS.`,
).to.have.been.calledWith(...spyMatcher);
}
});
});
}

testHooks({
method: 'Model.bulkCreate',
hooks: ['beforeBulkCreate', 'beforeCreate', 'afterCreate', 'afterBulkCreate'],
optionPos: 1,
async execute(User) {
await User.bulkCreate([{ name: 'bob' }], { individualHooks: true });
},
});

testHooks({
method: 'Model.findAll',
hooks: ['beforeFind', 'beforeFindAfterExpandIncludeAll', 'beforeFindAfterOptions', 'afterFind'],
optionPos: 0,
async execute(User) {
await User.findAll();
},
});

testHooks({
method: 'Model.count',
hooks: ['beforeCount'],
optionPos: 0,
async execute(User) {
await User.count();
},
});

testHooks({
method: 'Model.upsert',
hooks: ['beforeCount', 'afterUpsert'],
optionPos: 1,
async execute(User) {
await User.upsert({
name: 'bob',
});
},
});

testHooks({
method: 'Model.destroy',
hooks: ['beforeBulkDestroy', 'afterBulkDestroy'],
optionPos: 0,
async execute(User) {
await User.destroy({ where: { name: 'bob' } });
},
});

testHooks({
method: 'Model.destroy with individualHooks',
hooks: ['beforeDestroy', 'beforeDestroy'],
optionPos: 1,
async execute(User) {
await User.create({ name: 'bob' });
await User.destroy({ where: { name: 'bob' }, individualHooks: true });
},
});

testHooks({
method: 'Model#destroy',
hooks: ['beforeDestroy', 'beforeDestroy'],
optionPos: 1,
async execute(User) {
const user = await User.create({ name: 'bob' });
await user.destroy();
},
});

testHooks({
method: 'Model.update',
hooks: ['beforeBulkUpdate', 'afterBulkUpdate'],
optionPos: 0,
async execute(User) {
await User.update({ name: 'alice' }, { where: { name: 'bob' } });
},
});

testHooks({
method: 'Model.update with individualHooks',
hooks: ['beforeUpdate', 'afterUpdate'],
optionPos: 1,
async execute(User) {
await User.create({ name: 'bob' });
await User.update({ name: 'alice' }, { where: { name: 'bob' }, individualHooks: true });
},
});

testHooks({
method: 'Model#save (isNewRecord)',
hooks: ['beforeCreate', 'beforeUpdate'],
optionPos: 1,
async execute(User) {
const user = User.build({ name: 'bob' });
user.name = 'alice';
await user.save();
},
});

testHooks({
method: 'Model#save (!isNewRecord)',
hooks: ['beforeUpdate', 'afterUpdate'],
optionPos: 1,
async execute(User) {
const user = await User.create({ name: 'bob' });
user.name = 'alice';
await user.save();
},
});

describe('paranoid restore', () => {
beforeEach(async function () {
this.ParanoidUser = this.sequelize.define('paranoid_user', {
name: Sequelize.STRING,
}, { paranoid: true });

await this.ParanoidUser.sync({ force: true });
});

testHooks({
method: 'Model.restore',
hooks: ['beforeBulkRestore', 'afterBulkRestore'],
optionPos: 0,
async execute() {
const User = this.ParanoidUser;
await User.restore({ where: { name: 'bob' } });
},
});

testHooks({
method: 'Model.restore with individualHooks',
hooks: ['beforeRestore', 'afterRestore'],
optionPos: 1,
async execute() {
const User = this.ParanoidUser;

await User.create({ name: 'bob' });
await User.destroy({ where: { name: 'bob' } });
await User.restore({ where: { name: 'bob' }, individualHooks: true });
},
});

testHooks({
method: 'Model#restore',
hooks: ['beforeRestore', 'afterRestore'],
optionPos: 1,
async execute() {
const User = this.ParanoidUser;

const user = await User.create({ name: 'bob' });
await user.destroy();
await user.restore();
},
});
});
});

it('CLS namespace is stored in Sequelize._cls', function () {
expect(Sequelize._cls).to.equal(this.ns);
});
Expand Down

0 comments on commit 6294414

Please sign in to comment.