modal-form.test.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. import { expect } from 'chai'
  2. import sinon from 'sinon'
  3. import { fireEvent, screen, render, waitFor } from '@testing-library/react'
  4. import fetchMock, { FetchMockStatic } from 'fetch-mock'
  5. import LeaveModalForm from '../../../../../../frontend/js/features/settings/components/leave/modal-form'
  6. import * as useLocationModule from '../../../../../../frontend/js/shared/hooks/use-location'
  7. describe('<LeaveModalForm />', function () {
  8. beforeEach(function () {
  9. window.metaAttributesCache = new Map()
  10. window.metaAttributesCache.set('ol-usersEmail', 'foo@bar.com')
  11. window.metaAttributesCache.set('ol-ExposedSettings', { isOverleaf: true })
  12. })
  13. afterEach(function () {
  14. window.metaAttributesCache = new Map()
  15. fetchMock.reset()
  16. })
  17. it('validates form', async function () {
  18. const setIsFormValid = sinon.stub()
  19. render(
  20. <LeaveModalForm
  21. setInFlight={() => {}}
  22. isFormValid={false}
  23. setIsFormValid={setIsFormValid}
  24. />
  25. )
  26. const emailInput = screen.getByLabelText('Email')
  27. fireEvent.change(emailInput, { target: { value: 'FOO@bar.com' } })
  28. const passwordInput = screen.getByLabelText('Password')
  29. fireEvent.change(passwordInput, { target: { value: 'foobar' } })
  30. const checkbox = screen.getByLabelText(
  31. 'I understand this will delete all projects in my Overleaf account with email address foo@bar.com'
  32. )
  33. fireEvent.click(checkbox)
  34. const setIsFormValidCalls = setIsFormValid.getCalls()
  35. const lastSetIsFormValidCall = setIsFormValidCalls.pop()
  36. expect(lastSetIsFormValidCall!.args[0]).to.be.true
  37. for (const setIsFormValidCall of setIsFormValidCalls) {
  38. expect(setIsFormValidCall.args[0]).to.be.false
  39. }
  40. })
  41. describe('submits', async function () {
  42. let setInFlight: sinon.SinonStub
  43. let setIsFormValid: sinon.SinonStub
  44. let deleteMock: FetchMockStatic
  45. let assignStub: sinon.SinonStub
  46. beforeEach(function () {
  47. setInFlight = sinon.stub()
  48. setIsFormValid = sinon.stub()
  49. deleteMock = fetchMock.post('/user/delete', 200)
  50. assignStub = sinon.stub()
  51. this.locationStub = sinon.stub(useLocationModule, 'useLocation').returns({
  52. assign: assignStub,
  53. reload: sinon.stub(),
  54. })
  55. window.metaAttributesCache.set('ol-ExposedSettings', { isOverleaf: true })
  56. })
  57. afterEach(function () {
  58. fetchMock.reset()
  59. this.locationStub.restore()
  60. })
  61. it('with valid form', async function () {
  62. render(
  63. <LeaveModalForm
  64. setInFlight={setInFlight}
  65. isFormValid
  66. setIsFormValid={setIsFormValid}
  67. />
  68. )
  69. fireEvent.submit(screen.getByLabelText('Email'))
  70. sinon.assert.calledOnce(setInFlight)
  71. sinon.assert.calledWithMatch(setInFlight, true)
  72. expect(deleteMock.called()).to.be.true
  73. await waitFor(() => {
  74. sinon.assert.calledTwice(setInFlight)
  75. sinon.assert.calledWithMatch(setInFlight, false)
  76. sinon.assert.calledOnce(assignStub)
  77. sinon.assert.calledWith(assignStub, '/')
  78. })
  79. })
  80. it('with invalid form', async function () {
  81. render(
  82. <LeaveModalForm
  83. setInFlight={setInFlight}
  84. isFormValid={false}
  85. setIsFormValid={setIsFormValid}
  86. />
  87. )
  88. fireEvent.submit(screen.getByLabelText('Email'))
  89. expect(deleteMock.called()).to.be.false
  90. sinon.assert.notCalled(setInFlight)
  91. })
  92. })
  93. it('handles credentials error without Saas tip', async function () {
  94. window.metaAttributesCache.set('ol-ExposedSettings', { isOverleaf: false })
  95. fetchMock.post('/user/delete', 403)
  96. render(
  97. <LeaveModalForm
  98. setInFlight={() => {}}
  99. isFormValid
  100. setIsFormValid={() => {}}
  101. />
  102. )
  103. fireEvent.submit(screen.getByLabelText('Email'))
  104. await waitFor(() => {
  105. screen.getByText(/Your email or password is incorrect. Please try again/)
  106. })
  107. expect(screen.queryByText(/If you cannot remember your password/)).to.not
  108. .exist
  109. })
  110. it('handles credentials error with Saas tip', async function () {
  111. fetchMock.post('/user/delete', 403)
  112. render(
  113. <LeaveModalForm
  114. setInFlight={() => {}}
  115. isFormValid
  116. setIsFormValid={() => {}}
  117. />
  118. )
  119. fireEvent.submit(screen.getByLabelText('Email'))
  120. await waitFor(() => {
  121. screen.getByText(/Your email or password is incorrect. Please try again/)
  122. })
  123. screen.getByText(/If you cannot remember your password/)
  124. const link = screen.getByRole('link', { name: 'reset your password' })
  125. expect(link.getAttribute('href')).to.equal('/user/password/reset')
  126. })
  127. it('handles subscription error', async function () {
  128. fetchMock.post('/user/delete', {
  129. status: 422,
  130. body: {
  131. error: 'SubscriptionAdminDeletionError',
  132. },
  133. })
  134. render(
  135. <LeaveModalForm
  136. setInFlight={() => {}}
  137. isFormValid
  138. setIsFormValid={() => {}}
  139. />
  140. )
  141. fireEvent.submit(screen.getByLabelText('Email'))
  142. await waitFor(() => {
  143. screen.getByText(
  144. 'You cannot delete your account while on a subscription. Please cancel your subscription and try again. If you keep seeing this message please contact us.'
  145. )
  146. })
  147. })
  148. it('handles generic error', async function () {
  149. fetchMock.post('/user/delete', 500)
  150. render(
  151. <LeaveModalForm
  152. setInFlight={() => {}}
  153. isFormValid
  154. setIsFormValid={() => {}}
  155. />
  156. )
  157. fireEvent.submit(screen.getByLabelText('Email'))
  158. await waitFor(() => {
  159. screen.getByText(
  160. 'Sorry, something went wrong deleting your account. Please try again in a minute.'
  161. )
  162. })
  163. })
  164. })