UserEmailsConfirmationHandlerTests.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. no-unused-vars,
  5. */
  6. // TODO: This file was created by bulk-decaffeinate.
  7. // Fix any style issues and re-enable lint.
  8. /*
  9. * decaffeinate suggestions:
  10. * DS102: Remove unnecessary code created because of implicit returns
  11. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  12. */
  13. const SandboxedModule = require('sandboxed-module')
  14. const assert = require('assert')
  15. const path = require('path')
  16. const sinon = require('sinon')
  17. const modulePath = path.join(
  18. __dirname,
  19. '../../../../app/src/Features/User/UserEmailsConfirmationHandler'
  20. )
  21. const { expect } = require('chai')
  22. const Errors = require('../../../../app/src/Features/Errors/Errors')
  23. const EmailHelper = require('../../../../app/src/Features/Helpers/EmailHelper')
  24. describe('UserEmailsConfirmationHandler', function () {
  25. beforeEach(function () {
  26. this.UserEmailsConfirmationHandler = SandboxedModule.require(modulePath, {
  27. requires: {
  28. '@overleaf/settings': (this.settings = {
  29. siteUrl: 'https://emails.example.com',
  30. }),
  31. '../Security/OneTimeTokenHandler': (this.OneTimeTokenHandler = {}),
  32. './UserUpdater': (this.UserUpdater = {}),
  33. './UserGetter': (this.UserGetter = {
  34. getUser: sinon.stub().yields(null, this.mockUser),
  35. }),
  36. '../Email/EmailHandler': (this.EmailHandler = {}),
  37. '../Helpers/EmailHelper': EmailHelper,
  38. },
  39. })
  40. this.mockUser = {
  41. _id: 'mock-user-id',
  42. email: 'mock@example.com',
  43. emails: [{ email: 'mock@example.com' }],
  44. }
  45. this.user_id = this.mockUser._id
  46. this.email = this.mockUser.email
  47. return (this.callback = sinon.stub())
  48. })
  49. describe('sendConfirmationEmail', function () {
  50. beforeEach(function () {
  51. this.OneTimeTokenHandler.getNewToken = sinon
  52. .stub()
  53. .yields(null, (this.token = 'new-token'))
  54. return (this.EmailHandler.sendEmail = sinon.stub().yields())
  55. })
  56. describe('successfully', function () {
  57. beforeEach(function () {
  58. return this.UserEmailsConfirmationHandler.sendConfirmationEmail(
  59. this.user_id,
  60. this.email,
  61. this.callback
  62. )
  63. })
  64. it('should generate a token for the user which references their id and email', function () {
  65. return this.OneTimeTokenHandler.getNewToken
  66. .calledWith(
  67. 'email_confirmation',
  68. { user_id: this.user_id, email: this.email },
  69. { expiresIn: 90 * 24 * 60 * 60 }
  70. )
  71. .should.equal(true)
  72. })
  73. it('should send an email to the user', function () {
  74. return this.EmailHandler.sendEmail
  75. .calledWith('confirmEmail', {
  76. to: this.email,
  77. confirmEmailUrl:
  78. 'https://emails.example.com/user/emails/confirm?token=new-token',
  79. sendingUser_id: this.user_id,
  80. })
  81. .should.equal(true)
  82. })
  83. it('should call the callback', function () {
  84. return this.callback.called.should.equal(true)
  85. })
  86. })
  87. describe('with invalid email', function () {
  88. beforeEach(function () {
  89. return this.UserEmailsConfirmationHandler.sendConfirmationEmail(
  90. this.user_id,
  91. '!"£$%^&*()',
  92. this.callback
  93. )
  94. })
  95. it('should return an error', function () {
  96. return this.callback
  97. .calledWith(sinon.match.instanceOf(Error))
  98. .should.equal(true)
  99. })
  100. })
  101. describe('a custom template', function () {
  102. beforeEach(function () {
  103. return this.UserEmailsConfirmationHandler.sendConfirmationEmail(
  104. this.user_id,
  105. this.email,
  106. 'myCustomTemplate',
  107. this.callback
  108. )
  109. })
  110. it('should send an email with the given template', function () {
  111. return this.EmailHandler.sendEmail
  112. .calledWith('myCustomTemplate')
  113. .should.equal(true)
  114. })
  115. })
  116. })
  117. describe('confirmEmailFromToken', function () {
  118. beforeEach(function () {
  119. this.OneTimeTokenHandler.getValueFromTokenAndExpire = sinon
  120. .stub()
  121. .yields(null, { user_id: this.user_id, email: this.email })
  122. return (this.UserUpdater.confirmEmail = sinon.stub().yields())
  123. })
  124. describe('successfully', function () {
  125. beforeEach(function () {
  126. return this.UserEmailsConfirmationHandler.confirmEmailFromToken(
  127. (this.token = 'mock-token'),
  128. this.callback
  129. )
  130. })
  131. it('should call getValueFromTokenAndExpire', function () {
  132. return this.OneTimeTokenHandler.getValueFromTokenAndExpire
  133. .calledWith('email_confirmation', this.token)
  134. .should.equal(true)
  135. })
  136. it('should confirm the email of the user_id', function () {
  137. return this.UserUpdater.confirmEmail
  138. .calledWith(this.user_id, this.email)
  139. .should.equal(true)
  140. })
  141. it('should call the callback', function () {
  142. return this.callback.called.should.equal(true)
  143. })
  144. })
  145. describe('with an expired token', function () {
  146. beforeEach(function () {
  147. this.OneTimeTokenHandler.getValueFromTokenAndExpire = sinon
  148. .stub()
  149. .yields(null, null)
  150. return this.UserEmailsConfirmationHandler.confirmEmailFromToken(
  151. (this.token = 'mock-token'),
  152. this.callback
  153. )
  154. })
  155. it('should call the callback with a NotFoundError', function () {
  156. return this.callback
  157. .calledWith(sinon.match.instanceOf(Errors.NotFoundError))
  158. .should.equal(true)
  159. })
  160. })
  161. describe('with no user_id in the token', function () {
  162. beforeEach(function () {
  163. this.OneTimeTokenHandler.getValueFromTokenAndExpire = sinon
  164. .stub()
  165. .yields(null, { email: this.email })
  166. return this.UserEmailsConfirmationHandler.confirmEmailFromToken(
  167. (this.token = 'mock-token'),
  168. this.callback
  169. )
  170. })
  171. it('should call the callback with a NotFoundError', function () {
  172. return this.callback
  173. .calledWith(sinon.match.instanceOf(Errors.NotFoundError))
  174. .should.equal(true)
  175. })
  176. })
  177. describe('with no email in the token', function () {
  178. beforeEach(function () {
  179. this.OneTimeTokenHandler.getValueFromTokenAndExpire = sinon
  180. .stub()
  181. .yields(null, { user_id: this.user_id })
  182. return this.UserEmailsConfirmationHandler.confirmEmailFromToken(
  183. (this.token = 'mock-token'),
  184. this.callback
  185. )
  186. })
  187. it('should call the callback with a NotFoundError', function () {
  188. return this.callback
  189. .calledWith(sinon.match.instanceOf(Errors.NotFoundError))
  190. .should.equal(true)
  191. })
  192. })
  193. describe('with no user found', function () {
  194. beforeEach(function () {
  195. this.UserGetter.getUser.yields(null, null)
  196. return this.UserEmailsConfirmationHandler.confirmEmailFromToken(
  197. (this.token = 'mock-token'),
  198. this.callback
  199. )
  200. })
  201. it('should call the callback with a NotFoundError', function () {
  202. return this.callback
  203. .calledWith(sinon.match.instanceOf(Errors.NotFoundError))
  204. .should.equal(true)
  205. })
  206. })
  207. describe('with secondary email missing on user', function () {
  208. beforeEach(function () {
  209. this.OneTimeTokenHandler.getValueFromTokenAndExpire = sinon
  210. .stub()
  211. .yields(null, { user_id: this.user_id, email: 'deleted@email.com' })
  212. return this.UserEmailsConfirmationHandler.confirmEmailFromToken(
  213. (this.token = 'mock-token'),
  214. this.callback
  215. )
  216. })
  217. it('should call the callback with a NotFoundError', function () {
  218. return this.callback
  219. .calledWith(sinon.match.instanceOf(Errors.NotFoundError))
  220. .should.equal(true)
  221. })
  222. })
  223. })
  224. })