| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125 |
- 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,
- 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
- })
- })
- })
- })
- })
|