Files
overleaf-cep/services/web/test/frontend/features/settings/components/emails/emails-row.test.tsx
Jessica Lawshe ba13ccdb11 Merge pull request #33202 from overleaf/jel-domain-captured-by-group-settings-page
[Domain capture] Check `domainCapturedByGroup` for existing emails on user settings

GitOrigin-RevId: 5ac86b89969b186cce0cac410c2957e5aa1b9703
2026-05-12 08:06:33 +00:00

206 lines
7.3 KiB
TypeScript

import { render, screen, fireEvent } from '@testing-library/react'
import { expect } from 'chai'
import fetchMock from 'fetch-mock'
import { cloneDeep } from 'lodash'
import EmailsRow from '../../../../../../frontend/js/features/settings/components/emails/row'
import {
professionalUserData,
unconfirmedUserData,
} from '../../fixtures/test-user-email-data'
import { UserEmailData } from '../../../../../../types/user-email'
import { UserEmailsProvider } from '../../../../../../frontend/js/features/settings/context/user-email-context'
import { Affiliation } from '../../../../../../types/affiliation'
import getMeta from '@/utils/meta'
import { SplitTestProvider } from '@/shared/context/split-test-context'
function renderEmailsRow(data: UserEmailData) {
return render(
<SplitTestProvider>
<UserEmailsProvider>
<EmailsRow userEmailData={data} />
</UserEmailsProvider>
</SplitTestProvider>
)
}
function getByTextContent(text: string) {
return screen.getAllByText(
(content, node) =>
content === text || node?.children[0]?.textContent === text
)
}
describe('<EmailsRow/>', function () {
beforeEach(function () {
Object.assign(getMeta('ol-ExposedSettings'), {
samlInitPath: '/saml',
hasSamlBeta: true,
})
window.metaAttributesCache.set('ol-splitTestVariants', {})
fetchMock.get('/user/emails?ensureAffiliation=true', [])
})
afterEach(function () {
fetchMock.removeRoutes().clearHistory()
})
describe('with unaffiliated email data', function () {
it('renders email info', function () {
renderEmailsRow(unconfirmedUserData)
screen.getByText('baz@overleaf.com')
})
it('renders actions', function () {
renderEmailsRow(unconfirmedUserData)
screen.getByRole('button', { name: 'Make primary' })
})
})
describe('with affiliated email data', function () {
it('renders email info', function () {
renderEmailsRow(professionalUserData)
screen.getByText('foo@overleaf.com')
screen.getByText('Primary')
})
it('renders actions', function () {
renderEmailsRow(professionalUserData)
screen.getByRole('button', { name: 'Remove' })
})
it('renders institution info', function () {
renderEmailsRow(professionalUserData)
screen.getByText('Overleaf')
screen.getByText('Reader, Art History')
})
})
describe('with email data affiliated to an institution with SSO available', function () {
let affiliatedEmail: UserEmailData & { affiliation: Affiliation }
beforeEach(function () {
window.metaAttributesCache.get('ol-ExposedSettings').hasSamlFeature = true
// make sure the institution has SSO available
affiliatedEmail = cloneDeep(professionalUserData)
affiliatedEmail.affiliation.institution.confirmed = true
affiliatedEmail.affiliation.institution.isUniversity = true
affiliatedEmail.affiliation.institution.ssoEnabled = true
})
describe('when the email is not yet linked to the institution', function () {
beforeEach(async function () {
fetchMock.removeRoutes().clearHistory()
fetchMock.get(/\/user\/emails/, [affiliatedEmail, unconfirmedUserData])
await fetchMock.callHistory.flush(true)
})
it('prompts the user to link to their institutional account', function () {
renderEmailsRow(affiliatedEmail)
getByTextContent(
'You can now link your Overleaf account to your Overleaf institutional account.'
)
screen.getByRole('button', { name: 'Link accounts' })
})
})
describe('when the email is already linked to the institution', function () {
beforeEach(async function () {
affiliatedEmail.samlProviderId = '1'
fetchMock.removeRoutes().clearHistory()
fetchMock.get(/\/user\/emails/, [affiliatedEmail, unconfirmedUserData])
await fetchMock.callHistory.flush(true)
})
it('prompts the user to login using their institutional account', function () {
renderEmailsRow(affiliatedEmail)
getByTextContent(
'You can log in to Overleaf through your Overleaf institutional login.'
)
expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be
.null
})
it('shows unlink button and opens unlink modal', function () {
renderEmailsRow(affiliatedEmail)
fireEvent.click(screen.getByRole('button', { name: 'Unlink SSO' }))
screen.getByRole('dialog')
screen.getByText('Unlink institutional login')
})
})
describe('and domain capture is also on for group and Commons SSO also enabled', function () {
// scenario of a Commons account migrating to a group account
let affiliatedEmailWithDomainCaptureAndCommons: UserEmailData & {
affiliation: Affiliation
}
beforeEach(async function () {
fetchMock.removeRoutes().clearHistory()
affiliatedEmailWithDomainCaptureAndCommons = cloneDeep(affiliatedEmail)
affiliatedEmailWithDomainCaptureAndCommons.affiliation.group = {
_id: 'grou123',
domainCaptureEnabled: true,
managedUsersEnabled: true,
}
await fetchMock.callHistory.flush(true)
})
it('does not prompt the user to link to their institutional account', function () {
renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons)
expect(() =>
getByTextContent(
'You can now link your Overleaf account to your Overleaf institutional account.'
)
).to.throw('Unable to find an element with the text')
expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be
.null
})
it('still shows users can log in via Commons SSO if already linked', function () {
affiliatedEmailWithDomainCaptureAndCommons.samlProviderId = '1'
renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons)
getByTextContent(
'You can log in to Overleaf through your Overleaf institutional login.'
)
expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be
.null
})
it('uses `domainCapturedByGroup` when the feature flag is enabled', function () {
affiliatedEmailWithDomainCaptureAndCommons.affiliation.group = {
_id: 'grou123',
domainCaptureEnabled: true,
managedUsersEnabled: true,
}
affiliatedEmailWithDomainCaptureAndCommons.affiliation.domainCapturedByGroup = true
window.metaAttributesCache.set('ol-splitTestVariants', {
'domain-captured-by-group': 'enabled',
})
renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons)
expect(screen.queryByRole('button', { name: 'Link accounts' })).to.be
.null
})
it('ignores group domain capture when the feature flag is enabled and the domain is not captured', function () {
affiliatedEmailWithDomainCaptureAndCommons.affiliation.domainCapturedByGroup = false
window.metaAttributesCache.set('ol-splitTestVariants', {
'domain-captured-by-group': 'enabled',
})
renderEmailsRow(affiliatedEmailWithDomainCaptureAndCommons)
getByTextContent(
'You can now link your Overleaf account to your Overleaf institutional account.'
)
screen.getByRole('button', { name: 'Link accounts' })
})
})
})
})