UserCreatorTests.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. const SandboxedModule = require('sandboxed-module')
  2. const sinon = require('sinon')
  3. const { assert } = require('chai')
  4. const modulePath = '../../../../app/src/Features/User/UserCreator.js'
  5. describe('UserCreator', function () {
  6. beforeEach(function () {
  7. const self = this
  8. this.user = { _id: '12390i', ace: {} }
  9. this.user.save = sinon.stub().resolves(self.user)
  10. this.UserModel = class Project {
  11. constructor() {
  12. return self.user
  13. }
  14. }
  15. this.UserCreator = SandboxedModule.require(modulePath, {
  16. requires: {
  17. '../../models/User': {
  18. User: this.UserModel,
  19. },
  20. '../../infrastructure/Features': (this.Features = {
  21. hasFeature: sinon.stub().returns(false),
  22. }),
  23. './UserDeleter': (this.UserDeleter = {
  24. promises: {
  25. deleteNewUser: sinon.stub().resolves(),
  26. },
  27. }),
  28. './UserGetter': (this.UserGetter = {
  29. promises: {
  30. getUser: sinon.stub().resolves(this.user),
  31. },
  32. }),
  33. './UserUpdater': (this.UserUpdater = {
  34. promises: {
  35. addAffiliationForNewUser: sinon.stub().resolves({
  36. matchedCount: 1,
  37. modifiedCount: 1,
  38. acknowledged: true,
  39. }),
  40. updateUser: sinon.stub().resolves(),
  41. },
  42. }),
  43. '../Analytics/AnalyticsManager': (this.Analytics = {
  44. recordEventForUserInBackground: sinon.stub(),
  45. setUserPropertyForUser: sinon.stub(),
  46. }),
  47. '../SplitTests/SplitTestHandler': (this.SplitTestHandler = {
  48. promises: {
  49. getAssignmentForUser: sinon.stub().resolves({ variant: 'active' }),
  50. },
  51. }),
  52. './UserOnboardingEmailManager': (this.UserOnboardingEmailManager = {
  53. scheduleOnboardingEmail: sinon.stub(),
  54. }),
  55. './UserPostRegistrationAnalyticsManager':
  56. (this.UserPostRegistrationAnalyticsManager = {
  57. schedulePostRegistrationAnalytics: sinon.stub(),
  58. }),
  59. },
  60. })
  61. this.email = 'bob.oswald@gmail.com'
  62. })
  63. describe('createNewUser', function () {
  64. describe('with callbacks', function () {
  65. it('should take the opts and put them in the model', async function () {
  66. const user = await this.UserCreator.promises.createNewUser({
  67. email: this.email,
  68. holdingAccount: true,
  69. })
  70. assert.equal(user.email, this.email)
  71. assert.equal(user.holdingAccount, true)
  72. assert.equal(user.first_name, 'bob.oswald')
  73. })
  74. it('should use the start of the email if the first name is empty string', async function () {
  75. const user = await this.UserCreator.promises.createNewUser({
  76. email: this.email,
  77. holdingAccount: true,
  78. first_name: '',
  79. })
  80. assert.equal(user.email, this.email)
  81. assert.equal(user.holdingAccount, true)
  82. assert.equal(user.first_name, 'bob.oswald')
  83. })
  84. it('should use the first name if passed', async function () {
  85. const user = await this.UserCreator.promises.createNewUser({
  86. email: this.email,
  87. holdingAccount: true,
  88. first_name: 'fiiirstname',
  89. })
  90. assert.equal(user.email, this.email)
  91. assert.equal(user.holdingAccount, true)
  92. assert.equal(user.first_name, 'fiiirstname')
  93. })
  94. it('should use the last name if passed', async function () {
  95. const user = await this.UserCreator.promises.createNewUser({
  96. email: this.email,
  97. holdingAccount: true,
  98. last_name: 'lastNammmmeee',
  99. })
  100. assert.equal(user.email, this.email)
  101. assert.equal(user.holdingAccount, true)
  102. assert.equal(user.last_name, 'lastNammmmeee')
  103. })
  104. it('should set emails attribute', async function () {
  105. const user = await this.UserCreator.promises.createNewUser({
  106. email: this.email,
  107. })
  108. user.email.should.equal(this.email)
  109. user.emails.length.should.equal(1)
  110. user.emails[0].email.should.equal(this.email)
  111. user.emails[0].createdAt.should.be.a('date')
  112. user.emails[0].reversedHostname.should.equal('moc.liamg')
  113. })
  114. describe('with affiliations feature', function () {
  115. let attributes, user
  116. beforeEach(function () {
  117. attributes = { email: this.email }
  118. this.Features.hasFeature = sinon
  119. .stub()
  120. .withArgs('affiliations')
  121. .returns(true)
  122. })
  123. describe('when v1 affiliations API does not return an error', function () {
  124. beforeEach(async function () {
  125. user = await this.UserCreator.promises.createNewUser(attributes)
  126. })
  127. it('should flag that affiliation is unchecked', function () {
  128. user.emails[0].affiliationUnchecked.should.equal(true)
  129. })
  130. it('should try to add affiliation to v1', function () {
  131. sinon.assert.calledOnce(
  132. this.UserUpdater.promises.addAffiliationForNewUser
  133. )
  134. sinon.assert.calledWithMatch(
  135. this.UserUpdater.promises.addAffiliationForNewUser,
  136. user._id,
  137. this.email
  138. )
  139. })
  140. it('should query for updated user data', function () {
  141. sinon.assert.calledOnce(this.UserGetter.promises.getUser)
  142. })
  143. })
  144. describe('when v1 affiliations API does return an error', function () {
  145. beforeEach(async function () {
  146. this.UserUpdater.promises.addAffiliationForNewUser.rejects()
  147. user = await this.UserCreator.promises.createNewUser(attributes)
  148. })
  149. it('should flag that affiliation is unchecked', function () {
  150. user.emails[0].affiliationUnchecked.should.equal(true)
  151. })
  152. it('should try to add affiliation to v1', function () {
  153. sinon.assert.calledOnce(
  154. this.UserUpdater.promises.addAffiliationForNewUser
  155. )
  156. sinon.assert.calledWithMatch(
  157. this.UserUpdater.promises.addAffiliationForNewUser,
  158. user._id,
  159. this.email
  160. )
  161. })
  162. it('should not query for updated user data', function () {
  163. sinon.assert.notCalled(this.UserGetter.promises.getUser)
  164. })
  165. it('should log error', function () {
  166. sinon.assert.calledOnce(this.logger.error)
  167. })
  168. })
  169. describe('when v1 affiliations API returns an error and requireAffiliation=true', function () {
  170. beforeEach(async function () {
  171. this.UserUpdater.promises.addAffiliationForNewUser.rejects()
  172. user = await this.UserCreator.promises.createNewUser(attributes)
  173. })
  174. it('should flag that affiliation is unchecked', function () {
  175. user.emails[0].affiliationUnchecked.should.equal(true)
  176. })
  177. it('should try to add affiliation to v1', function () {
  178. sinon.assert.calledOnce(
  179. this.UserUpdater.promises.addAffiliationForNewUser
  180. )
  181. sinon.assert.calledWithMatch(
  182. this.UserUpdater.promises.addAffiliationForNewUser,
  183. user._id,
  184. this.email
  185. )
  186. })
  187. it('should not query for updated user data', function () {
  188. sinon.assert.notCalled(this.UserGetter.promises.getUser)
  189. })
  190. it('should log error', function () {
  191. sinon.assert.calledOnce(this.logger.error)
  192. })
  193. })
  194. })
  195. it('should not add affiliation when without affiliation feature', async function () {
  196. const attributes = { email: this.email }
  197. await this.UserCreator.promises.createNewUser(attributes)
  198. sinon.assert.notCalled(
  199. this.UserUpdater.promises.addAffiliationForNewUser
  200. )
  201. })
  202. })
  203. describe('with promises', function () {
  204. it('should take the opts and put them in the model', async function () {
  205. const opts = {
  206. email: this.email,
  207. holdingAccount: true,
  208. }
  209. const user = await this.UserCreator.promises.createNewUser(opts)
  210. assert.equal(user.email, this.email)
  211. assert.equal(user.holdingAccount, true)
  212. assert.equal(user.first_name, 'bob.oswald')
  213. })
  214. it('should add affiliation when with affiliation feature', async function () {
  215. this.Features.hasFeature = sinon
  216. .stub()
  217. .withArgs('affiliations')
  218. .returns(true)
  219. const attributes = { email: this.email }
  220. const user = await this.UserCreator.promises.createNewUser(attributes)
  221. sinon.assert.calledOnce(
  222. this.UserUpdater.promises.addAffiliationForNewUser
  223. )
  224. sinon.assert.calledWithMatch(
  225. this.UserUpdater.promises.addAffiliationForNewUser,
  226. user._id,
  227. this.email
  228. )
  229. })
  230. it('should not add affiliation when without affiliation feature', async function () {
  231. this.Features.hasFeature = sinon.stub().returns(false)
  232. const attributes = { email: this.email }
  233. await this.UserCreator.promises.createNewUser(attributes)
  234. sinon.assert.notCalled(
  235. this.UserUpdater.promises.addAffiliationForNewUser
  236. )
  237. })
  238. it('should include SAML provider ID with email', async function () {
  239. const attributes = {
  240. email: this.email,
  241. samlIdentifiers: [{ email: this.email, providerId: '1' }],
  242. }
  243. const user = await this.UserCreator.promises.createNewUser(attributes)
  244. assert.equal(user.emails[0].samlProviderId, '1')
  245. })
  246. it('should fire an analytics event and user property on registration', async function () {
  247. const user = await this.UserCreator.promises.createNewUser({
  248. email: this.email,
  249. })
  250. assert.equal(user.email, this.email)
  251. sinon.assert.calledWith(
  252. this.Analytics.recordEventForUserInBackground,
  253. user._id,
  254. 'user-registered'
  255. )
  256. sinon.assert.calledWith(
  257. this.Analytics.setUserPropertyForUser,
  258. user._id,
  259. 'created-at'
  260. )
  261. })
  262. it('should schedule post registration jobs on registration with saas feature', async function () {
  263. this.Features.hasFeature = sinon.stub().withArgs('saas').returns(true)
  264. const user = await this.UserCreator.promises.createNewUser({
  265. email: this.email,
  266. })
  267. assert.equal(user.email, this.email)
  268. sinon.assert.calledWith(
  269. this.UserOnboardingEmailManager.scheduleOnboardingEmail,
  270. user
  271. )
  272. sinon.assert.calledWith(
  273. this.UserPostRegistrationAnalyticsManager
  274. .schedulePostRegistrationAnalytics,
  275. user
  276. )
  277. })
  278. it('should not schedule post registration checks when without saas feature', async function () {
  279. const attributes = { email: this.email }
  280. await this.UserCreator.promises.createNewUser(attributes)
  281. sinon.assert.notCalled(
  282. this.UserOnboardingEmailManager.scheduleOnboardingEmail
  283. )
  284. sinon.assert.notCalled(
  285. this.UserPostRegistrationAnalyticsManager
  286. .schedulePostRegistrationAnalytics
  287. )
  288. })
  289. })
  290. })
  291. })