NewsletterManagerTests.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. const { expect } = require('chai')
  2. const sinon = require('sinon')
  3. const SandboxedModule = require('sandboxed-module')
  4. const MODULE_PATH = '../../../../app/src/Features/Newsletter/NewsletterManager'
  5. describe('NewsletterManager', function() {
  6. beforeEach('setup mocks', function() {
  7. this.Settings = {
  8. mailchimp: {
  9. api_key: 'api_key',
  10. list_id: 'list_id'
  11. }
  12. }
  13. this.mailchimp = {
  14. put: sinon.stub(),
  15. patch: sinon.stub(),
  16. delete: sinon.stub()
  17. }
  18. this.Mailchimp = sinon.stub().returns(this.mailchimp)
  19. this.mergeFields = {
  20. FNAME: 'Overleaf',
  21. LNAME: 'Duck',
  22. MONGO_ID: 'user_id'
  23. }
  24. this.NewsletterManager = SandboxedModule.require(MODULE_PATH, {
  25. requires: {
  26. 'logger-sharelatex': { info: sinon.stub() },
  27. 'mailchimp-api-v3': this.Mailchimp,
  28. 'settings-sharelatex': this.Settings
  29. },
  30. globals: { console: console }
  31. }).promises
  32. this.user = {
  33. _id: 'user_id',
  34. email: 'overleaf.duck@example.com',
  35. first_name: 'Overleaf',
  36. last_name: 'Duck'
  37. }
  38. // MD5 sum of the user email
  39. this.emailHash = 'c02f60ed0ef51818186274e406c9a48f'
  40. })
  41. describe('subscribe', function() {
  42. it('calls Mailchimp to subscribe the user', async function() {
  43. await this.NewsletterManager.subscribe(this.user)
  44. expect(this.mailchimp.put).to.have.been.calledWith(
  45. `/lists/list_id/members/${this.emailHash}`,
  46. {
  47. email_address: this.user.email,
  48. status: 'subscribed',
  49. status_if_new: 'subscribed',
  50. merge_fields: this.mergeFields
  51. }
  52. )
  53. })
  54. })
  55. describe('unsubscribe', function() {
  56. describe('when unsubscribing normally', function() {
  57. it('calls Mailchimp to unsubscribe the user', async function() {
  58. await this.NewsletterManager.unsubscribe(this.user)
  59. expect(this.mailchimp.patch).to.have.been.calledWith(
  60. `/lists/list_id/members/${this.emailHash}`,
  61. {
  62. status: 'unsubscribed',
  63. merge_fields: this.mergeFields
  64. }
  65. )
  66. })
  67. it('ignores a Mailchimp error about fake emails', async function() {
  68. this.mailchimp.patch.rejects(
  69. new Error(
  70. 'overleaf.duck@example.com looks fake or invalid, please enter a real email address'
  71. )
  72. )
  73. await expect(this.NewsletterManager.unsubscribe(this.user)).to.be
  74. .fulfilled
  75. })
  76. it('rejects on other errors', async function() {
  77. this.mailchimp.patch.rejects(
  78. new Error('something really wrong is happening')
  79. )
  80. await expect(this.NewsletterManager.unsubscribe(this.user)).to.be
  81. .rejected
  82. })
  83. })
  84. describe('when deleting', function() {
  85. it('calls Mailchimp to delete the user', async function() {
  86. await this.NewsletterManager.unsubscribe(this.user, { delete: true })
  87. expect(this.mailchimp.delete).to.have.been.calledWith(
  88. `/lists/list_id/members/${this.emailHash}`
  89. )
  90. })
  91. it('ignores a Mailchimp error about fake emails', async function() {
  92. this.mailchimp.delete.rejects(
  93. new Error(
  94. 'overleaf.duck@example.com looks fake or invalid, please enter a real email address'
  95. )
  96. )
  97. await expect(
  98. this.NewsletterManager.unsubscribe(this.user, { delete: true })
  99. ).to.be.fulfilled
  100. })
  101. it('rejects on other errors', async function() {
  102. this.mailchimp.delete.rejects(
  103. new Error('something really wrong is happening')
  104. )
  105. await expect(
  106. this.NewsletterManager.unsubscribe(this.user, { delete: true })
  107. ).to.be.rejected
  108. })
  109. })
  110. })
  111. describe('changeEmail', function() {
  112. it('calls Mailchimp to change the subscriber email', async function() {
  113. await this.NewsletterManager.changeEmail(
  114. this.user,
  115. 'overleaf.squirrel@example.com'
  116. )
  117. expect(this.mailchimp.patch).to.have.been.calledWith(
  118. `/lists/list_id/members/${this.emailHash}`,
  119. {
  120. email_address: 'overleaf.squirrel@example.com',
  121. merge_fields: this.mergeFields
  122. }
  123. )
  124. })
  125. it('deletes the old email if changing the address fails', async function() {
  126. this.mailchimp.patch
  127. .withArgs(`/lists/list_id/members/${this.emailHash}`, {
  128. email_address: 'overleaf.squirrel@example.com',
  129. merge_fields: this.mergeFields
  130. })
  131. .rejects(new Error('that did not work'))
  132. await expect(
  133. this.NewsletterManager.changeEmail(
  134. this.user,
  135. 'overleaf.squirrel@example.com'
  136. )
  137. ).to.be.rejected
  138. expect(this.mailchimp.delete).to.have.been.calledWith(
  139. `/lists/list_id/members/${this.emailHash}`
  140. )
  141. })
  142. it('does not reject on non-fatal error ', async function() {
  143. const nonFatalError = new Error('merge fields were invalid')
  144. this.mailchimp.patch.rejects(nonFatalError)
  145. await expect(
  146. this.NewsletterManager.changeEmail(
  147. this.user,
  148. 'overleaf.squirrel@example.com'
  149. )
  150. ).to.be.fulfilled
  151. })
  152. it('rejects on any other error', async function() {
  153. const fatalError = new Error('fatal error')
  154. this.mailchimp.patch.rejects(fatalError)
  155. await expect(
  156. this.NewsletterManager.changeEmail(
  157. this.user,
  158. 'overleaf.squirrel@example.com'
  159. )
  160. ).to.be.rejected
  161. })
  162. })
  163. })