Merge pull request #33610 from overleaf/jel-hostname-capturedByGroup

[web] Check `capturedByGroup` when adding new email

GitOrigin-RevId: f9ef3d4cc7387dc0139a70aecd6cfcb20170abc6
This commit is contained in:
Jessica Lawshe
2026-05-19 09:17:10 -05:00
committed by Copybot
parent 2f32b9d61e
commit 9acf3b8e7f
7 changed files with 372 additions and 44 deletions
@@ -22,6 +22,17 @@ import { ConfirmEmailForm } from '@/features/settings/components/emails/confirm-
import RecaptchaConditions from '@/shared/components/recaptcha-conditions'
import SsoLinkingInfoGroup from './add-email/sso-linking-info-group'
import Notification from '@/shared/components/notification'
import { useFeatureFlag } from '@/shared/context/split-test-context'
function isDomainCapturedByGroup(
domainInfo: DomainInfo,
domainCapturedByGroupRolloutFlagEnabled: boolean
): boolean {
return domainCapturedByGroupRolloutFlagEnabled
? (domainInfo.capturedByGroup && domainInfo.group?.domainCaptureEnabled) ||
false
: domainInfo.group?.domainCaptureEnabled || false
}
function AddEmail() {
const { t } = useTranslation()
@@ -49,6 +60,10 @@ function AddEmail() {
const emailAddressLimit = getMeta('ol-emailAddressLimit') || 10
const { ref: recaptchaRef, getReCaptchaToken } = useRecaptcha()
const domainCapturedByGroupRolloutFlagEnabled = useFeatureFlag(
'domain-captured-by-group'
)
useEffect(() => {
setUserEmailsContextLoading(isLoading)
}, [setUserEmailsContextLoading, isLoading])
@@ -196,8 +211,15 @@ function AddEmail() {
)
}
const isDomainCaptured = newEmailMatchedDomain
? isDomainCapturedByGroup(
newEmailMatchedDomain,
domainCapturedByGroupRolloutFlagEnabled
)
: false
const isSsoAvailableForDomain =
newEmailMatchedDomain && ssoAvailableForDomain(newEmailMatchedDomain)
newEmailMatchedDomain &&
ssoAvailableForDomain(newEmailMatchedDomain, isDomainCaptured)
return (
<form>
@@ -243,6 +265,7 @@ function AddEmail() {
<AddEmailViaSSO
email={newEmail}
domainInfo={newEmailMatchedDomain}
isDomainCaptured={isDomainCaptured}
userInstitutions={state.data.linkedInstitutionIds}
/>
</div>
@@ -259,15 +282,14 @@ function AddEmailViaSSO({
email,
domainInfo,
userInstitutions,
isDomainCaptured,
}: {
email: string
domainInfo: DomainInfo
userInstitutions: string[]
isDomainCaptured: boolean
}) {
if (
domainInfo.group?.domainCaptureEnabled &&
domainInfo.group?.managedUsersEnabled
) {
if (isDomainCaptured && domainInfo.group?.managedUsersEnabled) {
return (
<Notification
type="error"
@@ -298,10 +320,7 @@ function AddEmailViaSSO({
)
}
return <SsoLinkingInfo email={email} domainInfo={domainInfo} />
} else if (
domainInfo.group?.domainCaptureEnabled &&
domainInfo.group?.ssoConfig?.enabled
) {
} else if (isDomainCaptured && domainInfo.group?.ssoConfig?.enabled) {
return <SsoLinkingInfoGroup domainInfo={domainInfo} />
}
}
@@ -27,6 +27,7 @@ function matchLocalAndDomain(emailHint: string) {
export type DomainInfo = {
hostname: string
confirmed?: boolean
capturedByGroup?: boolean
university: {
id: number
name: string
@@ -3,7 +3,8 @@ import { DomainInfo } from '../components/emails/add-email/input'
import { Institution } from '../../../../../types/institution'
export const ssoAvailableForDomain = (
domain: DomainInfo | null
domain: DomainInfo | null,
isDomainCapturedByGroup: boolean
): domain is DomainInfo => {
const { hasSamlBeta, hasSamlFeature } = getMeta('ol-ExposedSettings')
if (!hasSamlFeature || !domain || !domain.confirmed || !domain.university) {
@@ -13,7 +14,7 @@ export const ssoAvailableForDomain = (
return true
}
if (domain.group?.ssoConfig?.enabled) {
if (isDomainCapturedByGroup && domain.group?.ssoConfig?.enabled) {
return true
}
@@ -14,6 +14,7 @@ import { Affiliation } from '../../../../../../types/affiliation'
import withMarkup from '../../../../helpers/with-markup'
import getMeta from '@/utils/meta'
import { clearDomainCache } from '../../../../../../frontend/js/features/settings/components/emails/add-email/input'
import { SplitTestProvider } from '@/shared/context/split-test-context'
const userEmailData: UserEmailData & { affiliation: Affiliation } = {
affiliation: {
@@ -57,6 +58,14 @@ const institutionDomainData = [
},
] as const
function renderEmailsSection() {
return render(<EmailsSection />, {
wrapper: ({ children }) => (
<SplitTestProvider>{children}</SplitTestProvider>
),
})
}
function resetFetchMock() {
fetchMock.removeRoutes().clearHistory()
fetchMock.get('express:/institutions/domains', [])
@@ -94,14 +103,14 @@ describe('<EmailsSection />', function () {
it('renders "add another email" button', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
await screen.findByRole('button', { name: 'Add another email' })
})
it('renders input', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
await fetchMock.callHistory.flush(true)
const button = await screen.findByRole<HTMLButtonElement>('button', {
@@ -116,7 +125,7 @@ describe('<EmailsSection />', function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
fetchMock.get(`/institutions/domains?hostname=email.com&limit=1`, 200)
fetchMock.get(`/institutions/domains?hostname=email&limit=1`, 200)
render(<EmailsSection />)
renderEmailsSection()
await fetchMock.callHistory.flush(true)
const button = await screen.findByRole<HTMLButtonElement>('button', {
@@ -159,7 +168,7 @@ describe('<EmailsSection />', function () {
it('renders "add new email" button', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -175,7 +184,7 @@ describe('<EmailsSection />', function () {
emails.push({ email: `bar${i}@overleaf.com` })
}
fetchMock.get('/user/emails?ensureAffiliation=true', emails)
render(<EmailsSection />)
renderEmailsSection()
const findByTextWithMarkup = withMarkup(screen.findByText)
await findByTextWithMarkup(
@@ -188,7 +197,7 @@ describe('<EmailsSection />', function () {
it('adds new email address', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
'button',
@@ -232,7 +241,7 @@ describe('<EmailsSection />', function () {
it('fails to add add new email address', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const addAnotherEmailBtn = await screen.findByRole<HTMLButtonElement>(
'button',
@@ -271,7 +280,7 @@ describe('<EmailsSection />', function () {
it('can link email address to an existing SSO institution', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -295,7 +304,7 @@ describe('<EmailsSection />', function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [
{ email: 'bar@autocomplete.edu', samlProviderId: '1234' },
])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -321,7 +330,7 @@ describe('<EmailsSection />', function () {
const country = 'Germany'
const customDepartment = 'Custom department'
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -424,7 +433,7 @@ describe('<EmailsSection />', function () {
it('autocompletes institution name', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -480,7 +489,7 @@ describe('<EmailsSection />', function () {
const countryCode = 'de'
const newUniversity = 'Abcdef'
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -596,7 +605,7 @@ describe('<EmailsSection />', function () {
]
const hostnameFirstChar = institutionDomainDataCopy[0].hostname.charAt(0)
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -669,7 +678,7 @@ describe('<EmailsSection />', function () {
]
const hostnameFirstChar = institutionDomainDataCopy[0].hostname.charAt(0)
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -766,7 +775,7 @@ describe('<EmailsSection />', function () {
it('can add email address via SSO', async function () {
// note: this UI is a WIP
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -809,7 +818,7 @@ describe('<EmailsSection />', function () {
it('renders error', async function () {
// note: this UI is a WIP
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -855,7 +864,7 @@ describe('<EmailsSection />', function () {
it('renders Commons UI', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -900,7 +909,7 @@ describe('<EmailsSection />', function () {
it('renders group domain-capture error instead of Commons UI', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
render(<EmailsSection />)
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
@@ -925,5 +934,192 @@ describe('<EmailsSection />', function () {
).to.be.null
})
})
describe('when the domain-captured-by-group feature flag is enabled', function () {
beforeEach(function () {
window.metaAttributesCache.set('ol-splitTestVariants', {
'domain-captured-by-group': 'enabled',
})
})
afterEach(function () {
window.metaAttributesCache.set('ol-splitTestVariants', {})
})
describe('and capturedByGroup is true with managedUsersEnabled', function () {
beforeEach(async function () {
await fetchMock.callHistory.flush(true)
fetchMock.removeRoutes().clearHistory()
const institution = {
university: {
id: 1234,
ssoEnabled: false,
name: 'Auto Complete University',
},
hostname: 'autocomplete.edu',
confirmed: true,
capturedByGroup: true,
group: {
domainCaptureEnabled: true,
managedUsersEnabled: true,
ssoConfig: { enabled: true },
},
}
fetchMock.get('express:/institutions/domains', [institution])
})
it('renders the domain-capture error', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
})
await userEvent.click(button)
const input = screen.getByRole('textbox', { name: 'Email' })
fireEvent.change(input, {
target: { value: 'user@autocomplete.edu' },
})
const notification = await screen.findByRole('alert')
within(notification).getByText(
'Your company email address has been registered under a verified domain, and cannot be added as a secondary email.',
{ exact: false }
)
})
})
describe('and capturedByGroup is false with managedUsersEnabled (domainCaptureEnabled alone is not enough)', function () {
beforeEach(async function () {
await fetchMock.callHistory.flush(true)
fetchMock.removeRoutes().clearHistory()
const institution = {
university: {
id: 1234,
ssoEnabled: false,
name: 'Auto Complete University',
},
hostname: 'autocomplete.edu',
confirmed: true,
capturedByGroup: false,
group: {
domainCaptureEnabled: true,
managedUsersEnabled: true,
ssoConfig: { enabled: true },
},
}
fetchMock.get('express:/institutions/domains', [institution])
})
it('does not render the domain-capture error and shows regular institution fields', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
})
await userEvent.click(button)
const input = screen.getByRole('textbox', { name: 'Email' })
fireEvent.change(input, {
target: { value: 'user@autocomplete.edu' },
})
await screen.findByRole('button', { name: 'Add new email' })
expect(screen.queryByRole('alert')).to.be.null
})
})
describe('and capturedByGroup is true with ssoConfig enabled (no managedUsers)', function () {
beforeEach(async function () {
await fetchMock.callHistory.flush(true)
fetchMock.removeRoutes().clearHistory()
const institution = {
university: {
id: 1234,
ssoEnabled: false,
name: 'Auto Complete University',
},
hostname: 'autocomplete.edu',
confirmed: true,
capturedByGroup: true,
group: {
domainCaptureEnabled: true,
managedUsersEnabled: false,
ssoConfig: { enabled: true },
},
}
fetchMock.get('express:/institutions/domains', [institution])
})
it('renders the group SSO unavailable message', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
})
await userEvent.click(button)
const input = screen.getByRole('textbox', { name: 'Email' })
fireEvent.change(input, {
target: { value: 'user@autocomplete.edu' },
})
await screen.findByText('This feature is currently unavailable.')
})
})
describe('and capturedByGroup is false with ssoConfig enabled', function () {
beforeEach(async function () {
await fetchMock.callHistory.flush(true)
fetchMock.removeRoutes().clearHistory()
const institution = {
university: {
id: 1234,
ssoEnabled: false,
name: 'Auto Complete University',
},
hostname: 'autocomplete.edu',
confirmed: true,
capturedByGroup: false,
group: {
domainCaptureEnabled: true,
managedUsersEnabled: false,
ssoConfig: { enabled: true },
},
}
fetchMock.get('express:/institutions/domains', [institution])
})
it('does not render SSO UI and shows regular institution fields', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [])
renderEmailsSection()
const button = await screen.findByRole<HTMLButtonElement>('button', {
name: 'Add another email',
})
await userEvent.click(button)
const input = screen.getByRole('textbox', { name: 'Email' })
fireEvent.change(input, {
target: { value: 'user@autocomplete.edu' },
})
await screen.findByRole('button', { name: 'Add new email' })
expect(screen.queryByText('This feature is currently unavailable.'))
.to.be.null
})
})
})
})
})
@@ -12,6 +12,7 @@ import { UserEmailsProvider } from '../../../../../../frontend/js/features/setti
import EmailsSection from '../../../../../../frontend/js/features/settings/components/emails-section'
import { Affiliation } from '../../../../../../types/affiliation'
import getMeta from '@/utils/meta'
import { SplitTestProvider } from '@/shared/context/split-test-context'
const userData1: UserEmailData & { affiliation: Affiliation } = {
affiliation: {
@@ -74,6 +75,14 @@ const userData2: UserEmailData & { affiliation: Affiliation } = {
default: false,
}
function renderEmailsSection() {
return render(<EmailsSection />, {
wrapper: ({ children }) => (
<SplitTestProvider>{children}</SplitTestProvider>
),
})
}
describe('user role and institution', function () {
beforeEach(function () {
Object.assign(getMeta('ol-ExposedSettings'), {
@@ -125,7 +134,7 @@ describe('user role and institution', function () {
it('fetches institution data and replaces departments dropdown on add/change', async function () {
const userEmailData = userData1
fetchMock.modifyRoute('get user emails', { response: [userEmailData] })
render(<EmailsSection />)
renderEmailsSection()
await fetchMock.callHistory.flush(true)
fetchMock.removeRoutes().clearHistory()
@@ -158,7 +167,7 @@ describe('user role and institution', function () {
.modifyRoute('get user emails', { response: [userData1] })
.get(/\/institutions\/list/, { departments: [] })
.post('/user/emails/endorse', 200)
render(<EmailsSection />)
renderEmailsSection()
const addBtn = await screen.findByRole('button', {
name: /add role and department/i,
@@ -16,6 +16,15 @@ import {
unconfirmedUserData,
} from '../../fixtures/test-user-email-data'
import getMeta from '@/utils/meta'
import { SplitTestProvider } from '@/shared/context/split-test-context'
function renderEmailsSection() {
return render(<EmailsSection />, {
wrapper: ({ children }) => (
<SplitTestProvider>{children}</SplitTestProvider>
),
})
}
describe('<EmailsSection />', function () {
beforeEach(function () {
@@ -30,13 +39,13 @@ describe('<EmailsSection />', function () {
})
it('renders translated heading', function () {
render(<EmailsSection />)
renderEmailsSection()
screen.getByRole('heading', { name: /emails and affiliations/i })
})
it('renders translated description', function () {
render(<EmailsSection />)
renderEmailsSection()
screen.getByText(/add additional email addresses/i)
screen.getByText(/to change your primary email/i)
@@ -46,14 +55,14 @@ describe('<EmailsSection />', function () {
})
it('renders a loading message when loading', async function () {
render(<EmailsSection />)
renderEmailsSection()
await screen.findByText(/loading/i)
})
it('renders an error message and hides loading message on error', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', 500)
render(<EmailsSection />)
renderEmailsSection()
await screen.findByText(
/an error has occurred while performing your request/i
@@ -63,7 +72,7 @@ describe('<EmailsSection />', function () {
it('renders user emails', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', fakeUsersData)
render(<EmailsSection />)
renderEmailsSection()
await waitFor(() => {
fakeUsersData.forEach(userData => {
@@ -74,7 +83,7 @@ describe('<EmailsSection />', function () {
it('renders primary status', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [professionalUserData])
render(<EmailsSection />)
renderEmailsSection()
await screen.findByText(`${professionalUserData.email}`)
screen.getByText('Primary')
@@ -82,14 +91,14 @@ describe('<EmailsSection />', function () {
it('shows confirmation status for unconfirmed users', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
render(<EmailsSection />)
renderEmailsSection()
await screen.findByText(/unconfirmed/i)
})
it('hides confirmation status for confirmed users', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [confirmedUserData])
render(<EmailsSection />)
renderEmailsSection()
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
expect(screen.queryByText(/please check your inbox/i)).to.be.null
@@ -97,14 +106,14 @@ describe('<EmailsSection />', function () {
it('renders resend link', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
render(<EmailsSection />)
renderEmailsSection()
await screen.findByRole('button', { name: 'Send confirmation code' })
})
it('renders professional label', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [professionalUserData])
render(<EmailsSection />)
renderEmailsSection()
const node = await screen.findByText(professionalUserData.email, {
exact: false,
@@ -115,7 +124,7 @@ describe('<EmailsSection />', function () {
it('shows loader when resending email', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
render(<EmailsSection />)
renderEmailsSection()
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
fetchMock.post('/user/emails/send-confirmation-code', 200)
@@ -145,7 +154,7 @@ describe('<EmailsSection />', function () {
it('shows error when resending email fails', async function () {
fetchMock.get('/user/emails?ensureAffiliation=true', [unconfirmedUserData])
render(<EmailsSection />)
renderEmailsSection()
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
fetchMock.post('/user/emails/send-confirmation-code', 503)
@@ -195,7 +204,7 @@ describe('<EmailsSection />', function () {
]
fetchMock.get('/user/emails?ensureAffiliation=true', emails)
render(<EmailsSection />)
renderEmailsSection()
await waitForElementToBeRemoved(() => screen.getByText(/loading/i))
@@ -0,0 +1,93 @@
import { expect } from 'chai'
import { ssoAvailableForDomain } from '../../../../../frontend/js/features/settings/utils/sso'
import { DomainInfo } from '../../../../../frontend/js/features/settings/components/emails/add-email/input'
const baseDomain: DomainInfo = {
hostname: 'example.edu',
confirmed: true,
university: {
id: 1,
name: 'Example University',
ssoEnabled: false,
ssoBeta: false,
},
group: {
domainCaptureEnabled: false,
ssoConfig: {
enabled: false,
},
},
}
describe('ssoAvailableForDomain', function () {
beforeEach(function () {
window.metaAttributesCache.set('ol-ExposedSettings', {
hasSamlFeature: true,
hasSamlBeta: false,
})
})
it('returns false when hasSamlFeature is false', function () {
window.metaAttributesCache.set('ol-ExposedSettings', {
hasSamlFeature: false,
hasSamlBeta: false,
})
expect(ssoAvailableForDomain(baseDomain, false)).to.be.false
})
it('returns false when domain is null', function () {
expect(ssoAvailableForDomain(null, false)).to.be.false
})
it('returns false when domain is not confirmed', function () {
const domain = { ...baseDomain, confirmed: false }
expect(ssoAvailableForDomain(domain, false)).to.be.false
})
it('returns true when university.ssoEnabled is true, regardless of isDomainCapturedByGroup', function () {
const domain: DomainInfo = {
...baseDomain,
university: { ...baseDomain.university, ssoEnabled: true },
}
expect(ssoAvailableForDomain(domain, false)).to.be.true
expect(ssoAvailableForDomain(domain, true)).to.be.true
})
describe('group SSO via ssoConfig', function () {
const domainWithGroupSso: DomainInfo = {
...baseDomain,
group: {
domainCaptureEnabled: true,
ssoConfig: { enabled: true },
},
}
it('returns true when isDomainCapturedByGroup is true and group ssoConfig is enabled', function () {
expect(ssoAvailableForDomain(domainWithGroupSso, true)).to.be.true
})
it('returns false when isDomainCapturedByGroup is false even if group ssoConfig is enabled', function () {
expect(ssoAvailableForDomain(domainWithGroupSso, false)).to.be.false
})
})
it('returns true when hasSamlBeta and university.ssoBeta are both true', function () {
window.metaAttributesCache.set('ol-ExposedSettings', {
hasSamlFeature: true,
hasSamlBeta: true,
})
const domain: DomainInfo = {
...baseDomain,
university: { ...baseDomain.university, ssoBeta: true },
}
expect(ssoAvailableForDomain(domain, false)).to.be.true
})
it('returns false when hasSamlBeta is false and university.ssoBeta is true', function () {
const domain: DomainInfo = {
...baseDomain,
university: { ...baseDomain.university, ssoBeta: true },
}
expect(ssoAvailableForDomain(domain, false)).to.be.false
})
})