|
|
@@ -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
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
})
|
|
|
})
|