| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126 |
- import {
- render,
- screen,
- fireEvent,
- waitForElementToBeRemoved,
- within,
- } from '@testing-library/react'
- import userEvent from '@testing-library/user-event'
- import EmailsSection from '../../../../../../frontend/js/features/settings/components/emails-section'
- import { expect } from 'chai'
- import fetchMock from 'fetch-mock'
- import { UserEmailData } from '../../../../../../types/user-email'
- 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: {
- cachedConfirmedAt: null,
- cachedEntitlement: null,
- cachedLastDayToReconfirm: null,
- cachedPastReconfirmDate: false,
- cachedReconfirmedAt: null,
- department: 'Art History',
- institution: {
- commonsAccount: false,
- enterpriseCommons: false,
- writefullCommonsAccount: false,
- confirmed: true,
- id: 1,
- isUniversity: true,
- maxConfirmationMonths: null,
- name: 'Overleaf',
- ssoEnabled: false,
- ssoBeta: false,
- },
- inReconfirmNotificationPeriod: false,
- inferred: false,
- licence: 'pro_plus',
- pastReconfirmDate: false,
- portal: { slug: '', templates_count: 1 },
- role: 'Reader',
- },
- email: 'baz@overleaf.com',
- default: false,
- }
- const institutionDomainData = [
- {
- university: {
- id: 1234,
- ssoEnabled: true,
- name: 'Auto Complete University',
- },
- hostname: 'autocomplete.edu',
- confirmed: true,
- },
- ] as const
- function renderEmailsSection() {
- return render(<EmailsSection />, {
- wrapper: ({ children }) => (
- <SplitTestProvider>{children}</SplitTestProvider>
- ),
- })
- }
- function resetFetchMock() {
- fetchMock.removeRoutes().clearHistory()
- fetchMock.get('express:/institutions/domains', [])
- }
- async function confirmCodeForEmail(email: string) {
- const inputCode = await screen.findByRole('textbox', {
- name: /Enter the 6-digit confirmation code sent to /,
- })
- screen.getByText(email, { exact: false })
- fireEvent.change(inputCode, { target: { value: '123456' } })
- const submitCodeBtn = screen.getByRole<HTMLButtonElement>('button', {
- name: 'Confirm',
- })
- fireEvent.click(submitCodeBtn)
- await waitForElementToBeRemoved(() =>
- screen.getByRole('button', { name: 'Confirming' })
- )
- }
- describe('<EmailsSection />', function () {
- beforeEach(function () {
- Object.assign(getMeta('ol-ExposedSettings'), {
- hasAffiliationsFeature: true,
- hasSamlFeature: true,
- samlInitPath: 'saml/init',
- })
- fetchMock.removeRoutes().clearHistory()
- })
- afterEach(function () {
- resetFetchMock()
- clearDomainCache()
- })
- it('renders "add another email" button', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- await screen.findByRole('button', { name: 'Add another email' })
- })
- it('renders input', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- await fetchMock.callHistory.flush(true)
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- fireEvent.click(button)
- await screen.findByRole('textbox', { name: 'Email' })
- })
- it('renders "Start adding your address" until a valid email is typed', async 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)
- renderEmailsSection()
- await fetchMock.callHistory.flush(true)
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- fireEvent.click(button)
- const input = screen.getByRole('textbox', { name: 'Email' })
- // initially the text is displayed and the "add email" button disabled
- screen.getByText('Start by adding your email address.')
- expect(
- screen.getByRole<HTMLButtonElement>('button', {
- name: 'Add new email',
- }).disabled
- ).to.be.true
- // no changes while writing the email address
- fireEvent.change(input, {
- target: { value: 'partial@email' },
- })
- screen.getByText('Start by adding your email address.')
- expect(
- screen.getByRole<HTMLButtonElement>('button', {
- name: 'Add new email',
- }).disabled
- ).to.be.true
- // the text is removed when the complete email address is typed, and the "add button" is reenabled
- fireEvent.change(input, {
- target: { value: 'valid@email.com' },
- })
- expect(screen.queryByText('Start by adding your email address.')).to.be.null
- expect(
- screen.getByRole<HTMLButtonElement>('button', {
- name: 'Add new email',
- }).disabled
- ).to.be.false
- })
- it('renders "add new email" button', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- fireEvent.click(button)
- screen.getByRole('button', { name: 'Add new email' })
- })
- it('prevent users from adding new emails when the limit is reached', async function () {
- const emails = []
- for (let i = 0; i < 10; i++) {
- emails.push({ email: `bar${i}@overleaf.com` })
- }
- fetchMock.get('/user/emails?ensureAffiliation=true', emails)
- renderEmailsSection()
- const findByTextWithMarkup = withMarkup(screen.findByText)
- await findByTextWithMarkup(
- 'You can have a maximum of 10 email addresses on this account. To add another email address, please delete an existing one.'
- )
- expect(screen.queryByRole('button', { name: 'Add another email' })).to.not
- .exist
- })
- it('adds new email address', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
- 'button',
- { name: 'Add another email' }
- )
- await fetchMock.callHistory.flush(true)
- resetFetchMock()
- fetchMock
- .get('/user/emails?ensureAffiliation=true', [userEmailData])
- .post('/user/emails/secondary', 200)
- .post('/user/emails/confirm-secondary', 200)
- fireEvent.click(addAnotherEmailBtn)
- const input = screen.getByRole('textbox', { name: 'Email' })
- fireEvent.change(input, {
- target: { value: userEmailData.email },
- })
- const submitBtn = screen.getByRole<HTMLButtonElement>('button', {
- name: 'Add new email',
- })
- expect(submitBtn.disabled).to.be.false
- fireEvent.click(submitBtn)
- expect(submitBtn.disabled).to.be.true
- await waitForElementToBeRemoved(() =>
- screen.getByRole('button', {
- name: /adding/i,
- })
- )
- await confirmCodeForEmail(userEmailData.email)
- const elements = await screen.findAllByText(userEmailData.email)
- expect(elements.length).to.equal(2)
- })
- it('fails to add add new email address', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
- 'button',
- { name: 'Add another email' }
- )
- await fetchMock.callHistory.flush(true)
- resetFetchMock()
- fetchMock
- .get('/user/emails?ensureAffiliation=true', [])
- .post('/user/emails/secondary', 400)
- fireEvent.click(addAnotherEmailBtn)
- const input = screen.getByRole('textbox', { name: 'Email' })
- fireEvent.change(input, {
- target: { value: userEmailData.email },
- })
- const submitBtn = screen.getByRole<HTMLButtonElement>('button', {
- name: 'Add new email',
- })
- expect(submitBtn.disabled).to.be.false
- fireEvent.click(submitBtn)
- expect(submitBtn.disabled).to.be.true
- await screen.findByText(
- 'Invalid Request. Please correct the data and try again.'
- )
- expect(submitBtn).to.not.be.null
- expect(submitBtn.disabled).to.be.false
- })
- it('can link email address to an existing SSO institution', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- fetchMock.get('express:/institutions/domains', institutionDomainData)
- await userEvent.click(button)
- const input = screen.getByRole('textbox', { name: 'Email' })
- fireEvent.change(input, {
- target: { value: 'user@autocomplete.edu' },
- })
- await screen.findByRole('button', { name: 'Link accounts and add email' })
- })
- it('prevents user from linking to same SSO institution twice', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [
- { email: 'bar@autocomplete.edu', samlProviderId: '1234' },
- ])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- fetchMock.get('express:/institutions/domains', institutionDomainData)
- await userEvent.click(button)
- const input = screen.getByRole('textbox', { name: 'Email' })
- fireEvent.change(input, {
- target: { value: 'baz@autocomplete.edu' },
- })
- await screen.findByText(
- 'This institution is already linked with your account via another email address.'
- )
- })
- it('adds new email address with existing institution and custom departments', async function () {
- const country = 'Germany'
- const customDepartment = 'Custom department'
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- await fetchMock.callHistory.flush(true)
- resetFetchMock()
- await userEvent.click(button)
- await userEvent.type(
- screen.getByRole('textbox', { name: 'Email' }),
- userEmailData.email
- )
- await userEvent.click(screen.getByRole('button', { name: 'Let us know' }))
- const universityInput = screen.getByRole<HTMLInputElement>('combobox', {
- name: 'University',
- })
- expect(universityInput.disabled).to.be.true
- fetchMock.get('/institutions/list?country_code=de', [
- {
- id: userEmailData.affiliation.institution.id,
- name: userEmailData.affiliation.institution.name,
- country_code: 'de',
- departments: [customDepartment],
- },
- ])
- // Select the country from dropdown
- await userEvent.type(
- screen.getByRole('combobox', {
- name: 'Country',
- }),
- country
- )
- await userEvent.click(screen.getByText(country))
- expect(universityInput.disabled).to.be.false
- await fetchMock.callHistory.flush(true)
- resetFetchMock()
- // Select the university from dropdown
- await userEvent.click(universityInput)
- await userEvent.click(
- await screen.findByText(userEmailData.affiliation.institution.name)
- )
- const roleInput = screen.getByRole('combobox', { name: 'Role' })
- await userEvent.type(roleInput, userEmailData.affiliation.role!)
- const departmentInput = screen.getByRole('combobox', {
- name: 'Department',
- })
- await userEvent.click(departmentInput)
- await userEvent.click(screen.getByText(customDepartment))
- const userEmailDataCopy = {
- ...userEmailData,
- affiliation: {
- ...userEmailData.affiliation,
- department: customDepartment,
- },
- }
- fetchMock
- .get('/user/emails?ensureAffiliation=true', [userEmailDataCopy])
- .post('/user/emails/secondary', 200)
- .post('/user/emails/confirm-secondary', 200)
- await userEvent.click(
- screen.getByRole('button', {
- name: 'Add new email',
- })
- )
- const request = fetchMock.callHistory.calls(/\/user\/emails/).at(0)
- expect(
- JSON.parse(request?.options.body?.toString() || '{}')
- ).to.deep.include({
- email: userEmailData.email,
- university: {
- id: userEmailData.affiliation?.institution.id,
- },
- role: userEmailData.affiliation?.role,
- department: customDepartment,
- })
- await screen.findByText(/Enter the 6-digit confirmation code sent to /)
- await confirmCodeForEmail(userEmailData.email)
- await screen.findByText(userEmailData.affiliation.role!, { exact: false })
- await screen.findByText(customDepartment, { exact: false })
- })
- it('autocompletes institution name', async function () {
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- await fetchMock.callHistory.flush(true)
- resetFetchMock()
- fetchMock.get('/institutions/list?country_code=de', [
- {
- id: 1,
- name: 'University of Bonn',
- },
- {
- id: 2,
- name: 'Bochum institute of Science',
- },
- ])
- // open "add new email" section and click "let us know" to open the Country/University form
- await userEvent.click(button)
- await userEvent.type(
- screen.getByRole('textbox', { name: 'Email' }),
- userEmailData.email
- )
- await userEvent.click(screen.getByRole('button', { name: 'Let us know' }))
- // select a country
- const countryInput = screen.getByRole<HTMLInputElement>('combobox', {
- name: 'Country',
- })
- await userEvent.click(countryInput)
- await userEvent.type(countryInput, 'Germ')
- await userEvent.click(await screen.findByText('Germany'))
- // match several universities on initial typing
- const universityInput = screen.getByRole<HTMLInputElement>('combobox', {
- name: 'University',
- })
- await userEvent.click(universityInput)
- await userEvent.type(universityInput, 'bo')
- await screen.findByText('University of Bonn')
- await screen.findByText('Bochum institute of Science')
- // match a single university when typing to refine the search
- await userEvent.type(universityInput, 'nn')
- await screen.findByText('University of Bonn')
- expect(screen.queryByText('Bochum institute of Science')).to.be.null
- })
- it('adds new email address without existing institution', async function () {
- const country = 'Germany'
- const countryCode = 'de'
- const newUniversity = 'Abcdef'
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- await fetchMock.callHistory.flush(true)
- resetFetchMock()
- await userEvent.click(button)
- await userEvent.type(
- screen.getByRole('textbox', { name: 'Email' }),
- userEmailData.email
- )
- await userEvent.click(screen.getByRole('button', { name: 'Let us know' }))
- const universityInput = screen.getByRole<HTMLInputElement>('combobox', {
- name: 'University',
- })
- expect(universityInput.disabled).to.be.true
- fetchMock.get(/\/institutions\/list/, [
- {
- id: userEmailData.affiliation.institution.id,
- name: userEmailData.affiliation.institution.name,
- country_code: 'de',
- departments: [],
- },
- ])
- // Select the country from dropdown
- await userEvent.type(
- screen.getByRole('combobox', {
- name: 'Country',
- }),
- country
- )
- await userEvent.click(screen.getByText(country))
- expect(universityInput.disabled).to.be.false
- await fetchMock.callHistory.flush(true)
- resetFetchMock()
- // Enter the university manually
- await userEvent.type(universityInput, newUniversity)
- const roleInput = screen.getByRole('combobox', { name: 'Role' })
- await userEvent.type(roleInput, userEmailData.affiliation.role!)
- const departmentInput = screen.getByRole('combobox', {
- name: 'Department',
- })
- await userEvent.type(departmentInput, userEmailData.affiliation.department!)
- const userEmailDataCopy = {
- ...userEmailData,
- affiliation: {
- ...userEmailData.affiliation,
- institution: {
- ...userEmailData.affiliation.institution,
- name: newUniversity,
- },
- },
- }
- fetchMock
- .get('/user/emails?ensureAffiliation=true', [userEmailDataCopy])
- .post('/user/emails/secondary', 200)
- .post('/user/emails/confirm-secondary', 200)
- await userEvent.click(
- screen.getByRole('button', {
- name: 'Add new email',
- })
- )
- await confirmCodeForEmail(userEmailData.email)
- const request = fetchMock.callHistory.calls(/\/user\/emails/).at(0)
- expect(
- JSON.parse(request?.options.body?.toString() || '{}')
- ).to.deep.include({
- email: userEmailData.email,
- university: {
- name: newUniversity,
- country_code: countryCode,
- },
- role: userEmailData.affiliation?.role,
- department: userEmailData.affiliation?.department,
- })
- const elements = await screen.findAllByText(userEmailData.email)
- expect(elements.length).to.equal(2)
- await screen.findByText(newUniversity)
- await screen.findByText(userEmailData.affiliation.role!, { exact: false })
- await screen.findByText(userEmailData.affiliation.department!, {
- exact: false,
- })
- })
- it('shows country, university, role and department fields based on whether `change` was clicked or not', async function () {
- const institutionDomainDataCopy = [
- {
- ...institutionDomainData[0],
- university: {
- ...institutionDomainData[0].university,
- ssoEnabled: false,
- },
- },
- ]
- const hostnameFirstChar = institutionDomainDataCopy[0].hostname.charAt(0)
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- fetchMock.get(
- `/institutions/domains?hostname=${hostnameFirstChar}&limit=1`,
- institutionDomainDataCopy
- )
- await userEvent.click(button)
- await userEvent.type(
- screen.getByRole('textbox', { name: 'Email' }),
- `user@${hostnameFirstChar}`
- )
- await userEvent.keyboard('{Tab}')
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- expect(
- screen.queryByRole('combobox', {
- name: 'Country',
- })
- ).to.be.null
- expect(
- screen.queryByRole('combobox', {
- name: 'University',
- })
- ).to.be.null
- screen.getByRole('combobox', {
- name: 'Role',
- })
- screen.getByRole('combobox', {
- name: 'Department',
- })
- await userEvent.click(screen.getByRole('button', { name: 'Change' }))
- screen.getByRole('combobox', {
- name: 'Country',
- })
- screen.getByRole('combobox', {
- name: 'University',
- })
- expect(
- screen.queryByRole('combobox', {
- name: 'Role',
- })
- ).to.be.null
- expect(
- screen.queryByRole('combobox', {
- name: 'Department',
- })
- ).to.be.null
- })
- it('displays institution name with change button when autocompleted and adds new record', async function () {
- const institutionDomainDataCopy = [
- {
- ...institutionDomainData[0],
- university: {
- ...institutionDomainData[0].university,
- ssoEnabled: false,
- },
- },
- ]
- const hostnameFirstChar = institutionDomainDataCopy[0].hostname.charAt(0)
- fetchMock.get('/user/emails?ensureAffiliation=true', [])
- renderEmailsSection()
- const button = await screen.findByRole<HTMLButtonElement>('button', {
- name: 'Add another email',
- })
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- fetchMock.get(
- `/institutions/domains?hostname=${hostnameFirstChar}&limit=1`,
- institutionDomainDataCopy
- )
- await userEvent.click(button)
- await userEvent.type(
- screen.getByRole('textbox', { name: 'Email' }),
- `user@${hostnameFirstChar}`
- )
- await userEvent.keyboard('{Tab}')
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- screen.getByText(institutionDomainDataCopy[0].university.name)
- const userEmailDataCopy = {
- ...userEmailData,
- affiliation: {
- ...userEmailData.affiliation,
- institution: {
- ...userEmailData.affiliation.institution,
- name: institutionDomainDataCopy[0].university.name,
- },
- },
- }
- fetchMock
- .get('/user/emails?ensureAffiliation=true', [userEmailDataCopy])
- .post('/user/emails/secondary', 200)
- .post('/user/emails/confirm-secondary', 200)
- await userEvent.type(
- screen.getByRole('combobox', { name: 'Role' }),
- userEmailData.affiliation.role!
- )
- await userEvent.type(
- screen.getByRole('combobox', { name: 'Department' }),
- userEmailData.affiliation.department!
- )
- await userEvent.click(
- screen.getByRole('button', {
- name: 'Add new email',
- })
- )
- await confirmCodeForEmail('user@autocomplete.edu')
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- screen.getByText(userEmailDataCopy.affiliation.institution.name, {
- exact: false,
- })
- screen.getByText(userEmailDataCopy.affiliation.role!, { exact: false })
- screen.getByText(userEmailDataCopy.affiliation.department!, {
- exact: false,
- })
- })
- describe('when domain is captured by a group', function () {
- describe('and managed users is not 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,
- group: {
- domainCaptureEnabled: true,
- ssoConfig: {
- enabled: true,
- },
- },
- }
- fetchMock.get('express:/institutions/domains', [institution])
- })
- it('can add email address via SSO', async function () {
- // note: this UI is a WIP
- 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 managed users is 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,
- group: {
- domainCaptureEnabled: true,
- managedUsersEnabled: true,
- ssoConfig: {
- enabled: true,
- },
- },
- }
- fetchMock.get('express:/institutions/domains', [institution])
- })
- it('renders error', async function () {
- // note: this UI is a WIP
- 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('if Commons SSO is enabled and managed users is not enabled, Commons takes priority over group UI', function () {
- beforeEach(async function () {
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- const institution = {
- university: {
- id: 1234,
- ssoEnabled: true,
- name: 'Auto Complete University',
- },
- hostname: 'autocomplete.edu',
- confirmed: true,
- group: {
- domainCaptureEnabled: true,
- ssoConfig: {
- enabled: true,
- },
- },
- }
- fetchMock.get('express:/institutions/domains', [institution])
- })
- it('renders Commons UI', 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: 'Link accounts and add email',
- })
- })
- })
- describe('if Commons SSO is enabled and managed users is enabled, group domain capture takes priority', function () {
- beforeEach(async function () {
- await fetchMock.callHistory.flush(true)
- fetchMock.removeRoutes().clearHistory()
- const institution = {
- university: {
- id: 1234,
- ssoEnabled: true,
- name: 'Auto Complete University',
- },
- hostname: 'autocomplete.edu',
- confirmed: true,
- group: {
- domainCaptureEnabled: true,
- managedUsersEnabled: true,
- ssoConfig: {
- enabled: true,
- },
- },
- }
- fetchMock.get('express:/institutions/domains', [institution])
- })
- it('renders group domain-capture error instead of Commons UI', 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 }
- )
- expect(
- screen.queryByRole('button', {
- name: 'Link accounts and add email',
- })
- ).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
- })
- })
- })
- })
- })
|