Merge pull request #33610 from overleaf/jel-hostname-capturedByGroup
[web] Check `capturedByGroup` when adding new email GitOrigin-RevId: f9ef3d4cc7387dc0139a70aecd6cfcb20170abc6
This commit is contained in:
@@ -22,6 +22,17 @@ import { ConfirmEmailForm } from '@/features/settings/components/emails/confirm-
|
||||
import RecaptchaConditions from '@/shared/components/recaptcha-conditions'
|
||||
import SsoLinkingInfoGroup from './add-email/sso-linking-info-group'
|
||||
import Notification from '@/shared/components/notification'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
|
||||
function isDomainCapturedByGroup(
|
||||
domainInfo: DomainInfo,
|
||||
domainCapturedByGroupRolloutFlagEnabled: boolean
|
||||
): boolean {
|
||||
return domainCapturedByGroupRolloutFlagEnabled
|
||||
? (domainInfo.capturedByGroup && domainInfo.group?.domainCaptureEnabled) ||
|
||||
false
|
||||
: domainInfo.group?.domainCaptureEnabled || false
|
||||
}
|
||||
|
||||
function AddEmail() {
|
||||
const { t } = useTranslation()
|
||||
@@ -49,6 +60,10 @@ function AddEmail() {
|
||||
const emailAddressLimit = getMeta('ol-emailAddressLimit') || 10
|
||||
const { ref: recaptchaRef, getReCaptchaToken } = useRecaptcha()
|
||||
|
||||
const domainCapturedByGroupRolloutFlagEnabled = useFeatureFlag(
|
||||
'domain-captured-by-group'
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setUserEmailsContextLoading(isLoading)
|
||||
}, [setUserEmailsContextLoading, isLoading])
|
||||
@@ -196,8 +211,15 @@ function AddEmail() {
|
||||
)
|
||||
}
|
||||
|
||||
const isDomainCaptured = newEmailMatchedDomain
|
||||
? isDomainCapturedByGroup(
|
||||
newEmailMatchedDomain,
|
||||
domainCapturedByGroupRolloutFlagEnabled
|
||||
)
|
||||
: false
|
||||
const isSsoAvailableForDomain =
|
||||
newEmailMatchedDomain && ssoAvailableForDomain(newEmailMatchedDomain)
|
||||
newEmailMatchedDomain &&
|
||||
ssoAvailableForDomain(newEmailMatchedDomain, isDomainCaptured)
|
||||
|
||||
return (
|
||||
<form>
|
||||
@@ -243,6 +265,7 @@ function AddEmail() {
|
||||
<AddEmailViaSSO
|
||||
email={newEmail}
|
||||
domainInfo={newEmailMatchedDomain}
|
||||
isDomainCaptured={isDomainCaptured}
|
||||
userInstitutions={state.data.linkedInstitutionIds}
|
||||
/>
|
||||
</div>
|
||||
@@ -259,15 +282,14 @@ function AddEmailViaSSO({
|
||||
email,
|
||||
domainInfo,
|
||||
userInstitutions,
|
||||
isDomainCaptured,
|
||||
}: {
|
||||
email: string
|
||||
domainInfo: DomainInfo
|
||||
userInstitutions: string[]
|
||||
isDomainCaptured: boolean
|
||||
}) {
|
||||
if (
|
||||
domainInfo.group?.domainCaptureEnabled &&
|
||||
domainInfo.group?.managedUsersEnabled
|
||||
) {
|
||||
if (isDomainCaptured && domainInfo.group?.managedUsersEnabled) {
|
||||
return (
|
||||
<Notification
|
||||
type="error"
|
||||
@@ -298,10 +320,7 @@ function AddEmailViaSSO({
|
||||
)
|
||||
}
|
||||
return <SsoLinkingInfo email={email} domainInfo={domainInfo} />
|
||||
} else if (
|
||||
domainInfo.group?.domainCaptureEnabled &&
|
||||
domainInfo.group?.ssoConfig?.enabled
|
||||
) {
|
||||
} else if (isDomainCaptured && domainInfo.group?.ssoConfig?.enabled) {
|
||||
return <SsoLinkingInfoGroup domainInfo={domainInfo} />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ function matchLocalAndDomain(emailHint: string) {
|
||||
export type DomainInfo = {
|
||||
hostname: string
|
||||
confirmed?: boolean
|
||||
capturedByGroup?: boolean
|
||||
university: {
|
||||
id: number
|
||||
name: string
|
||||
|
||||
@@ -3,7 +3,8 @@ import { DomainInfo } from '../components/emails/add-email/input'
|
||||
import { Institution } from '../../../../../types/institution'
|
||||
|
||||
export const ssoAvailableForDomain = (
|
||||
domain: DomainInfo | null
|
||||
domain: DomainInfo | null,
|
||||
isDomainCapturedByGroup: boolean
|
||||
): domain is DomainInfo => {
|
||||
const { hasSamlBeta, hasSamlFeature } = getMeta('ol-ExposedSettings')
|
||||
if (!hasSamlFeature || !domain || !domain.confirmed || !domain.university) {
|
||||
@@ -13,7 +14,7 @@ export const ssoAvailableForDomain = (
|
||||
return true
|
||||
}
|
||||
|
||||
if (domain.group?.ssoConfig?.enabled) {
|
||||
if (isDomainCapturedByGroup && domain.group?.ssoConfig?.enabled) {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
+214
-18
@@ -14,6 +14,7 @@ import { Affiliation } from '../../../../../../types/affiliation'
|
||||
import withMarkup from '../../../../helpers/with-markup'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { clearDomainCache } from '../../../../../../frontend/js/features/settings/components/emails/add-email/input'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
|
||||
const userEmailData: UserEmailData & { affiliation: Affiliation } = {
|
||||
affiliation: {
|
||||
@@ -57,6 +58,14 @@ const institutionDomainData = [
|
||||
},
|
||||
] as const
|
||||
|
||||
function renderEmailsSection() {
|
||||
return render(<EmailsSection />, {
|
||||
wrapper: ({ children }) => (
|
||||
<SplitTestProvider>{children}</SplitTestProvider>
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
function resetFetchMock() {
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
fetchMock.get('express:/institutions/domains', [])
|
||||
@@ -94,14 +103,14 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('renders "add another email" button', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await screen.findByRole('button', { name: 'Add another email' })
|
||||
})
|
||||
|
||||
it('renders input', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
await fetchMock.callHistory.flush(true)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
@@ -116,7 +125,7 @@ describe('<EmailsSection />', function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
fetchMock.get(`/institutions/domains?hostname=email.com&limit=1`, 200)
|
||||
fetchMock.get(`/institutions/domains?hostname=email&limit=1`, 200)
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
await fetchMock.callHistory.flush(true)
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
@@ -159,7 +168,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('renders "add new email" button', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -175,7 +184,7 @@ describe('<EmailsSection />', function () {
|
||||
emails.push({ email: `bar${i}@overleaf.com` })
|
||||
}
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', emails)
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const findByTextWithMarkup = withMarkup(screen.findByText)
|
||||
await findByTextWithMarkup(
|
||||
@@ -188,7 +197,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('adds new email address', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
|
||||
'button',
|
||||
@@ -232,7 +241,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('fails to add add new email address', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
|
||||
'button',
|
||||
@@ -271,7 +280,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('can link email address to an existing SSO institution', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -295,7 +304,7 @@ describe('<EmailsSection />', function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [
|
||||
{ email: 'bar@autocomplete.edu', samlProviderId: '1234' },
|
||||
])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -321,7 +330,7 @@ describe('<EmailsSection />', function () {
|
||||
const country = 'Germany'
|
||||
const customDepartment = 'Custom department'
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -424,7 +433,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('autocompletes institution name', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -480,7 +489,7 @@ describe('<EmailsSection />', function () {
|
||||
const countryCode = 'de'
|
||||
const newUniversity = 'Abcdef'
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -596,7 +605,7 @@ describe('<EmailsSection />', function () {
|
||||
]
|
||||
const hostnameFirstChar = institutionDomainDataCopy[0].hostname.charAt(0)
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -669,7 +678,7 @@ describe('<EmailsSection />', function () {
|
||||
]
|
||||
const hostnameFirstChar = institutionDomainDataCopy[0].hostname.charAt(0)
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -766,7 +775,7 @@ describe('<EmailsSection />', function () {
|
||||
it('can add email address via SSO', async function () {
|
||||
// note: this UI is a WIP
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -809,7 +818,7 @@ describe('<EmailsSection />', function () {
|
||||
it('renders error', async function () {
|
||||
// note: this UI is a WIP
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -855,7 +864,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('renders Commons UI', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -900,7 +909,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('renders group domain-capture error instead of Commons UI', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
@@ -925,5 +934,192 @@ describe('<EmailsSection />', function () {
|
||||
).to.be.null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when the domain-captured-by-group feature flag is enabled', function () {
|
||||
beforeEach(function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {
|
||||
'domain-captured-by-group': 'enabled',
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
window.metaAttributesCache.set('ol-splitTestVariants', {})
|
||||
})
|
||||
|
||||
describe('and capturedByGroup is true with managedUsersEnabled', function () {
|
||||
beforeEach(async function () {
|
||||
await fetchMock.callHistory.flush(true)
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
const institution = {
|
||||
university: {
|
||||
id: 1234,
|
||||
ssoEnabled: false,
|
||||
name: 'Auto Complete University',
|
||||
},
|
||||
hostname: 'autocomplete.edu',
|
||||
confirmed: true,
|
||||
capturedByGroup: true,
|
||||
group: {
|
||||
domainCaptureEnabled: true,
|
||||
managedUsersEnabled: true,
|
||||
ssoConfig: { enabled: true },
|
||||
},
|
||||
}
|
||||
|
||||
fetchMock.get('express:/institutions/domains', [institution])
|
||||
})
|
||||
|
||||
it('renders the domain-capture error', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
|
||||
const notification = await screen.findByRole('alert')
|
||||
within(notification).getByText(
|
||||
'Your company email address has been registered under a verified domain, and cannot be added as a secondary email.',
|
||||
{ exact: false }
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('and capturedByGroup is false with managedUsersEnabled (domainCaptureEnabled alone is not enough)', function () {
|
||||
beforeEach(async function () {
|
||||
await fetchMock.callHistory.flush(true)
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
const institution = {
|
||||
university: {
|
||||
id: 1234,
|
||||
ssoEnabled: false,
|
||||
name: 'Auto Complete University',
|
||||
},
|
||||
hostname: 'autocomplete.edu',
|
||||
confirmed: true,
|
||||
capturedByGroup: false,
|
||||
group: {
|
||||
domainCaptureEnabled: true,
|
||||
managedUsersEnabled: true,
|
||||
ssoConfig: { enabled: true },
|
||||
},
|
||||
}
|
||||
|
||||
fetchMock.get('express:/institutions/domains', [institution])
|
||||
})
|
||||
|
||||
it('does not render the domain-capture error and shows regular institution fields', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
|
||||
await screen.findByRole('button', { name: 'Add new email' })
|
||||
expect(screen.queryByRole('alert')).to.be.null
|
||||
})
|
||||
})
|
||||
|
||||
describe('and capturedByGroup is true with ssoConfig enabled (no managedUsers)', function () {
|
||||
beforeEach(async function () {
|
||||
await fetchMock.callHistory.flush(true)
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
const institution = {
|
||||
university: {
|
||||
id: 1234,
|
||||
ssoEnabled: false,
|
||||
name: 'Auto Complete University',
|
||||
},
|
||||
hostname: 'autocomplete.edu',
|
||||
confirmed: true,
|
||||
capturedByGroup: true,
|
||||
group: {
|
||||
domainCaptureEnabled: true,
|
||||
managedUsersEnabled: false,
|
||||
ssoConfig: { enabled: true },
|
||||
},
|
||||
}
|
||||
|
||||
fetchMock.get('express:/institutions/domains', [institution])
|
||||
})
|
||||
|
||||
it('renders the group SSO unavailable message', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
|
||||
await screen.findByText('This feature is currently unavailable.')
|
||||
})
|
||||
})
|
||||
|
||||
describe('and capturedByGroup is false with ssoConfig enabled', function () {
|
||||
beforeEach(async function () {
|
||||
await fetchMock.callHistory.flush(true)
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
const institution = {
|
||||
university: {
|
||||
id: 1234,
|
||||
ssoEnabled: false,
|
||||
name: 'Auto Complete University',
|
||||
},
|
||||
hostname: 'autocomplete.edu',
|
||||
confirmed: true,
|
||||
capturedByGroup: false,
|
||||
group: {
|
||||
domainCaptureEnabled: true,
|
||||
managedUsersEnabled: false,
|
||||
ssoConfig: { enabled: true },
|
||||
},
|
||||
}
|
||||
|
||||
fetchMock.get('express:/institutions/domains', [institution])
|
||||
})
|
||||
|
||||
it('does not render SSO UI and shows regular institution fields', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [])
|
||||
renderEmailsSection()
|
||||
|
||||
const button = await screen.findByRole<HTMLButtonElement>('button', {
|
||||
name: 'Add another email',
|
||||
})
|
||||
|
||||
await userEvent.click(button)
|
||||
|
||||
const input = screen.getByRole('textbox', { name: 'Email' })
|
||||
fireEvent.change(input, {
|
||||
target: { value: 'user@autocomplete.edu' },
|
||||
})
|
||||
|
||||
await screen.findByRole('button', { name: 'Add new email' })
|
||||
expect(screen.queryByText('This feature is currently unavailable.'))
|
||||
.to.be.null
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
+11
-2
@@ -12,6 +12,7 @@ import { UserEmailsProvider } from '../../../../../../frontend/js/features/setti
|
||||
import EmailsSection from '../../../../../../frontend/js/features/settings/components/emails-section'
|
||||
import { Affiliation } from '../../../../../../types/affiliation'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
|
||||
const userData1: UserEmailData & { affiliation: Affiliation } = {
|
||||
affiliation: {
|
||||
@@ -74,6 +75,14 @@ const userData2: UserEmailData & { affiliation: Affiliation } = {
|
||||
default: false,
|
||||
}
|
||||
|
||||
function renderEmailsSection() {
|
||||
return render(<EmailsSection />, {
|
||||
wrapper: ({ children }) => (
|
||||
<SplitTestProvider>{children}</SplitTestProvider>
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
describe('user role and institution', function () {
|
||||
beforeEach(function () {
|
||||
Object.assign(getMeta('ol-ExposedSettings'), {
|
||||
@@ -125,7 +134,7 @@ describe('user role and institution', function () {
|
||||
it('fetches institution data and replaces departments dropdown on add/change', async function () {
|
||||
const userEmailData = userData1
|
||||
fetchMock.modifyRoute('get user emails', { response: [userEmailData] })
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await fetchMock.callHistory.flush(true)
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
@@ -158,7 +167,7 @@ describe('user role and institution', function () {
|
||||
.modifyRoute('get user emails', { response: [userData1] })
|
||||
.get(/\/institutions\/list/, { departments: [] })
|
||||
.post('/user/emails/endorse', 200)
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const addBtn = await screen.findByRole('button', {
|
||||
name: /add role and department/i,
|
||||
|
||||
+22
-13
@@ -16,6 +16,15 @@ import {
|
||||
unconfirmedUserData,
|
||||
} from '../../fixtures/test-user-email-data'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
|
||||
function renderEmailsSection() {
|
||||
return render(<EmailsSection />, {
|
||||
wrapper: ({ children }) => (
|
||||
<SplitTestProvider>{children}</SplitTestProvider>
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
describe('<EmailsSection />', function () {
|
||||
beforeEach(function () {
|
||||
@@ -30,13 +39,13 @@ describe('<EmailsSection />', function () {
|
||||
})
|
||||
|
||||
it('renders translated heading', function () {
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
screen.getByRole('heading', { name: /emails and affiliations/i })
|
||||
})
|
||||
|
||||
it('renders translated description', function () {
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
screen.getByText(/add additional email addresses/i)
|
||||
screen.getByText(/to change your primary email/i)
|
||||
@@ -46,14 +55,14 @@ describe('<EmailsSection />', function () {
|
||||
})
|
||||
|
||||
it('renders a loading message when loading', async function () {
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await screen.findByText(/loading/i)
|
||||
})
|
||||
|
||||
it('renders an error message and hides loading message on error', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', 500)
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await screen.findByText(
|
||||
/an error has occurred while performing your request/i
|
||||
@@ -63,7 +72,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('renders user emails', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', fakeUsersData)
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await waitFor(() => {
|
||||
fakeUsersData.forEach(userData => {
|
||||
@@ -74,7 +83,7 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('renders primary status', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [professionalUserData])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await screen.findByText(`${professionalUserData.email}`)
|
||||
screen.getByText('Primary')
|
||||
@@ -82,14 +91,14 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('shows confirmation status for unconfirmed users', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await screen.findByText(/unconfirmed/i)
|
||||
})
|
||||
|
||||
it('hides confirmation status for confirmed users', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [confirmedUserData])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
|
||||
|
||||
expect(screen.queryByText(/please check your inbox/i)).to.be.null
|
||||
@@ -97,14 +106,14 @@ describe('<EmailsSection />', function () {
|
||||
|
||||
it('renders resend link', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await screen.findByRole('button', { name: 'Send confirmation code' })
|
||||
})
|
||||
|
||||
it('renders professional label', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [professionalUserData])
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
const node = await screen.findByText(professionalUserData.email, {
|
||||
exact: false,
|
||||
@@ -115,7 +124,7 @@ describe('<EmailsSection />', function () {
|
||||
it('shows loader when resending email', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
|
||||
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
|
||||
|
||||
fetchMock.post('/user/emails/send-confirmation-code', 200)
|
||||
@@ -145,7 +154,7 @@ describe('<EmailsSection />', function () {
|
||||
it('shows error when resending email fails', async function () {
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
|
||||
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
|
||||
|
||||
fetchMock.post('/user/emails/send-confirmation-code', 503)
|
||||
@@ -195,7 +204,7 @@ describe('<EmailsSection />', function () {
|
||||
]
|
||||
|
||||
fetchMock.get('/user/emails?ensureAffiliation=true', emails)
|
||||
render(<EmailsSection />)
|
||||
renderEmailsSection()
|
||||
|
||||
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { expect } from 'chai'
|
||||
import { ssoAvailableForDomain } from '../../../../../frontend/js/features/settings/utils/sso'
|
||||
import { DomainInfo } from '../../../../../frontend/js/features/settings/components/emails/add-email/input'
|
||||
|
||||
const baseDomain: DomainInfo = {
|
||||
hostname: 'example.edu',
|
||||
confirmed: true,
|
||||
university: {
|
||||
id: 1,
|
||||
name: 'Example University',
|
||||
ssoEnabled: false,
|
||||
ssoBeta: false,
|
||||
},
|
||||
group: {
|
||||
domainCaptureEnabled: false,
|
||||
ssoConfig: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
describe('ssoAvailableForDomain', function () {
|
||||
beforeEach(function () {
|
||||
window.metaAttributesCache.set('ol-ExposedSettings', {
|
||||
hasSamlFeature: true,
|
||||
hasSamlBeta: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('returns false when hasSamlFeature is false', function () {
|
||||
window.metaAttributesCache.set('ol-ExposedSettings', {
|
||||
hasSamlFeature: false,
|
||||
hasSamlBeta: false,
|
||||
})
|
||||
expect(ssoAvailableForDomain(baseDomain, false)).to.be.false
|
||||
})
|
||||
|
||||
it('returns false when domain is null', function () {
|
||||
expect(ssoAvailableForDomain(null, false)).to.be.false
|
||||
})
|
||||
|
||||
it('returns false when domain is not confirmed', function () {
|
||||
const domain = { ...baseDomain, confirmed: false }
|
||||
expect(ssoAvailableForDomain(domain, false)).to.be.false
|
||||
})
|
||||
|
||||
it('returns true when university.ssoEnabled is true, regardless of isDomainCapturedByGroup', function () {
|
||||
const domain: DomainInfo = {
|
||||
...baseDomain,
|
||||
university: { ...baseDomain.university, ssoEnabled: true },
|
||||
}
|
||||
expect(ssoAvailableForDomain(domain, false)).to.be.true
|
||||
expect(ssoAvailableForDomain(domain, true)).to.be.true
|
||||
})
|
||||
|
||||
describe('group SSO via ssoConfig', function () {
|
||||
const domainWithGroupSso: DomainInfo = {
|
||||
...baseDomain,
|
||||
group: {
|
||||
domainCaptureEnabled: true,
|
||||
ssoConfig: { enabled: true },
|
||||
},
|
||||
}
|
||||
|
||||
it('returns true when isDomainCapturedByGroup is true and group ssoConfig is enabled', function () {
|
||||
expect(ssoAvailableForDomain(domainWithGroupSso, true)).to.be.true
|
||||
})
|
||||
|
||||
it('returns false when isDomainCapturedByGroup is false even if group ssoConfig is enabled', function () {
|
||||
expect(ssoAvailableForDomain(domainWithGroupSso, false)).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
it('returns true when hasSamlBeta and university.ssoBeta are both true', function () {
|
||||
window.metaAttributesCache.set('ol-ExposedSettings', {
|
||||
hasSamlFeature: true,
|
||||
hasSamlBeta: true,
|
||||
})
|
||||
const domain: DomainInfo = {
|
||||
...baseDomain,
|
||||
university: { ...baseDomain.university, ssoBeta: true },
|
||||
}
|
||||
expect(ssoAvailableForDomain(domain, false)).to.be.true
|
||||
})
|
||||
|
||||
it('returns false when hasSamlBeta is false and university.ssoBeta is true', function () {
|
||||
const domain: DomainInfo = {
|
||||
...baseDomain,
|
||||
university: { ...baseDomain.university, ssoBeta: true },
|
||||
}
|
||||
expect(ssoAvailableForDomain(domain, false)).to.be.false
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user