emails-row.test.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import { render, screen } from '@testing-library/react'
  2. import { expect } from 'chai'
  3. import fetchMock from 'fetch-mock'
  4. import { cloneDeep } from 'lodash'
  5. import EmailsRow from '../../../../../../frontend/js/features/settings/components/emails/row'
  6. import {
  7. professionalUserData,
  8. unconfirmedUserData,
  9. } from '../../fixtures/test-user-email-data'
  10. import { UserEmailData } from '../../../../../../types/user-email'
  11. import { UserEmailsProvider } from '../../../../../../frontend/js/features/settings/context/user-email-context'
  12. import { Affiliation } from '../../../../../../types/affiliation'
  13. import getMeta from '@/utils/meta'
  14. function renderEmailsRow(data: UserEmailData) {
  15. return render(
  16. <UserEmailsProvider>
  17. <EmailsRow userEmailData={data} />
  18. </UserEmailsProvider>
  19. )
  20. }
  21. function getByTextContent(text: string) {
  22. return screen.getAllByText(
  23. (content, node) =>
  24. content === text || node?.children[0]?.textContent === text
  25. )
  26. }
  27. describe('<EmailsRow/>', function () {
  28. beforeEach(function () {
  29. Object.assign(getMeta('ol-ExposedSettings'), {
  30. samlInitPath: '/saml',
  31. hasSamlBeta: true,
  32. })
  33. fetchMock.get('/user/emails?ensureAffiliation=true', [])
  34. })
  35. afterEach(function () {
  36. fetchMock.removeRoutes().clearHistory()
  37. })
  38. describe('with unaffiliated email data', function () {
  39. it('renders email info', function () {
  40. renderEmailsRow(unconfirmedUserData)
  41. screen.getByText('baz@overleaf.com')
  42. })
  43. it('renders actions', function () {
  44. renderEmailsRow(unconfirmedUserData)
  45. screen.getByRole('button', { name: 'Make primary' })
  46. })
  47. })
  48. describe('with affiliated email data', function () {
  49. it('renders email info', function () {
  50. renderEmailsRow(professionalUserData)
  51. screen.getByText('foo@overleaf.com')
  52. screen.getByText('Primary')
  53. })
  54. it('renders actions', function () {
  55. renderEmailsRow(professionalUserData)
  56. screen.getByRole('button', { name: 'Remove' })
  57. })
  58. it('renders institution info', function () {
  59. renderEmailsRow(professionalUserData)
  60. screen.getByText('Overleaf')
  61. screen.getByText('Reader, Art History')
  62. })
  63. })
  64. describe('with email data affiliated to an institution with SSO available', function () {
  65. let affiliatedEmail: UserEmailData & { affiliation: Affiliation }
  66. beforeEach(function () {
  67. window.metaAttributesCache.get('ol-ExposedSettings').hasSamlFeature = true
  68. // make sure the institution has SSO available
  69. affiliatedEmail = cloneDeep(professionalUserData)
  70. affiliatedEmail.affiliation.institution.confirmed = true
  71. affiliatedEmail.affiliation.institution.isUniversity = true
  72. affiliatedEmail.affiliation.institution.ssoEnabled = true
  73. })
  74. describe('when the email is not yet linked to the institution', function () {
  75. beforeEach(async function () {
  76. fetchMock.removeRoutes().clearHistory()
  77. fetchMock.get(/\/user\/emails/, [affiliatedEmail, unconfirmedUserData])
  78. await fetchMock.callHistory.flush(true)
  79. })
  80. it('prompts the user to link to their institutional account', function () {
  81. renderEmailsRow(affiliatedEmail)
  82. getByTextContent(
  83. 'You can now link your Overleaf account to your Overleaf institutional account.'
  84. )
  85. screen.getByRole('button', { name: 'Link accounts' })
  86. })
  87. })
  88. describe('when the email is already linked to the institution', function () {
  89. beforeEach(async function () {
  90. affiliatedEmail.samlProviderId = '1'
  91. fetchMock.removeRoutes().clearHistory()
  92. fetchMock.get(/\/user\/emails/, [affiliatedEmail, unconfirmedUserData])
  93. await fetchMock.callHistory.flush(true)
  94. })
  95. it('prompts the user to login using their institutional account', function () {
  96. renderEmailsRow(affiliatedEmail)
  97. getByTextContent(
  98. 'You can log in to Overleaf through your Overleaf institutional login.'
  99. )
  100. expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be
  101. .null
  102. })
  103. })
  104. describe('and domain capture is also on for group and Commons SSO also enabled', function () {
  105. // scenario of a Commons account migrating to a group account
  106. let affiliatedEmailWithDomainCaptureAndCommons: UserEmailData & {
  107. affiliation: Affiliation
  108. }
  109. beforeEach(async function () {
  110. fetchMock.removeRoutes().clearHistory()
  111. affiliatedEmailWithDomainCaptureAndCommons = cloneDeep(affiliatedEmail)
  112. affiliatedEmailWithDomainCaptureAndCommons.affiliation.group = {
  113. _id: 'grou123',
  114. domainCaptureEnabled: true,
  115. managedUsersEnabled: true,
  116. }
  117. await fetchMock.callHistory.flush(true)
  118. })
  119. it('does not prompt the user to link to their institutional account', function () {
  120. renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons)
  121. expect(() =>
  122. getByTextContent(
  123. 'You can now link your Overleaf account to your Overleaf institutional account.'
  124. )
  125. ).to.throw('Unable to find an element with the text')
  126. expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be
  127. .null
  128. })
  129. it('still shows users can log in via Commons SSO if already linked', function () {
  130. affiliatedEmailWithDomainCaptureAndCommons.samlProviderId = '1'
  131. renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons)
  132. getByTextContent(
  133. 'You can log in to Overleaf through your Overleaf institutional login.'
  134. )
  135. expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be
  136. .null
  137. })
  138. })
  139. })
  140. })