emails-section-actions.test.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import {
  2. render,
  3. screen,
  4. waitForElementToBeRemoved,
  5. fireEvent,
  6. } from '@testing-library/react'
  7. import userEvent from '@testing-library/user-event'
  8. import { expect } from 'chai'
  9. import { UserEmailData } from '../../../../../../types/user-email'
  10. import fetchMock from 'fetch-mock'
  11. import EmailsSection from '../../../../../../frontend/js/features/settings/components/emails-section'
  12. import { Institution } from '../../../../../../types/institution'
  13. import { Affiliation } from '../../../../../../types/affiliation'
  14. const userEmailData: UserEmailData = {
  15. confirmedAt: '2022-03-10T10:59:44.139Z',
  16. email: 'bar@overleaf.com',
  17. default: false,
  18. }
  19. const userEmailData2: UserEmailData = {
  20. affiliation: {
  21. inReconfirmNotificationPeriod: false,
  22. institution: {
  23. confirmed: false,
  24. } as Institution,
  25. } as Affiliation,
  26. confirmedAt: '2022-03-10T10:59:44.139Z',
  27. email: 'bar@overleaf.com',
  28. default: false,
  29. }
  30. describe('email actions - make primary', function () {
  31. beforeEach(function () {
  32. window.metaAttributesCache.set('ol-ExposedSettings', {
  33. hasAffiliationsFeature: true,
  34. })
  35. fetchMock.reset()
  36. })
  37. afterEach(function () {
  38. window.metaAttributesCache = new Map()
  39. fetchMock.reset()
  40. })
  41. describe('disabled `make primary` button', function () {
  42. it('when renders with unconfirmed email', async function () {
  43. const userEmailDataCopy = { ...userEmailData2 }
  44. const { confirmedAt: _, ...userEmailData } = userEmailDataCopy
  45. fetchMock.get('/user/emails?ensureAffiliation=true', [userEmailData])
  46. render(<EmailsSection />)
  47. const button = (await screen.findByRole('button', {
  48. name: /make primary/i,
  49. })) as HTMLButtonElement
  50. expect(button.disabled).to.be.true
  51. })
  52. it('when renders with email in reconfirmation period', async function () {
  53. const userEmailDataCopy = {
  54. ...userEmailData2,
  55. affiliation: {
  56. ...userEmailData2.affiliation,
  57. inReconfirmNotificationPeriod: true,
  58. },
  59. }
  60. fetchMock.get('/user/emails?ensureAffiliation=true', [userEmailDataCopy])
  61. render(<EmailsSection />)
  62. const button = (await screen.findByRole('button', {
  63. name: /make primary/i,
  64. })) as HTMLButtonElement
  65. expect(button.disabled).to.be.true
  66. })
  67. })
  68. describe('button tooltips', function () {
  69. it('when the email is in reconfirmation period', async function () {
  70. const userEmailDataCopy = {
  71. ...userEmailData2,
  72. affiliation: {
  73. ...userEmailData2.affiliation,
  74. inReconfirmNotificationPeriod: true,
  75. },
  76. }
  77. fetchMock.get('/user/emails?ensureAffiliation=true', [userEmailDataCopy])
  78. render(<EmailsSection />)
  79. const button = (await screen.findByRole('button', {
  80. name: /make primary/i,
  81. })) as HTMLButtonElement
  82. userEvent.hover(button.parentElement)
  83. screen.getByText(
  84. /Please confirm your affiliation before making this the primary/i
  85. )
  86. })
  87. it('when the email is confirmed', async function () {
  88. const userEmailDataCopy = { ...userEmailData2 }
  89. fetchMock.get('/user/emails?ensureAffiliation=true', [userEmailDataCopy])
  90. render(<EmailsSection />)
  91. const button = (await screen.findByRole('button', {
  92. name: /make primary/i,
  93. })) as HTMLButtonElement
  94. userEvent.hover(button.parentElement)
  95. screen.getByText('Make this the primary email, used to log in', {
  96. exact: false,
  97. })
  98. })
  99. it('when not linked to institution', async function () {
  100. window.metaAttributesCache.set('ol-ExposedSettings', {
  101. hasAffiliationsFeature: true,
  102. hasSamlFeature: true,
  103. })
  104. const userEmailDataCopy = { ...userEmailData2 }
  105. const { confirmedAt: _, ...userEmailData } = userEmailDataCopy
  106. const userEmailDataCopy1 = { ...userEmailData }
  107. const userEmailDataCopy2 = {
  108. ...userEmailData,
  109. email: 'baz@overleaf.com',
  110. affiliation: {
  111. ...userEmailData.affiliation,
  112. institution: {
  113. ...userEmailData.affiliation.institution,
  114. id: 123,
  115. confirmed: true,
  116. isUniversity: true,
  117. ssoEnabled: true,
  118. },
  119. },
  120. }
  121. fetchMock.get('/user/emails?ensureAffiliation=true', [
  122. userEmailDataCopy1,
  123. userEmailDataCopy2,
  124. ])
  125. render(<EmailsSection />)
  126. const buttons = (await screen.findAllByRole('button', {
  127. name: /make primary/i,
  128. })) as HTMLButtonElement[]
  129. userEvent.hover(buttons[1].parentElement)
  130. screen.getByText(
  131. 'Please confirm your email by linking to your institutional account before making it the primary email',
  132. {
  133. exact: false,
  134. }
  135. )
  136. })
  137. })
  138. it('shows loader when making email primary and removes button', async function () {
  139. fetchMock
  140. .get('/user/emails?ensureAffiliation=true', [userEmailData])
  141. .post('/user/emails/default', 200)
  142. const userEmailDataCopy = { ...userEmailData }
  143. render(<EmailsSection />)
  144. const button = await screen.findByRole('button', { name: /make primary/i })
  145. fireEvent.click(button)
  146. expect(screen.queryByRole('button', { name: /make primary/i })).to.be.null
  147. userEmailDataCopy.default = true
  148. await waitForElementToBeRemoved(() =>
  149. screen.getByRole('button', { name: /sending/i })
  150. )
  151. expect(
  152. screen.queryByText(/an error has occurred while performing your request/i)
  153. ).to.be.null
  154. expect(screen.queryByRole('button', { name: /make primary/i })).to.be.null
  155. })
  156. it('shows error when making email primary', async function () {
  157. fetchMock
  158. .get('/user/emails?ensureAffiliation=true', [userEmailData])
  159. .post('/user/emails/default', 503)
  160. render(<EmailsSection />)
  161. const button = await screen.findByRole('button', { name: /make primary/i })
  162. fireEvent.click(button)
  163. await waitForElementToBeRemoved(() =>
  164. screen.getByRole('button', { name: /sending/i })
  165. )
  166. screen.getByText(/sorry, something went wrong/i)
  167. screen.getByRole('button', { name: /make primary/i })
  168. })
  169. })
  170. describe('email actions - delete', function () {
  171. beforeEach(function () {
  172. window.metaAttributesCache.set('ol-ExposedSettings', {
  173. hasAffiliationsFeature: true,
  174. })
  175. fetchMock.reset()
  176. })
  177. afterEach(function () {
  178. window.metaAttributesCache = new Map()
  179. fetchMock.reset()
  180. })
  181. it('shows loader when deleting and removes the row', async function () {
  182. fetchMock
  183. .get('/user/emails?ensureAffiliation=true', [userEmailData])
  184. .post('/user/emails/delete', 200)
  185. render(<EmailsSection />)
  186. const button = await screen.findByRole('button', { name: /remove/i })
  187. fireEvent.click(button)
  188. await waitForElementToBeRemoved(() =>
  189. screen.queryByText(userEmailData.email)
  190. )
  191. })
  192. it('shows error when deleting', async function () {
  193. fetchMock
  194. .get('/user/emails?ensureAffiliation=true', [userEmailData])
  195. .post('/user/emails/delete', 503)
  196. render(<EmailsSection />)
  197. const button = await screen.findByRole('button', { name: /remove/i })
  198. fireEvent.click(button)
  199. await screen.queryByText(/sorry, something went wrong/i)
  200. screen.getByRole('button', { name: /remove/i })
  201. })
  202. })