destroy.test.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. 'use strict';
  2. const chai = require('chai');
  3. const expect = chai.expect;
  4. const Support = require('../support');
  5. const { DataTypes } = require('@sequelize/core');
  6. const sinon = require('sinon');
  7. describe(Support.getTestDialectTeaser('Hooks'), () => {
  8. beforeEach(async function () {
  9. this.User = this.sequelize.define('User', {
  10. username: {
  11. type: DataTypes.STRING,
  12. allowNull: false,
  13. },
  14. mood: {
  15. type: DataTypes.ENUM(['happy', 'sad', 'neutral']),
  16. },
  17. });
  18. await this.sequelize.sync({ force: true });
  19. });
  20. describe('#destroy', () => {
  21. describe('on success', () => {
  22. it('should run hooks', async function () {
  23. const beforeHook = sinon.spy();
  24. const afterHook = sinon.spy();
  25. this.User.beforeDestroy(beforeHook);
  26. this.User.afterDestroy(afterHook);
  27. const user = await this.User.create({ username: 'Toni', mood: 'happy' });
  28. await user.destroy();
  29. expect(beforeHook).to.have.been.calledOnce;
  30. expect(afterHook).to.have.been.calledOnce;
  31. });
  32. });
  33. describe('on error', () => {
  34. it('should return an error from before', async function () {
  35. const beforeHook = sinon.spy();
  36. const afterHook = sinon.spy();
  37. this.User.beforeDestroy(() => {
  38. beforeHook();
  39. throw new Error('Whoops!');
  40. });
  41. this.User.afterDestroy(afterHook);
  42. const user = await this.User.create({ username: 'Toni', mood: 'happy' });
  43. await expect(user.destroy()).to.be.rejected;
  44. expect(beforeHook).to.have.been.calledOnce;
  45. expect(afterHook).not.to.have.been.called;
  46. });
  47. it('should return an error from after', async function () {
  48. const beforeHook = sinon.spy();
  49. const afterHook = sinon.spy();
  50. this.User.beforeDestroy(beforeHook);
  51. this.User.afterDestroy(() => {
  52. afterHook();
  53. throw new Error('Whoops!');
  54. });
  55. const user = await this.User.create({ username: 'Toni', mood: 'happy' });
  56. await expect(user.destroy()).to.be.rejected;
  57. expect(beforeHook).to.have.been.calledOnce;
  58. expect(afterHook).to.have.been.calledOnce;
  59. });
  60. });
  61. describe('with paranoid mode enabled', () => {
  62. beforeEach(function () {
  63. this.ParanoidUser = this.sequelize.define(
  64. 'ParanoidUser',
  65. {
  66. username: DataTypes.STRING,
  67. updatedBy: DataTypes.INTEGER,
  68. virtualField: {
  69. type: DataTypes.VIRTUAL(DataTypes.INTEGER, ['updatedBy']),
  70. get() {
  71. return this.updatedBy - 1;
  72. },
  73. },
  74. },
  75. {
  76. paranoid: true,
  77. hooks: {
  78. beforeDestroy: instance => {
  79. instance.updatedBy = 1;
  80. },
  81. },
  82. },
  83. );
  84. });
  85. it('sets other changed values when soft deleting and a beforeDestroy hooks kicks in', async function () {
  86. await this.ParanoidUser.sync({ force: true });
  87. const user0 = await this.ParanoidUser.create({ username: 'user1' });
  88. await user0.destroy();
  89. const user = await this.ParanoidUser.findOne({ paranoid: false });
  90. expect(user.updatedBy).to.equal(1);
  91. });
  92. it('should not throw error when a beforeDestroy hook changes a virtual column', async function () {
  93. this.ParanoidUser.beforeDestroy(instance => {
  94. instance.virtualField = 2;
  95. });
  96. await this.ParanoidUser.sync({ force: true });
  97. const user0 = await this.ParanoidUser.create({ username: 'user1' });
  98. await user0.destroy();
  99. const user = await this.ParanoidUser.findOne({ paranoid: false });
  100. expect(user.virtualField).to.equal(0);
  101. });
  102. });
  103. });
  104. });