EmailHandlerTests.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. const SandboxedModule = require('sandboxed-module')
  2. const path = require('path')
  3. const sinon = require('sinon')
  4. const { expect } = require('chai')
  5. const MODULE_PATH = path.join(
  6. __dirname,
  7. '../../../../app/src/Features/Email/EmailHandler'
  8. )
  9. describe('EmailHandler', function () {
  10. beforeEach(function () {
  11. this.html = '<html>hello</html>'
  12. this.Settings = { email: {} }
  13. this.EmailBuilder = {
  14. buildEmail: sinon.stub().returns({ html: this.html }),
  15. }
  16. this.EmailSender = {
  17. promises: {
  18. sendEmail: sinon.stub().resolves(),
  19. },
  20. }
  21. this.Queues = {
  22. createScheduledJob: sinon.stub(),
  23. }
  24. this.EmailHandler = SandboxedModule.require(MODULE_PATH, {
  25. requires: {
  26. './EmailBuilder': this.EmailBuilder,
  27. './EmailSender': this.EmailSender,
  28. '@overleaf/settings': this.Settings,
  29. '../../infrastructure/Queues': this.Queues,
  30. },
  31. })
  32. })
  33. describe('send email', function () {
  34. it('should use the correct options', async function () {
  35. const opts = { to: 'bob@bob.com' }
  36. await this.EmailHandler.promises.sendEmail('welcome', opts)
  37. expect(this.EmailSender.promises.sendEmail).to.have.been.calledWithMatch({
  38. html: this.html,
  39. })
  40. })
  41. it('should return the error', async function () {
  42. this.EmailSender.promises.sendEmail.rejects(new Error('boom'))
  43. const opts = {
  44. to: 'bob@bob.com',
  45. subject: 'hello bob',
  46. }
  47. await expect(this.EmailHandler.promises.sendEmail('welcome', opts)).to.be
  48. .rejected
  49. })
  50. it('should not send an email if lifecycle is not enabled', async function () {
  51. this.Settings.email.lifecycle = false
  52. this.EmailBuilder.buildEmail.returns({ type: 'lifecycle' })
  53. await this.EmailHandler.promises.sendEmail('welcome', {})
  54. expect(this.EmailSender.promises.sendEmail).not.to.have.been.called
  55. })
  56. it('should send an email if lifecycle is not enabled but the type is notification', async function () {
  57. this.Settings.email.lifecycle = false
  58. this.EmailBuilder.buildEmail.returns({ type: 'notification' })
  59. const opts = { to: 'bob@bob.com' }
  60. await this.EmailHandler.promises.sendEmail('welcome', opts)
  61. expect(this.EmailSender.promises.sendEmail).to.have.been.called
  62. })
  63. it('should send lifecycle email if it is enabled', async function () {
  64. this.Settings.email.lifecycle = true
  65. this.EmailBuilder.buildEmail.returns({ type: 'lifecycle' })
  66. const opts = { to: 'bob@bob.com' }
  67. await this.EmailHandler.promises.sendEmail('welcome', opts)
  68. expect(this.EmailSender.promises.sendEmail).to.have.been.called
  69. })
  70. describe('with plain-text email content', function () {
  71. beforeEach(function () {
  72. this.text = 'hello there'
  73. })
  74. it('should pass along the text field', async function () {
  75. this.EmailBuilder.buildEmail.returns({
  76. html: this.html,
  77. text: this.text,
  78. })
  79. const opts = { to: 'bob@bob.com' }
  80. await this.EmailHandler.promises.sendEmail('welcome', opts)
  81. expect(
  82. this.EmailSender.promises.sendEmail
  83. ).to.have.been.calledWithMatch({
  84. html: this.html,
  85. text: this.text,
  86. })
  87. })
  88. })
  89. })
  90. describe('send deferred email', function () {
  91. beforeEach(function () {
  92. this.opts = {
  93. to: 'bob@bob.com',
  94. first_name: 'hello bob',
  95. }
  96. this.emailType = 'canceledSubscription'
  97. this.ONE_HOUR_IN_MS = 1000 * 60 * 60
  98. this.EmailHandler.sendDeferredEmail(
  99. this.emailType,
  100. this.opts,
  101. this.ONE_HOUR_IN_MS
  102. )
  103. })
  104. it('should add a email job to the queue', function () {
  105. expect(this.Queues.createScheduledJob).to.have.been.calledWith(
  106. 'deferred-emails',
  107. { data: { emailType: this.emailType, opts: this.opts } },
  108. this.ONE_HOUR_IN_MS
  109. )
  110. })
  111. })
  112. })