account-info-section.test.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import { expect } from 'chai'
  2. import { fireEvent, screen, render } from '@testing-library/react'
  3. import fetchMock from 'fetch-mock'
  4. import AccountInfoSection from '../../../../../frontend/js/features/settings/components/account-info-section'
  5. import { UserProvider } from '../../../../../frontend/js/shared/context/user-context'
  6. import getMeta from '@/utils/meta'
  7. function renderSectionWithUserProvider() {
  8. render(<AccountInfoSection />, {
  9. wrapper: ({ children }) => <UserProvider>{children}</UserProvider>,
  10. })
  11. }
  12. describe('<AccountInfoSection />', function () {
  13. beforeEach(function () {
  14. window.metaAttributesCache.set('ol-user', {
  15. email: 'sherlock@holmes.co.uk',
  16. first_name: 'Sherlock',
  17. last_name: 'Holmes',
  18. })
  19. Object.assign(getMeta('ol-ExposedSettings'), {
  20. hasAffiliationsFeature: false,
  21. })
  22. window.metaAttributesCache.set(
  23. 'ol-isExternalAuthenticationSystemUsed',
  24. false
  25. )
  26. window.metaAttributesCache.set('ol-shouldAllowEditingDetails', true)
  27. })
  28. afterEach(function () {
  29. fetchMock.removeRoutes().clearHistory()
  30. })
  31. it('submits all inputs', async function () {
  32. const updateMock = fetchMock.post('/user/settings', 200)
  33. renderSectionWithUserProvider()
  34. fireEvent.change(screen.getByLabelText('Email'), {
  35. target: { value: 'john@watson.co.uk' },
  36. })
  37. fireEvent.change(screen.getByLabelText('First name'), {
  38. target: { value: 'John' },
  39. })
  40. fireEvent.change(screen.getByLabelText('Last name'), {
  41. target: { value: 'Watson' },
  42. })
  43. fireEvent.click(
  44. screen.getByRole('button', {
  45. name: 'Update account info',
  46. })
  47. )
  48. expect(updateMock.callHistory.called()).to.be.true
  49. expect(
  50. JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string)
  51. ).to.deep.equal({
  52. email: 'john@watson.co.uk',
  53. first_name: 'John',
  54. last_name: 'Watson',
  55. })
  56. })
  57. it('disables button on invalid email', async function () {
  58. const updateMock = fetchMock.post('/user/settings', 200)
  59. renderSectionWithUserProvider()
  60. fireEvent.change(screen.getByLabelText('Email'), {
  61. target: { value: 'john' },
  62. })
  63. const button = screen.getByRole('button', {
  64. name: 'Update account info',
  65. }) as HTMLButtonElement
  66. expect(button.disabled).to.be.true
  67. fireEvent.click(button)
  68. expect(updateMock.callHistory.called()).to.be.false
  69. })
  70. it('shows inflight state and success message', async function () {
  71. let finishUpdateCall: (value: any) => void = () => {}
  72. fetchMock.post(
  73. '/user/settings',
  74. new Promise(resolve => (finishUpdateCall = resolve))
  75. )
  76. renderSectionWithUserProvider()
  77. fireEvent.click(
  78. screen.getByRole('button', {
  79. name: /update/i,
  80. })
  81. )
  82. await screen.findByRole('button', { name: /saving/i })
  83. finishUpdateCall(200)
  84. await screen.findByRole('button', {
  85. name: /update/i,
  86. })
  87. screen.getByText('Thanks, your settings have been updated.')
  88. })
  89. it('shows server error', async function () {
  90. fetchMock.post('/user/settings', 500)
  91. renderSectionWithUserProvider()
  92. fireEvent.click(
  93. screen.getByRole('button', {
  94. name: /update/i,
  95. })
  96. )
  97. await screen.findByText('Something went wrong. Please try again.')
  98. })
  99. it('shows invalid error', async function () {
  100. fetchMock.post('/user/settings', 400)
  101. renderSectionWithUserProvider()
  102. fireEvent.click(
  103. screen.getByRole('button', {
  104. name: /update/i,
  105. })
  106. )
  107. await screen.findByText(
  108. 'Invalid Request. Please correct the data and try again.'
  109. )
  110. })
  111. it('shows conflict error', async function () {
  112. fetchMock.post('/user/settings', {
  113. status: 409,
  114. body: {
  115. message:
  116. 'This email address is already associated with a different Overleaf account.',
  117. },
  118. })
  119. renderSectionWithUserProvider()
  120. fireEvent.click(
  121. screen.getByRole('button', {
  122. name: /update/i,
  123. })
  124. )
  125. await screen.findByText(
  126. 'This email address is already associated with a different Overleaf account.'
  127. )
  128. })
  129. it('hides email input', async function () {
  130. Object.assign(getMeta('ol-ExposedSettings'), {
  131. hasAffiliationsFeature: true,
  132. })
  133. const updateMock = fetchMock.post('/user/settings', 200)
  134. renderSectionWithUserProvider()
  135. expect(screen.queryByLabelText('Email')).to.not.exist
  136. fireEvent.click(
  137. screen.getByRole('button', {
  138. name: /update/i,
  139. })
  140. )
  141. expect(
  142. JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string)
  143. ).to.deep.equal({
  144. first_name: 'Sherlock',
  145. last_name: 'Holmes',
  146. })
  147. })
  148. it('disables email input', async function () {
  149. window.metaAttributesCache.set(
  150. 'ol-isExternalAuthenticationSystemUsed',
  151. true
  152. )
  153. const updateMock = fetchMock.post('/user/settings', 200)
  154. renderSectionWithUserProvider()
  155. expect(screen.getByLabelText('Email')).to.have.property('readOnly', true)
  156. expect(screen.getByLabelText('First name')).to.have.property(
  157. 'readOnly',
  158. false
  159. )
  160. expect(screen.getByLabelText('Last name')).to.have.property(
  161. 'readOnly',
  162. false
  163. )
  164. fireEvent.click(
  165. screen.getByRole('button', {
  166. name: /update account info/i,
  167. })
  168. )
  169. expect(
  170. JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string)
  171. ).to.deep.equal({
  172. first_name: 'Sherlock',
  173. last_name: 'Holmes',
  174. })
  175. })
  176. it('disables names input', async function () {
  177. window.metaAttributesCache.set('ol-shouldAllowEditingDetails', false)
  178. const updateMock = fetchMock.post('/user/settings', 200)
  179. renderSectionWithUserProvider()
  180. expect(screen.getByLabelText('Email')).to.have.property('readOnly', false)
  181. expect(screen.getByLabelText('First name')).to.have.property(
  182. 'readOnly',
  183. true
  184. )
  185. expect(screen.getByLabelText('Last name')).to.have.property(
  186. 'readOnly',
  187. true
  188. )
  189. fireEvent.click(
  190. screen.getByRole('button', {
  191. name: /update/i,
  192. })
  193. )
  194. expect(
  195. JSON.parse(updateMock.callHistory.calls().at(-1)?.options.body as string)
  196. ).to.deep.equal({
  197. email: 'sherlock@holmes.co.uk',
  198. })
  199. })
  200. })