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