mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Merge pull request #12278 from overleaf/ii-change-email-confirmation
[web] Show confirmation modal when making an email primary GitOrigin-RevId: eb67fc37c18a5ecd59973baa27ee9ef8e4b67423
This commit is contained in:
parent
3a071c247a
commit
122d2310e6
8 changed files with 262 additions and 143 deletions
|
@ -134,6 +134,7 @@
|
||||||
"confirm_affiliation": "",
|
"confirm_affiliation": "",
|
||||||
"confirm_affiliation_to_relink_dropbox": "",
|
"confirm_affiliation_to_relink_dropbox": "",
|
||||||
"confirm_new_password": "",
|
"confirm_new_password": "",
|
||||||
|
"confirm_primary_email_change": "",
|
||||||
"conflicting_paths_found": "",
|
"conflicting_paths_found": "",
|
||||||
"connected_users": "",
|
"connected_users": "",
|
||||||
"contact_message_label": "",
|
"contact_message_label": "",
|
||||||
|
@ -183,6 +184,7 @@
|
||||||
"discount_of": "",
|
"discount_of": "",
|
||||||
"dismiss": "",
|
"dismiss": "",
|
||||||
"dismiss_error_popup": "",
|
"dismiss_error_popup": "",
|
||||||
|
"do_you_want_to_change_your_primary_email_address_to": "",
|
||||||
"do_you_want_to_overwrite_them": "",
|
"do_you_want_to_overwrite_them": "",
|
||||||
"documentation": "",
|
"documentation": "",
|
||||||
"doesnt_match": "",
|
"doesnt_match": "",
|
||||||
|
@ -451,6 +453,7 @@
|
||||||
"log_entry_maximum_entries_see_full_logs": "",
|
"log_entry_maximum_entries_see_full_logs": "",
|
||||||
"log_entry_maximum_entries_title": "",
|
"log_entry_maximum_entries_title": "",
|
||||||
"log_hint_extra_info": "",
|
"log_hint_extra_info": "",
|
||||||
|
"log_in_with_primary_email_address": "",
|
||||||
"log_viewer_error": "",
|
"log_viewer_error": "",
|
||||||
"login_with_service": "",
|
"login_with_service": "",
|
||||||
"logs_and_output_files": "",
|
"logs_and_output_files": "",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import MakePrimary from './actions/make-primary'
|
import MakePrimary from './actions/make-primary/make-primary'
|
||||||
import Remove from './actions/remove'
|
import Remove from './actions/remove'
|
||||||
import useAsync from '../../../../shared/hooks/use-async'
|
import useAsync from '../../../../shared/hooks/use-async'
|
||||||
import { useUserEmailsContext } from '../../context/user-email-context'
|
import { useUserEmailsContext } from '../../context/user-email-context'
|
||||||
|
|
|
@ -1,112 +0,0 @@
|
||||||
import Tooltip from '../../../../../shared/components/tooltip'
|
|
||||||
import { Button } from 'react-bootstrap'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import {
|
|
||||||
inReconfirmNotificationPeriod,
|
|
||||||
institutionAlreadyLinked,
|
|
||||||
} from '../../../utils/selectors'
|
|
||||||
import { postJSON } from '../../../../../infrastructure/fetch-json'
|
|
||||||
import {
|
|
||||||
State,
|
|
||||||
useUserEmailsContext,
|
|
||||||
} from '../../../context/user-email-context'
|
|
||||||
import { UserEmailData } from '../../../../../../../types/user-email'
|
|
||||||
import { UseAsyncReturnType } from '../../../../../shared/hooks/use-async'
|
|
||||||
import { ssoAvailableForInstitution } from '../../../utils/sso'
|
|
||||||
|
|
||||||
const getDescription = (
|
|
||||||
t: (s: string) => string,
|
|
||||||
state: State,
|
|
||||||
userEmailData: UserEmailData
|
|
||||||
) => {
|
|
||||||
if (inReconfirmNotificationPeriod(userEmailData)) {
|
|
||||||
return t('please_reconfirm_your_affiliation_before_making_this_primary')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userEmailData.confirmedAt) {
|
|
||||||
return t('make_email_primary_description')
|
|
||||||
}
|
|
||||||
|
|
||||||
const ssoAvailable = ssoAvailableForInstitution(
|
|
||||||
userEmailData.affiliation?.institution || null
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!institutionAlreadyLinked(state, userEmailData) && ssoAvailable) {
|
|
||||||
return t('please_link_before_making_primary')
|
|
||||||
}
|
|
||||||
|
|
||||||
return t('please_confirm_your_email_before_making_it_default')
|
|
||||||
}
|
|
||||||
|
|
||||||
function PrimaryButton({ children, disabled, onClick }: Button.ButtonProps) {
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
bsSize="small"
|
|
||||||
bsStyle={null}
|
|
||||||
className="btn-secondary-info btn-secondary"
|
|
||||||
disabled={disabled}
|
|
||||||
onClick={onClick}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
type MakePrimaryProps = {
|
|
||||||
userEmailData: UserEmailData
|
|
||||||
makePrimaryAsync: UseAsyncReturnType
|
|
||||||
}
|
|
||||||
|
|
||||||
function MakePrimary({ userEmailData, makePrimaryAsync }: MakePrimaryProps) {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const { state, makePrimary } = useUserEmailsContext()
|
|
||||||
|
|
||||||
const handleSetDefaultUserEmail = () => {
|
|
||||||
makePrimaryAsync
|
|
||||||
.runAsync(
|
|
||||||
postJSON('/user/emails/default', {
|
|
||||||
body: {
|
|
||||||
email: userEmailData.email,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
makePrimary(userEmailData.email)
|
|
||||||
})
|
|
||||||
.catch(() => {})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userEmailData.default) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (makePrimaryAsync.isLoading) {
|
|
||||||
return <PrimaryButton disabled>{t('sending')}...</PrimaryButton>
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip
|
|
||||||
id={`make-primary-${userEmailData.email}`}
|
|
||||||
description={getDescription(t, state, userEmailData)}
|
|
||||||
>
|
|
||||||
{/*
|
|
||||||
Disabled buttons don't work with tooltips, due to pointer-events: none,
|
|
||||||
so create a wrapper for the tooltip
|
|
||||||
*/}
|
|
||||||
<span>
|
|
||||||
<PrimaryButton
|
|
||||||
disabled={
|
|
||||||
!userEmailData.confirmedAt ||
|
|
||||||
state.isLoading ||
|
|
||||||
inReconfirmNotificationPeriod(userEmailData)
|
|
||||||
}
|
|
||||||
onClick={handleSetDefaultUserEmail}
|
|
||||||
>
|
|
||||||
{t('make_primary')}
|
|
||||||
</PrimaryButton>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default MakePrimary
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
import { useTranslation, Trans } from 'react-i18next'
|
||||||
|
import { Modal, Button } from 'react-bootstrap'
|
||||||
|
import AccessibleModal from '../../../../../../shared/components/accessible-modal'
|
||||||
|
import { MergeAndOverride } from '../../../../../../../../types/utils'
|
||||||
|
|
||||||
|
type ConfirmationModalProps = MergeAndOverride<
|
||||||
|
React.ComponentProps<typeof AccessibleModal>,
|
||||||
|
{
|
||||||
|
email: string
|
||||||
|
isConfirmDisabled: boolean
|
||||||
|
onConfirm: () => void
|
||||||
|
onHide: () => void
|
||||||
|
}
|
||||||
|
>
|
||||||
|
|
||||||
|
function ConfirmationModal({
|
||||||
|
email,
|
||||||
|
isConfirmDisabled,
|
||||||
|
show,
|
||||||
|
onConfirm,
|
||||||
|
onHide,
|
||||||
|
}: ConfirmationModalProps) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AccessibleModal show={show} onHide={onHide}>
|
||||||
|
<Modal.Header closeButton>
|
||||||
|
<Modal.Title>{t('confirm_primary_email_change')}</Modal.Title>
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body className="modal-body-share">
|
||||||
|
<p>
|
||||||
|
<Trans
|
||||||
|
i18nKey="do_you_want_to_change_your_primary_email_address_to"
|
||||||
|
components={{ b: <b /> }}
|
||||||
|
values={{ email }}
|
||||||
|
/>
|
||||||
|
</p>
|
||||||
|
<p className="mb-0">{t('log_in_with_primary_email_address')}</p>
|
||||||
|
</Modal.Body>
|
||||||
|
<Modal.Footer>
|
||||||
|
<Button
|
||||||
|
bsStyle={null}
|
||||||
|
className="btn-secondary-info btn-secondary"
|
||||||
|
onClick={onHide}
|
||||||
|
>
|
||||||
|
{t('cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
bsStyle={null}
|
||||||
|
className="btn-primary"
|
||||||
|
disabled={isConfirmDisabled}
|
||||||
|
onClick={onConfirm}
|
||||||
|
>
|
||||||
|
{t('confirm')}
|
||||||
|
</Button>
|
||||||
|
</Modal.Footer>
|
||||||
|
</AccessibleModal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConfirmationModal
|
|
@ -0,0 +1,116 @@
|
||||||
|
import { useState } from 'react'
|
||||||
|
import Tooltip from '../../../../../../shared/components/tooltip'
|
||||||
|
import PrimaryButton from './primary-button'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import {
|
||||||
|
inReconfirmNotificationPeriod,
|
||||||
|
institutionAlreadyLinked,
|
||||||
|
} from '../../../../utils/selectors'
|
||||||
|
import { postJSON } from '../../../../../../infrastructure/fetch-json'
|
||||||
|
import {
|
||||||
|
State,
|
||||||
|
useUserEmailsContext,
|
||||||
|
} from '../../../../context/user-email-context'
|
||||||
|
import { UserEmailData } from '../../../../../../../../types/user-email'
|
||||||
|
import { UseAsyncReturnType } from '../../../../../../shared/hooks/use-async'
|
||||||
|
import { ssoAvailableForInstitution } from '../../../../utils/sso'
|
||||||
|
import ConfirmationModal from './confirmation-modal'
|
||||||
|
|
||||||
|
const getDescription = (
|
||||||
|
t: (s: string) => string,
|
||||||
|
state: State,
|
||||||
|
userEmailData: UserEmailData
|
||||||
|
) => {
|
||||||
|
if (inReconfirmNotificationPeriod(userEmailData)) {
|
||||||
|
return t('please_reconfirm_your_affiliation_before_making_this_primary')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userEmailData.confirmedAt) {
|
||||||
|
return t('make_email_primary_description')
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssoAvailable = ssoAvailableForInstitution(
|
||||||
|
userEmailData.affiliation?.institution || null
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!institutionAlreadyLinked(state, userEmailData) && ssoAvailable) {
|
||||||
|
return t('please_link_before_making_primary')
|
||||||
|
}
|
||||||
|
|
||||||
|
return t('please_confirm_your_email_before_making_it_default')
|
||||||
|
}
|
||||||
|
|
||||||
|
type MakePrimaryProps = {
|
||||||
|
userEmailData: UserEmailData
|
||||||
|
makePrimaryAsync: UseAsyncReturnType
|
||||||
|
}
|
||||||
|
|
||||||
|
function MakePrimary({ userEmailData, makePrimaryAsync }: MakePrimaryProps) {
|
||||||
|
const [show, setShow] = useState(false)
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { state, makePrimary } = useUserEmailsContext()
|
||||||
|
|
||||||
|
const handleShowModal = () => setShow(true)
|
||||||
|
const handleHideModal = () => setShow(false)
|
||||||
|
const handleSetDefaultUserEmail = () => {
|
||||||
|
handleHideModal()
|
||||||
|
|
||||||
|
makePrimaryAsync
|
||||||
|
.runAsync(
|
||||||
|
postJSON('/user/emails/default', {
|
||||||
|
body: {
|
||||||
|
email: userEmailData.email,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
makePrimary(userEmailData.email)
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userEmailData.default) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const isConfirmDisabled = Boolean(
|
||||||
|
!userEmailData.confirmedAt ||
|
||||||
|
state.isLoading ||
|
||||||
|
inReconfirmNotificationPeriod(userEmailData)
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{makePrimaryAsync.isLoading ? (
|
||||||
|
<PrimaryButton disabled>{t('sending')}...</PrimaryButton>
|
||||||
|
) : (
|
||||||
|
<Tooltip
|
||||||
|
id={`make-primary-${userEmailData.email}`}
|
||||||
|
description={getDescription(t, state, userEmailData)}
|
||||||
|
>
|
||||||
|
{/*
|
||||||
|
Disabled buttons don't work with tooltips, due to pointer-events: none,
|
||||||
|
so create a wrapper for the tooltip
|
||||||
|
*/}
|
||||||
|
<span>
|
||||||
|
<PrimaryButton
|
||||||
|
disabled={isConfirmDisabled}
|
||||||
|
onClick={handleShowModal}
|
||||||
|
>
|
||||||
|
{t('make_primary')}
|
||||||
|
</PrimaryButton>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
<ConfirmationModal
|
||||||
|
email={userEmailData.email}
|
||||||
|
isConfirmDisabled={isConfirmDisabled}
|
||||||
|
show={show}
|
||||||
|
onHide={handleHideModal}
|
||||||
|
onConfirm={handleSetDefaultUserEmail}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MakePrimary
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { Button } from 'react-bootstrap'
|
||||||
|
|
||||||
|
function PrimaryButton({ children, disabled, onClick }: Button.ButtonProps) {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
bsSize="small"
|
||||||
|
bsStyle={null}
|
||||||
|
className="btn-secondary-info btn-secondary"
|
||||||
|
disabled={disabled}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PrimaryButton
|
|
@ -255,6 +255,7 @@
|
||||||
"confirm_affiliation_to_relink_dropbox": "Please confirm you are still at the institution and on their license, or upgrade your account in order to relink your Dropbox account.",
|
"confirm_affiliation_to_relink_dropbox": "Please confirm you are still at the institution and on their license, or upgrade your account in order to relink your Dropbox account.",
|
||||||
"confirm_email": "Confirm Email",
|
"confirm_email": "Confirm Email",
|
||||||
"confirm_new_password": "Confirm New Password",
|
"confirm_new_password": "Confirm New Password",
|
||||||
|
"confirm_primary_email_change": "Confirm primary email change",
|
||||||
"confirmation_link_broken": "Sorry, something is wrong with your confirmation link. Please try copy and pasting the link from the bottom of your confirmation email.",
|
"confirmation_link_broken": "Sorry, something is wrong with your confirmation link. Please try copy and pasting the link from the bottom of your confirmation email.",
|
||||||
"confirmation_token_invalid": "Sorry, your confirmation token is invalid or has expired. Please request a new email confirmation link.",
|
"confirmation_token_invalid": "Sorry, your confirmation token is invalid or has expired. Please request a new email confirmation link.",
|
||||||
"confirming": "Confirming",
|
"confirming": "Confirming",
|
||||||
|
@ -342,6 +343,7 @@
|
||||||
"dismiss_error_popup": "Dismiss first error alert",
|
"dismiss_error_popup": "Dismiss first error alert",
|
||||||
"do_not_have_acct_or_do_not_want_to_link": "If you don’t have an <b>__appName__</b> account, or if you don’t want to link to your <b>__institutionName__</b> account, please click <b>__clickText__</b>.",
|
"do_not_have_acct_or_do_not_want_to_link": "If you don’t have an <b>__appName__</b> account, or if you don’t want to link to your <b>__institutionName__</b> account, please click <b>__clickText__</b>.",
|
||||||
"do_not_link_accounts": "Don’t link accounts",
|
"do_not_link_accounts": "Don’t link accounts",
|
||||||
|
"do_you_want_to_change_your_primary_email_address_to": "Do you want to change your primary email address to <b>__email__</b>?",
|
||||||
"do_you_want_to_overwrite_them": "Do you want to overwrite them?",
|
"do_you_want_to_overwrite_them": "Do you want to overwrite them?",
|
||||||
"document_history": "Document history",
|
"document_history": "Document history",
|
||||||
"documentation": "Documentation",
|
"documentation": "Documentation",
|
||||||
|
@ -854,6 +856,7 @@
|
||||||
"log_in_with": "Log in with __provider__",
|
"log_in_with": "Log in with __provider__",
|
||||||
"log_in_with_email": "Log in with __email__",
|
"log_in_with_email": "Log in with __email__",
|
||||||
"log_in_with_existing_institution_email": "Please log in with your existing <b>__appName__</b> account in order to get your <b>__appName__</b> and <b>__institutionName__</b> institutional accounts linked.",
|
"log_in_with_existing_institution_email": "Please log in with your existing <b>__appName__</b> account in order to get your <b>__appName__</b> and <b>__institutionName__</b> institutional accounts linked.",
|
||||||
|
"log_in_with_primary_email_address": "This will be the email address to use if you log in with an email address and password. Important __appName__ notifications will be sent to this email address.",
|
||||||
"log_out": "Log Out",
|
"log_out": "Log Out",
|
||||||
"log_out_from": "Log out from __email__",
|
"log_out_from": "Log out from __email__",
|
||||||
"log_viewer_error": "There was a problem displaying this project’s compilation errors and logs.",
|
"log_viewer_error": "There was a problem displaying this project’s compilation errors and logs.",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import {
|
||||||
render,
|
render,
|
||||||
screen,
|
screen,
|
||||||
waitForElementToBeRemoved,
|
waitForElementToBeRemoved,
|
||||||
|
within,
|
||||||
fireEvent,
|
fireEvent,
|
||||||
} from '@testing-library/react'
|
} from '@testing-library/react'
|
||||||
import userEvent from '@testing-library/user-event'
|
import userEvent from '@testing-library/user-event'
|
||||||
|
@ -160,45 +161,74 @@ describe('email actions - make primary', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('shows loader when making email primary and removes button', async function () {
|
describe('make an email primary', function () {
|
||||||
fetchMock
|
const confirmPrimaryEmail = async () => {
|
||||||
.get('/user/emails?ensureAffiliation=true', [userEmailData])
|
const button = await screen.findByRole('button', {
|
||||||
.post('/user/emails/default', 200)
|
name: /make primary/i,
|
||||||
const userEmailDataCopy = { ...userEmailData }
|
})
|
||||||
render(<EmailsSection />)
|
fireEvent.click(button)
|
||||||
|
|
||||||
const button = await screen.findByRole('button', { name: /make primary/i })
|
const withinModal = within(screen.getByRole('dialog'))
|
||||||
fireEvent.click(button)
|
fireEvent.click(withinModal.getByRole('button', { name: /confirm/i }))
|
||||||
|
expect(screen.queryByRole('dialog')).to.be.null
|
||||||
|
|
||||||
expect(screen.queryByRole('button', { name: /make primary/i })).to.be.null
|
await waitForElementToBeRemoved(() =>
|
||||||
|
screen.getByRole('button', { name: /sending/i, hidden: true })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
userEmailDataCopy.default = true
|
it('shows confirmation modal and closes it', async function () {
|
||||||
|
fetchMock.get('/user/emails?ensureAffiliation=true', [userEmailData])
|
||||||
|
render(<EmailsSection />)
|
||||||
|
|
||||||
await waitForElementToBeRemoved(() =>
|
const button = await screen.findByRole('button', {
|
||||||
screen.getByRole('button', { name: /sending/i })
|
name: /make primary/i,
|
||||||
)
|
})
|
||||||
|
fireEvent.click(button)
|
||||||
|
|
||||||
expect(
|
const withinModal = within(screen.getByRole('dialog'))
|
||||||
screen.queryByText(/an error has occurred while performing your request/i)
|
withinModal.getByText(
|
||||||
).to.be.null
|
/do you want to change your primary email address to .*/i
|
||||||
expect(screen.queryByRole('button', { name: /make primary/i })).to.be.null
|
)
|
||||||
})
|
withinModal.getByText(
|
||||||
|
/this will be the email address to use if you log in with an email address and password/i
|
||||||
|
)
|
||||||
|
withinModal.getByText(
|
||||||
|
/important .* notifications will be sent to this email address/i
|
||||||
|
)
|
||||||
|
withinModal.getByRole('button', { name: /confirm/i })
|
||||||
|
|
||||||
it('shows error when making email primary', async function () {
|
fireEvent.click(withinModal.getByRole('button', { name: /cancel/i }))
|
||||||
fetchMock
|
expect(screen.queryByRole('dialog')).to.be.null
|
||||||
.get('/user/emails?ensureAffiliation=true', [userEmailData])
|
})
|
||||||
.post('/user/emails/default', 503)
|
|
||||||
render(<EmailsSection />)
|
|
||||||
|
|
||||||
const button = await screen.findByRole('button', { name: /make primary/i })
|
it('shows loader and removes button', async function () {
|
||||||
fireEvent.click(button)
|
fetchMock
|
||||||
|
.get('/user/emails?ensureAffiliation=true', [userEmailData])
|
||||||
|
.post('/user/emails/default', 200)
|
||||||
|
render(<EmailsSection />)
|
||||||
|
|
||||||
await waitForElementToBeRemoved(() =>
|
await confirmPrimaryEmail()
|
||||||
screen.getByRole('button', { name: /sending/i })
|
|
||||||
)
|
|
||||||
|
|
||||||
screen.getByText(/sorry, something went wrong/i)
|
expect(
|
||||||
screen.getByRole('button', { name: /make primary/i })
|
screen.queryByText(
|
||||||
|
/an error has occurred while performing your request/i
|
||||||
|
)
|
||||||
|
).to.be.null
|
||||||
|
expect(screen.queryByRole('button', { name: /make primary/i })).to.be.null
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows error', async function () {
|
||||||
|
fetchMock
|
||||||
|
.get('/user/emails?ensureAffiliation=true', [userEmailData])
|
||||||
|
.post('/user/emails/default', 503)
|
||||||
|
render(<EmailsSection />)
|
||||||
|
|
||||||
|
await confirmPrimaryEmail()
|
||||||
|
|
||||||
|
screen.getByText(/sorry, something went wrong/i)
|
||||||
|
await screen.findByRole('button', { name: /make primary/i })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue