✨(frontend) user can add mail domain
- user can add an externally created mail domain from UI and see the mail domain status on mail domain page and left panel links. - user can not create mailboxes to domain if mail domain status is not equal to `enabled` - update related tests and translations
@@ -8,6 +8,10 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- ✨(frontend) user can add mail domains
|
||||
|
||||
## [1.0.0] - 2024-08-09
|
||||
|
||||
### Added
|
||||
|
||||
|
Before Width: | Height: | Size: 617 B After Width: | Height: | Size: 617 B |
|
Before Width: | Height: | Size: 500 B After Width: | Height: | Size: 500 B |
|
Before Width: | Height: | Size: 429 B After Width: | Height: | Size: 429 B |
@@ -2,3 +2,4 @@ export * from './useMailDomains';
|
||||
export * from './useMailDomain';
|
||||
export * from './useCreateMailbox';
|
||||
export * from './useMailboxes';
|
||||
export * from './useCreateMailDomain';
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { APIError, errorCauses, fetchAPI } from '@/api';
|
||||
import { MailDomain } from '@/features/mail-domains';
|
||||
|
||||
import { KEY_LIST_MAIL_DOMAIN } from './useMailDomains';
|
||||
|
||||
export const createMailDomain = async (name: string): Promise<MailDomain> => {
|
||||
const response = await fetchAPI(`mail-domains/`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
name,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
'Failed to add the mail domain',
|
||||
await errorCauses(response),
|
||||
);
|
||||
}
|
||||
|
||||
return response.json() as Promise<MailDomain>;
|
||||
};
|
||||
|
||||
export function useCreateMailDomain({
|
||||
onSuccess,
|
||||
}: {
|
||||
onSuccess: (data: MailDomain) => void;
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation<MailDomain, APIError, string>({
|
||||
mutationFn: createMailDomain,
|
||||
onSuccess: (data) => {
|
||||
void queryClient.invalidateQueries({
|
||||
queryKey: [KEY_LIST_MAIL_DOMAIN],
|
||||
});
|
||||
onSuccess(data);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -13,7 +13,7 @@ type MailDomainResponse = MailDomain;
|
||||
export const getMailDomain = async ({
|
||||
slug,
|
||||
}: MailDomainParams): Promise<MailDomainResponse> => {
|
||||
const response = await fetchAPI(`mail-domains/${slug}`);
|
||||
const response = await fetchAPI(`mail-domains/${slug}/`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new APIError(
|
||||
|
||||
@@ -40,7 +40,7 @@ export const getMailDomains = async ({
|
||||
return response.json() as Promise<MailDomainsResponse>;
|
||||
};
|
||||
|
||||
export const KEY_LIST_MAIL_DOMAINS = 'mail-domains';
|
||||
export const KEY_LIST_MAIL_DOMAIN = 'mail-domains';
|
||||
|
||||
export function useMailDomains(
|
||||
param: MailDomainsParams,
|
||||
@@ -60,7 +60,7 @@ export function useMailDomains(
|
||||
number
|
||||
>({
|
||||
initialPageParam: 1,
|
||||
queryKey: [KEY_LIST_MAIL_DOMAINS, param],
|
||||
queryKey: [KEY_LIST_MAIL_DOMAIN, param],
|
||||
queryFn: ({ pageParam }) => getMailDomains({ ...param, page: pageParam }),
|
||||
getNextPageParam(lastPage, allPages) {
|
||||
return lastPage.next ? allPages.length + 1 : undefined;
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { UUID } from 'crypto';
|
||||
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
DataGrid,
|
||||
Loader,
|
||||
SortModel,
|
||||
VariantType,
|
||||
usePagination,
|
||||
} from '@openfun/cunningham-react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, Card, Text, TextErrors } from '@/components';
|
||||
import { Box, Card, Text, TextErrors, TextStyled } from '@/components';
|
||||
|
||||
import { useMailboxes } from '../api/useMailboxes';
|
||||
import { default as MailDomainsLogo } from '../assets/mail-domains-logo.svg';
|
||||
@@ -35,12 +37,6 @@ const defaultOrderingMapping: Record<string, string> = {
|
||||
email: 'local_part',
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the sorting model based on a given mapping.
|
||||
* @param {SortModelItem} sortModel The sorting model item containing field and sort direction.
|
||||
* @param {Record<string, string>} mapping The mapping object to map field names.
|
||||
* @returns {string} The formatted sorting string.
|
||||
*/
|
||||
function formatSortModel(
|
||||
sortModel: SortModelItem,
|
||||
mapping = defaultOrderingMapping,
|
||||
@@ -98,9 +94,8 @@ export function MailDomainsContent({ mailDomain }: { mailDomain: MailDomain }) {
|
||||
) : null}
|
||||
|
||||
<TopBanner
|
||||
name={mailDomain.name}
|
||||
setIsFormVisible={setIsCreateMailboxFormVisible}
|
||||
abilities={mailDomain?.abilities}
|
||||
mailDomain={mailDomain}
|
||||
showMailBoxCreationForm={setIsCreateMailboxFormVisible}
|
||||
/>
|
||||
|
||||
<Card
|
||||
@@ -150,39 +145,111 @@ export function MailDomainsContent({ mailDomain }: { mailDomain: MailDomain }) {
|
||||
}
|
||||
|
||||
const TopBanner = ({
|
||||
name,
|
||||
setIsFormVisible,
|
||||
abilities,
|
||||
mailDomain,
|
||||
showMailBoxCreationForm,
|
||||
}: {
|
||||
name: string;
|
||||
setIsFormVisible: (value: boolean) => void;
|
||||
abilities: MailDomain['abilities'];
|
||||
mailDomain: MailDomain;
|
||||
showMailBoxCreationForm: (value: boolean) => void;
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
$direction="column"
|
||||
$margin={{ all: 'big', bottom: 'tiny' }}
|
||||
$gap="1rem"
|
||||
>
|
||||
<Box
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$margin={{ all: 'big', vertical: 'xbig' }}
|
||||
$gap="2.25rem"
|
||||
$justify="space-between"
|
||||
>
|
||||
<MailDomainsLogo aria-hidden="true" />
|
||||
<Text $margin="none" as="h3" $size="h3">
|
||||
{name}
|
||||
</Text>
|
||||
<Box $direction="row" $margin="none" $gap="2.25rem">
|
||||
<MailDomainsLogo aria-hidden="true" />
|
||||
<Text $margin="none" as="h3" $size="h3">
|
||||
{mailDomain?.name}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box $margin={{ all: 'big', bottom: 'small' }} $align="flex-end">
|
||||
{abilities.post ? (
|
||||
<Button
|
||||
aria-label={t(`Create a mailbox in {{name}} domain`, { name })}
|
||||
onClick={() => setIsFormVisible(true)}
|
||||
>
|
||||
{t('Create a mailbox')}
|
||||
</Button>
|
||||
) : null}
|
||||
|
||||
<Box $direction="row" $justify="space-between">
|
||||
<AlertStatus status={mailDomain.status} />
|
||||
</Box>
|
||||
</>
|
||||
{mailDomain?.abilities.post && (
|
||||
<Box $direction="row-reverse">
|
||||
<Box $display="inline">
|
||||
<Button
|
||||
aria-label={t('Create a mailbox in {{name}} domain', {
|
||||
name: mailDomain?.name,
|
||||
})}
|
||||
disabled={mailDomain?.status !== 'enabled'}
|
||||
onClick={() => showMailBoxCreationForm(true)}
|
||||
>
|
||||
{t('Create a mailbox')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const AlertStatus = ({ status }: { status: MailDomain['status'] }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getStatusAlertProps = (status?: string) => {
|
||||
switch (status) {
|
||||
case 'pending':
|
||||
return {
|
||||
variant: VariantType.WARNING,
|
||||
message: t(
|
||||
'Your domain name is being validated. ' +
|
||||
'You will not be able to create mailboxes until your domain name has been validated by our team.',
|
||||
),
|
||||
};
|
||||
case 'disabled':
|
||||
return {
|
||||
variant: VariantType.NEUTRAL,
|
||||
message: t(
|
||||
'This domain name is deactivated. No new mailboxes can be created.',
|
||||
),
|
||||
};
|
||||
case 'failed':
|
||||
return {
|
||||
variant: VariantType.ERROR,
|
||||
message: (
|
||||
<Text $display="inline">
|
||||
{t(
|
||||
'The domain name encounters an error. Please contact our support team to solve the problem:',
|
||||
)}{' '}
|
||||
<TextStyled
|
||||
as="a"
|
||||
target="_blank"
|
||||
$display="inline"
|
||||
href="mailto:suiteterritoriale@anct.gouv.fr"
|
||||
aria-label={t(
|
||||
'Contact our support at "suiteterritoriale@anct.gouv.fr"',
|
||||
)}
|
||||
>
|
||||
suiteterritoriale@anct.gouv.fr
|
||||
</TextStyled>
|
||||
.
|
||||
</Text>
|
||||
),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const alertStatusProps = getStatusAlertProps(status);
|
||||
|
||||
if (!alertStatusProps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Alert canClose={false} type={alertStatusProps.variant}>
|
||||
<Text $display="inline">{alertStatusProps.message}</Text>
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
Loader,
|
||||
Modal,
|
||||
ModalSize,
|
||||
} from '@openfun/cunningham-react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import React from 'react';
|
||||
import { Controller, FormProvider, useForm } from 'react-hook-form';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { Box, StyledLink, Text, TextErrors } from '@/components';
|
||||
import { useCreateMailDomain } from '@/features/mail-domains';
|
||||
|
||||
import { default as MailDomainsLogo } from '../assets/mail-domains-logo.svg';
|
||||
|
||||
const FORM_ID = 'form-add-mail-domain';
|
||||
|
||||
export const ModalCreateMailDomain = () => {
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
|
||||
const createMailDomainValidationSchema = z.object({
|
||||
name: z.string().min(1, t('Example: saint-laurent.fr')),
|
||||
});
|
||||
|
||||
const methods = useForm<{ name: string }>({
|
||||
delayError: 0,
|
||||
defaultValues: {
|
||||
name: '',
|
||||
},
|
||||
mode: 'onChange',
|
||||
reValidateMode: 'onChange',
|
||||
resolver: zodResolver(createMailDomainValidationSchema),
|
||||
});
|
||||
|
||||
const {
|
||||
mutate: createMailDomain,
|
||||
isPending,
|
||||
error,
|
||||
} = useCreateMailDomain({
|
||||
onSuccess: (mailDomain) => {
|
||||
router.push(`/mail-domains/${mailDomain.slug}`);
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmitCallback = () => {
|
||||
void methods.handleSubmit(({ name }, event) => {
|
||||
event?.preventDefault();
|
||||
void createMailDomain(name);
|
||||
})();
|
||||
};
|
||||
|
||||
const causes = error?.cause?.filter((cause) => {
|
||||
const isFound = cause === 'Mail domain with this name already exists.';
|
||||
|
||||
if (isFound) {
|
||||
methods.setError('name', {
|
||||
type: 'manual',
|
||||
message: t(
|
||||
'This mail domain is already used. Please, choose another one.',
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
return !isFound;
|
||||
});
|
||||
|
||||
if (!methods) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen
|
||||
leftActions={
|
||||
<StyledLink href="/mail-domains">
|
||||
<Button color="secondary" tabIndex={-1}>
|
||||
{t('Cancel')}
|
||||
</Button>
|
||||
</StyledLink>
|
||||
}
|
||||
hideCloseButton
|
||||
closeOnClickOutside
|
||||
closeOnEsc
|
||||
onClose={() => router.push('/mail-domains')}
|
||||
rightActions={
|
||||
<Button
|
||||
onClick={onSubmitCallback}
|
||||
disabled={!methods.watch('name') || isPending}
|
||||
>
|
||||
{t('Add the domain')}
|
||||
</Button>
|
||||
}
|
||||
size={ModalSize.MEDIUM}
|
||||
title={
|
||||
<>
|
||||
<MailDomainsLogo aria-hidden="true" />
|
||||
<Text as="h3" $textAlign="center">
|
||||
{t('Add your mail domain')}
|
||||
</Text>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<FormProvider {...methods}>
|
||||
<form action="" id={FORM_ID}>
|
||||
<Controller
|
||||
control={methods.control}
|
||||
name="name"
|
||||
render={({ fieldState }) => (
|
||||
<Input
|
||||
fullWidth
|
||||
type="text"
|
||||
{...methods.register('name')}
|
||||
aria-invalid={!!fieldState.error}
|
||||
aria-required
|
||||
required
|
||||
autoComplete="off"
|
||||
label={t('Domain name')}
|
||||
state={fieldState.error ? 'error' : 'default'}
|
||||
text={
|
||||
fieldState?.error?.message
|
||||
? fieldState.error.message
|
||||
: t('Example: saint-laurent.fr')
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
{!!causes?.length ? <TextErrors causes={causes} /> : null}
|
||||
|
||||
{isPending && (
|
||||
<Box $align="center">
|
||||
<Loader />
|
||||
</Box>
|
||||
)}
|
||||
</FormProvider>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -1,11 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import IconOpenClose from '@/assets/icons/icon-open-close.svg';
|
||||
import { Box, BoxButton, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import IconOpenClose from '../../assets/icon-open-close.svg';
|
||||
|
||||
import { ItemList } from './ItemList';
|
||||
import { PanelActions } from './PanelActions';
|
||||
|
||||
@@ -39,7 +38,7 @@ export const Panel = () => {
|
||||
transition: ${transition};
|
||||
`}
|
||||
$height="inherit"
|
||||
aria-label="mail domains panel"
|
||||
aria-label={t('Mail domains panel')}
|
||||
{...closedOverridingStyles}
|
||||
>
|
||||
<BoxButton
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, BoxButton } from '@/components';
|
||||
import IconAdd from '@/assets/icons/icon-add.svg';
|
||||
import IconSort from '@/assets/icons/icon-sort.svg';
|
||||
import { Box, BoxButton, StyledLink, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { EnumMailDomainsOrdering } from '@/features/mail-domains';
|
||||
import { useMailDomainsStore } from '@/features/mail-domains/store/useMailDomainsStore';
|
||||
|
||||
import IconSort from '../../assets/icon-sort.svg';
|
||||
|
||||
export const PanelActions = () => {
|
||||
const { t } = useTranslation();
|
||||
const { changeOrdering, ordering } = useMailDomainsStore();
|
||||
@@ -42,6 +42,16 @@ export const PanelActions = () => {
|
||||
>
|
||||
<IconSort width={30} height={30} aria-hidden="true" />
|
||||
</BoxButton>
|
||||
|
||||
<StyledLink href="/mail-domains/add/">
|
||||
<Text
|
||||
$margin="auto"
|
||||
aria-label={t('Add your mail domain')}
|
||||
$theme="primary"
|
||||
>
|
||||
<IconAdd width={27} height={27} aria-hidden="true" />
|
||||
</Text>
|
||||
</StyledLink>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { Box, StyledLink, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
@@ -11,6 +12,7 @@ interface MailDomainProps {
|
||||
}
|
||||
|
||||
export const PanelMailDomains = ({ mailDomain }: MailDomainProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { colorsTokens } = useCunninghamTheme();
|
||||
const {
|
||||
query: { slug },
|
||||
@@ -18,10 +20,23 @@ export const PanelMailDomains = ({ mailDomain }: MailDomainProps) => {
|
||||
|
||||
const isActive = mailDomain.slug === slug;
|
||||
|
||||
const getStatusText = (status: MailDomain['status']) => {
|
||||
switch (status) {
|
||||
case 'pending':
|
||||
return t('[pending]');
|
||||
case 'enabled':
|
||||
return t('[enabled]');
|
||||
case 'disabled':
|
||||
return t('[disabled]');
|
||||
case 'failed':
|
||||
return t('[failed]');
|
||||
}
|
||||
};
|
||||
|
||||
const activeStyle = `
|
||||
border-right: 4px solid ${colorsTokens()['primary-600']};
|
||||
background: ${colorsTokens()['primary-400']};
|
||||
span{
|
||||
span {
|
||||
color: ${colorsTokens()['primary-text']};
|
||||
}
|
||||
`;
|
||||
@@ -31,12 +46,14 @@ export const PanelMailDomains = ({ mailDomain }: MailDomainProps) => {
|
||||
border-right: 4px solid ${colorsTokens()['primary-400']};
|
||||
background: ${colorsTokens()['primary-300']};
|
||||
|
||||
span{
|
||||
span {
|
||||
color: ${colorsTokens()['primary-text']};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const statusText = getStatusText(mailDomain.status);
|
||||
|
||||
return (
|
||||
<Box
|
||||
$margin="none"
|
||||
@@ -49,29 +66,44 @@ export const PanelMailDomains = ({ mailDomain }: MailDomainProps) => {
|
||||
>
|
||||
<StyledLink
|
||||
className="p-s pt-t pb-t"
|
||||
$css="width: 100%"
|
||||
href={`/mail-domains/${mailDomain.slug}`}
|
||||
>
|
||||
<Box $align="center" $direction="row" $gap="0.5rem">
|
||||
<IconMailDomains
|
||||
aria-hidden="true"
|
||||
color={colorsTokens()['primary-500']}
|
||||
className="p-t"
|
||||
width="52"
|
||||
style={{
|
||||
borderRadius: '10px',
|
||||
flexShrink: 0,
|
||||
background: '#fff',
|
||||
border: `1px solid ${colorsTokens()['primary-300']}`,
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
$weight="bold"
|
||||
$color={colorsTokens()['greyscale-600']}
|
||||
$css={`
|
||||
min-width: 14rem;
|
||||
<Box
|
||||
$position="relative"
|
||||
$align="center"
|
||||
$direction="row"
|
||||
$justify="space-between"
|
||||
$gap="1rem"
|
||||
>
|
||||
<Box $direction="row" $gap="0.5rem" $justify="left" $align="center">
|
||||
<IconMailDomains
|
||||
aria-hidden="true"
|
||||
color={colorsTokens()['primary-500']}
|
||||
className="p-t"
|
||||
width="52"
|
||||
style={{
|
||||
borderRadius: '10px',
|
||||
flexShrink: 0,
|
||||
background: '#fff',
|
||||
border: `1px solid ${colorsTokens()['primary-300']}`,
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
$weight="bold"
|
||||
$color={colorsTokens()['greyscale-600']}
|
||||
$css={`
|
||||
display: inline-block;
|
||||
width: 10rem;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis !important;
|
||||
`}
|
||||
>
|
||||
{mailDomain.name}
|
||||
>
|
||||
{mailDomain.name}
|
||||
</Text>
|
||||
</Box>
|
||||
<Text $size="s" $theme="greyscale">
|
||||
{statusText}
|
||||
</Text>
|
||||
</Box>
|
||||
</StyledLink>
|
||||
|
||||
@@ -6,6 +6,7 @@ export interface MailDomain {
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
slug: string;
|
||||
status: 'pending' | 'enabled' | 'failed' | 'disabled';
|
||||
abilities: {
|
||||
get: boolean;
|
||||
patch: boolean;
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="11.5" transform="rotate(-180 12 12)" fill="white" stroke="currentColor"/>
|
||||
<path d="M14.1683 16.232C14.4803 15.92 14.4803 15.416 14.1683 15.104L11.0643 12L14.1683 8.896C14.4803 8.584 14.4803 8.08 14.1683 7.768C13.8563 7.456 13.3523 7.456 13.0403 7.768L9.36834 11.44C9.05634 11.752 9.05634 12.256 9.36834 12.568L13.0403 16.24C13.3443 16.544 13.8563 16.544 14.1683 16.232Z" fill="currentColor"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 500 B |
@@ -1,13 +0,0 @@
|
||||
<svg viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_178_17837)">
|
||||
<path
|
||||
d="M11.25 3.75L6.25 8.7375H10V17.5H12.5V8.7375H16.25L11.25 3.75ZM20 21.2625V12.5H17.5V21.2625H13.75L18.75 26.25L23.75 21.2625H20Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_178_17837">
|
||||
<rect width="30" height="30" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 429 B |
@@ -1,11 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import IconOpenClose from '@/assets/icons/icon-open-close.svg';
|
||||
import { Box, BoxButton, Text } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
|
||||
import IconOpenClose from '../assets/icon-open-close.svg';
|
||||
|
||||
import { PanelActions } from './PanelActions';
|
||||
import { TeamList } from './TeamList';
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import IconAdd from '@/assets/icons/icon-add.svg';
|
||||
import IconSort from '@/assets/icons/icon-sort.svg';
|
||||
import { Box, BoxButton, StyledLink } from '@/components';
|
||||
import { useCunninghamTheme } from '@/cunningham';
|
||||
import { TeamsOrdering } from '@/features/teams/team-management/api';
|
||||
|
||||
import IconAdd from '../assets/icon-add.svg';
|
||||
import IconSort from '../assets/icon-sort.svg';
|
||||
import { useTeamStore } from '../store/useTeamsStore';
|
||||
|
||||
export const PanelActions = () => {
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"Add a member": "Ajouter un membre",
|
||||
"Add a team": "Ajouter un groupe",
|
||||
"Add members to the team": "Ajouter des membres à l'équipe",
|
||||
"Add the domain": "Ajouter le domaine",
|
||||
"Add to group": "Ajouter au groupe",
|
||||
"Add your mail domain": "Ajouter votre nom de domaine",
|
||||
"Address: National Agency for Territorial Cohesion - 20, avenue de Ségur TSA 10717 75 334 Paris Cedex 07 Paris": "Adresse : Agence Nationale de la Cohésion des Territoires - 20, avenue de Ségur TSA 10717 75 334 Paris Cedex 07",
|
||||
"Administration": "Administration",
|
||||
"All fields are mandatory.": "Tous les champs sont obligatoires.",
|
||||
@@ -28,6 +30,7 @@
|
||||
"Close the teams panel": "Fermer le panneau des groupes",
|
||||
"Compliance status": "État de conformité",
|
||||
"Confirm deletion": "Confirmer la suppression",
|
||||
"Contact our support at \"suiteterritoriale@anct.gouv.fr\"": "Contacter notre support à \"suiteterritoriale@anct.gouv.fr\"",
|
||||
"Content modal to delete the team": "Contenu modal pour supprimer le groupe",
|
||||
"Content modal to update the team": "Contenu modal pour mettre à jour le groupe",
|
||||
"Cookies placed": "Cookies déposés",
|
||||
@@ -45,12 +48,14 @@
|
||||
"Defender of Rights - Free response - 71120 75342 Paris CEDEX 07": "Défenseur des droits\nLibre réponse 71120 75342 Paris CEDEX 07",
|
||||
"Delete the team": "Supprimer le groupe",
|
||||
"Deleting the {{teamName}} team": "Suppression du groupe {{teamName}}",
|
||||
"Domain name": "Nom de domaine",
|
||||
"E-mail:": "E-mail:",
|
||||
"E.g. : jean.dupont@mail.fr": "Ex. : jean.dupont@mail.fr",
|
||||
"Email address prefix": "Préfixe de l'adresse mail",
|
||||
"Emails": "Emails",
|
||||
"Empty team icon": "Icône équipe vide",
|
||||
"Enter the new name of the selected team": "Entrez le nouveau nom du groupe sélectionné",
|
||||
"Example: saint-laurent.fr": "Exemple : saint-laurent.fr",
|
||||
"Failed to add {{name}} in the team": "Impossible d'ajouter {{name}} au groupe",
|
||||
"Failed to create the invitation for {{email}}": "Impossible de créer l'invitation pour {{email}}",
|
||||
"Find a member to add to the team": "Trouver un membre à ajouter au groupe",
|
||||
@@ -78,6 +83,7 @@
|
||||
"List members card": "Carte liste des membres",
|
||||
"Logout": "Se déconnecter",
|
||||
"Mail Domains": "Domaines de messagerie",
|
||||
"Mail domains panel": "Panel des domaines de messagerie",
|
||||
"Mailbox created!": "Boîte mail créée !",
|
||||
"Mailboxes list": "Liste des boîtes mail",
|
||||
"Marianne Logo": "Logo Marianne",
|
||||
@@ -127,6 +133,7 @@
|
||||
"Team name": "Nom du groupe",
|
||||
"Teams": "Équipes",
|
||||
"The National Agency for Territorial Cohesion undertakes to make its\n service accessible, in accordance with article 47 of law no. 2005-102\n of February 11, 2005.": "L'Agence Nationale de la Cohésion des Territoires s’engage à rendre son service accessible, conformément à l’article 47 de la loi n° 2005-102 du 11 février 2005.",
|
||||
"The domain name encounters an error. Please contact our support team to solve the problem:": "Le nom de domaine rencontre une erreur. Veuillez contacter notre support pour résoudre le problème :",
|
||||
"The member has been removed from the team": "Le membre a été supprimé de votre groupe",
|
||||
"The role has been updated": "Le rôle a bien été mis à jour",
|
||||
"The team has been removed.": "Le groupe a été supprimé.",
|
||||
@@ -134,7 +141,9 @@
|
||||
"The team in charge of the digital workspace \"La Suite numérique\" can be contacted directly at": "L'équipe responsable de l'espace de travail numérique \"La Suite numérique\" peut être contactée directement à l'adresse",
|
||||
"This accessibility statement applies to La Régie (Suite Territoriale)": "Cette déclaration d’accessibilité s’applique à La Régie (Suite Territoriale)",
|
||||
"This allows us to measure the number of visits and understand which pages are the most viewed.": "Cela nous permet de mesurer le nombre de visites et de comprendre quelles pages sont les plus consultées.",
|
||||
"This domain name is deactivated. No new mailboxes can be created.": "Ce nom de domaine est désactivé. Aucune nouvelle boîte mail ne peut être créée.",
|
||||
"This email prefix is already used.": "Ce préfixe d'email est déjà utilisé.",
|
||||
"This mail domain is already used. Please, choose another one.": "Ce domaine de messagerie est déjà utilisé. Veuillez en choisir un autre.",
|
||||
"This procedure is to be used in the following case: you have reported to the website \n manager an accessibility defect which prevents you from accessing content or one of the \n portal's services and you have not obtained a satisfactory response.": "Cette procédure est à utiliser dans le cas suivant : vous avez signalé au responsable du site internet un défaut d’accessibilité qui vous empêche d’accéder à un contenu ou à un des services du portail et vous n’avez pas obtenu de réponse satisfaisante.",
|
||||
"This site does not display a cookie consent banner, why?": "Ce site n'affiche pas de bannière de consentement des cookies, pourquoi?",
|
||||
"This site places a small text file (a \"cookie\") on your computer when you visit it.": "Ce site place un petit fichier texte (un « cookie ») sur votre ordinateur lorsque vous le visitez.",
|
||||
@@ -154,6 +163,11 @@
|
||||
"You cannot remove other owner.": "Vous ne pouvez pas supprimer un autre propriétaire.",
|
||||
"You cannot update the role of other owner.": "Vous ne pouvez pas mettre à jour les rôles d'autre propriétaire.",
|
||||
"You must have minimum 1 character": "Vous devez entrer au moins 1 caractère",
|
||||
"Your domain name is being validated. You will not be able to create mailboxes until your domain name has been validated by our team.": "Votre nom de domaine est en cours de validation. Vous ne pourrez créer de boîtes mail que lorsque votre nom de domaine sera validé par notre équipe.",
|
||||
"[disabled]": "[désactivé]",
|
||||
"[enabled]": "[actif]",
|
||||
"[failed]": "[erroné]",
|
||||
"[pending]": "[en attente]",
|
||||
"accessibility-contact-defenseurdesdroits": "Contacter le délégué du<1>Défenseur des droits dans votre région</1>",
|
||||
"accessibility-form-defenseurdesdroits": "Écrire un message au<1>Défenseur des droits</1>",
|
||||
"mail domains list loading": "chargement de la liste des domaines de messagerie",
|
||||
|
||||
20
src/frontend/apps/desk/src/pages/mail-domains/add.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import React, { ReactElement } from 'react';
|
||||
|
||||
import { Box } from '@/components';
|
||||
import { MailDomainsLayout } from '@/features/mail-domains';
|
||||
import { ModalCreateMailDomain } from '@/features/mail-domains/components/ModalAddMailDomain';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
return (
|
||||
<Box $padding="large" $height="inherit">
|
||||
<ModalCreateMailDomain />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = function getLayout(page: ReactElement) {
|
||||
return <MailDomainsLayout>{page}</MailDomainsLayout>;
|
||||
};
|
||||
|
||||
export default Page;
|
||||
@@ -1,10 +1,29 @@
|
||||
import { ReactElement } from 'react';
|
||||
import { Button } from '@openfun/cunningham-react';
|
||||
import { useRouter } from 'next/router';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Box } from '@/components';
|
||||
import { MailDomainsLayout } from '@/features/mail-domains';
|
||||
import { NextPageWithLayout } from '@/types/next';
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
width: fit-content;
|
||||
`;
|
||||
|
||||
const Page: NextPageWithLayout = () => {
|
||||
return null;
|
||||
const { t } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Box $align="center" $justify="center" $height="inherit">
|
||||
<StyledButton onClick={() => void router.push('/mail-domains/add')}>
|
||||
{t('Add your mail domain')}
|
||||
</StyledButton>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
Page.getLayout = function getLayout(page: ReactElement) {
|
||||
|
||||
@@ -15,6 +15,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -30,6 +31,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'mailsfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -45,6 +47,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'versaillesnet',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -60,6 +63,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'parisfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -95,7 +99,7 @@ const interceptCommonApiRequests = (page: Page) => {
|
||||
});
|
||||
});
|
||||
|
||||
void page.route('**/api/v1.0/mail-domains/domainfr', (route) => {
|
||||
void page.route('**/api/v1.0/mail-domains/domainfr/', (route) => {
|
||||
void route.fulfill({
|
||||
json: mailDomainDomainFrFixture,
|
||||
});
|
||||
@@ -275,7 +279,7 @@ test.describe('Mail domain create mailbox', () => {
|
||||
});
|
||||
});
|
||||
|
||||
void page.route('**/api/v1.0/mail-domains/domainfr', (route) => {
|
||||
void page.route('**/api/v1.0/mail-domains/domainfr/', (route) => {
|
||||
void route.fulfill({
|
||||
json: localMailDomainDomainFr,
|
||||
});
|
||||
|
||||
@@ -5,74 +5,113 @@ import { keyCloakSignIn } from './common';
|
||||
|
||||
const currentDateIso = new Date().toISOString();
|
||||
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'mails.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43e',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'mailsfr',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'versailles.net',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43g',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'versaillesnet',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'paris.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43h',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'parisfr',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
const interceptCommonApiCalls = async (
|
||||
page: Page,
|
||||
arrayMailDomains: MailDomain[],
|
||||
) => {
|
||||
const singleMailDomain = arrayMailDomains[0];
|
||||
await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: arrayMailDomains.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: arrayMailDomains,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const mailDomainDomainFrFixture = mailDomainsFixtures[0];
|
||||
await page.route('**/api/v1.0/mail-domains/domainfr/', async (route) => {
|
||||
await route.fulfill({
|
||||
json: singleMailDomain,
|
||||
});
|
||||
});
|
||||
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: 0,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: [],
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
const clickOnMailDomainsNavButton = async (page: Page): Promise<void> =>
|
||||
await page.locator('menu').first().getByLabel(`Mail Domains button`).click();
|
||||
|
||||
const assertMailDomainUpperElementsAreVisible = async (page: Page) => {
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
await expect(page).toHaveURL(/mail-domains\/domainfr\//);
|
||||
|
||||
await expect(page.getByRole('heading', { name: 'domain.fr' })).toBeVisible();
|
||||
};
|
||||
|
||||
const assertFilledMailboxesTableElementsAreVisible = async (
|
||||
page: Page,
|
||||
domainFr: object & { name: string },
|
||||
multiLevelArrayMailboxes: object & Array<{ local_part: string }[]>,
|
||||
) => {
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: /Names/ }).first(),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: /Emails/ }).first(),
|
||||
).toBeVisible();
|
||||
|
||||
await Promise.all(
|
||||
multiLevelArrayMailboxes[0].map((mailbox) =>
|
||||
expect(
|
||||
page.getByText(`${mailbox.local_part}@${domainFr.name}`),
|
||||
).toBeVisible(),
|
||||
),
|
||||
);
|
||||
|
||||
const table = page.locator('table');
|
||||
await expect(table).toBeVisible();
|
||||
|
||||
const tdNames = await table.getByText('John Doe').all();
|
||||
expect(tdNames.length).toEqual(20);
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByRole('button', { name: '1' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByText('navigate_next'),
|
||||
).toBeVisible();
|
||||
|
||||
await page
|
||||
.locator('.c__pagination__list')
|
||||
.getByRole('button', { name: '2' })
|
||||
.click();
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByText('navigate_next'),
|
||||
).toBeHidden();
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByText('navigate_before'),
|
||||
).toBeVisible();
|
||||
|
||||
await Promise.all(
|
||||
multiLevelArrayMailboxes[1].map((mailbox) =>
|
||||
expect(
|
||||
page.getByText(`${mailbox.local_part}@${domainFr.name}`),
|
||||
).toBeVisible(),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
test.describe('Mail domain', () => {
|
||||
test.beforeEach(async ({ page, browserName }) => {
|
||||
await page.goto('/');
|
||||
@@ -103,195 +142,645 @@ test.describe('Mail domain', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('checks all the elements are visible when domain exist but contains no mailboxes', async ({
|
||||
page,
|
||||
}) => {
|
||||
const interceptApiCalls = async () => {
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: 0,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: [],
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
await page.route('**/api/v1.0/mail-domains/domainfr**', async (route) => {
|
||||
await route.fulfill({
|
||||
json: mailDomainDomainFrFixture,
|
||||
});
|
||||
});
|
||||
await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: mailDomainsFixtures.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailDomainsFixtures,
|
||||
test.describe('user is administrator or owner', () => {
|
||||
test.describe('mail domain is enabled', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
});
|
||||
},
|
||||
{
|
||||
name: 'mails.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43e',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'mailsfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'versailles.net',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43g',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'versaillesnet',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'paris.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43h',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'parisfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test('checks all the elements are visible when domain exist but contains no mailboxes', async ({
|
||||
page,
|
||||
}) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).toBeEnabled();
|
||||
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
};
|
||||
|
||||
await interceptApiCalls();
|
||||
test('checks all the elements are visible when domain exists and contains 2 pages of mailboxes', async ({
|
||||
page,
|
||||
}) => {
|
||||
const mailboxesFixtures = {
|
||||
domainFr: {
|
||||
page1: Array.from({ length: 20 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}f`,
|
||||
first_name: 'john',
|
||||
last_name: 'doe',
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
page2: Array.from({ length: 2 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}d`,
|
||||
first_name: 'john',
|
||||
last_name: 'doe',
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
},
|
||||
};
|
||||
const interceptApiCalls = async () => {
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/?page=*',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: mailDomainsFixtures.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailDomainsFixtures,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: mailDomainsFixtures[0],
|
||||
});
|
||||
},
|
||||
);
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count:
|
||||
mailboxesFixtures.domainFr.page1.length +
|
||||
mailboxesFixtures.domainFr.page2.length,
|
||||
next: 'http://localhost:8071/api/v1.0/mail-domains/domainfr/mailboxes/?page=2',
|
||||
previous: null,
|
||||
results: mailboxesFixtures.domainFr.page1,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=2**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count:
|
||||
mailboxesFixtures.domainFr.page1.length +
|
||||
mailboxesFixtures.domainFr.page2.length,
|
||||
next: null,
|
||||
previous:
|
||||
'http://localhost:8071/api/v1.0/mail-domains/domainfr/mailboxes/?page=1',
|
||||
results: mailboxesFixtures.domainFr.page2,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
await interceptApiCalls();
|
||||
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
await expect(page).toHaveURL(/mail-domains\/domainfr\//);
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: /domain\.fr/ }).first(),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).toBeEnabled();
|
||||
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
await assertFilledMailboxesTableElementsAreVisible(
|
||||
page,
|
||||
mailDomainsFixtures[0],
|
||||
[mailboxesFixtures.domainFr.page1, mailboxesFixtures.domainFr.page2],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('mail domain creation is pending', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'pending',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test('checks expected elements are visible', async ({ page }) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
await expect(page).toHaveURL(/mail-domains\/domainfr\//);
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'domain.fr' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByText(
|
||||
'Your domain name is being validated. ' +
|
||||
'You will not be able to create mailboxes until your domain name has been validated by our team.',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).toBeDisabled();
|
||||
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('mail domain is disabled', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'disabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test('checks expected elements are visible', async ({ page }) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await expect(
|
||||
page.getByText(
|
||||
'This domain name is deactivated. No new mailboxes can be created.',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).toBeDisabled();
|
||||
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('mail domain creation has failed', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'failed',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
put: true,
|
||||
post: true,
|
||||
delete: true,
|
||||
manage_accesses: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test('checks expected elements are visible', async ({ page }) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await expect(
|
||||
page.getByText(
|
||||
'The domain name encounters an error. Please contact our support team to solve the problem:',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('link', { name: 'suiteterritoriale@anct.gouv.fr' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).toBeDisabled();
|
||||
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('checks all the elements are visible when domain exists and contains 2 pages of mailboxes', async ({
|
||||
page,
|
||||
}) => {
|
||||
const mailboxesFixtures = {
|
||||
domainFr: {
|
||||
page1: Array.from({ length: 20 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}f`,
|
||||
first_name: 'john',
|
||||
last_name: 'doe',
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
page2: Array.from({ length: 2 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}d`,
|
||||
first_name: 'john',
|
||||
last_name: 'doe',
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
},
|
||||
};
|
||||
const interceptApiCalls = async () => {
|
||||
await page.route('**/api/v1.0/mail-domains/?page=*', async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: mailDomainsFixtures.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailDomainsFixtures,
|
||||
test.describe('user is member', () => {
|
||||
test.describe('mail domain is enabled', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: false,
|
||||
put: false,
|
||||
post: false,
|
||||
delete: false,
|
||||
manage_accesses: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
await page.route('**/api/v1.0/mail-domains/domainfr', async (route) => {
|
||||
await route.fulfill({
|
||||
json: mailDomainDomainFrFixture,
|
||||
});
|
||||
});
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count:
|
||||
mailboxesFixtures.domainFr.page1.length +
|
||||
mailboxesFixtures.domainFr.page2.length,
|
||||
next: 'http://localhost:8071/api/v1.0/mail-domains/domainfr/mailboxes/?page=2',
|
||||
previous: null,
|
||||
results: mailboxesFixtures.domainFr.page1,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=2**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count:
|
||||
mailboxesFixtures.domainFr.page1.length +
|
||||
mailboxesFixtures.domainFr.page2.length,
|
||||
next: null,
|
||||
previous:
|
||||
'http://localhost:8071/api/v1.0/mail-domains/domainfr/mailboxes/?page=1',
|
||||
results: mailboxesFixtures.domainFr.page2,
|
||||
},
|
||||
});
|
||||
{
|
||||
name: 'mails.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43e',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'mailsfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: false,
|
||||
put: false,
|
||||
post: false,
|
||||
delete: false,
|
||||
manage_accesses: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
||||
{
|
||||
name: 'versailles.net',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43g',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'versaillesnet',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: false,
|
||||
put: false,
|
||||
post: false,
|
||||
delete: false,
|
||||
manage_accesses: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'paris.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43h',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'parisfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: false,
|
||||
put: false,
|
||||
post: false,
|
||||
delete: false,
|
||||
manage_accesses: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
await interceptApiCalls();
|
||||
test('checks all the elements are visible when domain exist but contains no mailboxes', async ({
|
||||
page,
|
||||
}) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
await expect(page).toHaveURL(/mail-domains\/domainfr\//);
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).not.toBeInViewport();
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'domain.fr' }),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: /Names/ }).first(),
|
||||
).toBeVisible();
|
||||
test('checks all the elements are visible when domain exists and contains 2 pages of mailboxes', async ({
|
||||
page,
|
||||
}) => {
|
||||
const mailboxesFixtures = {
|
||||
domainFr: {
|
||||
page1: Array.from({ length: 20 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}f`,
|
||||
first_name: 'john',
|
||||
last_name: 'doe',
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
page2: Array.from({ length: 2 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}d`,
|
||||
first_name: 'john',
|
||||
last_name: 'doe',
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
},
|
||||
};
|
||||
const interceptApiCalls = async () => {
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/?page=*',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: mailDomainsFixtures.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailDomainsFixtures,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: mailDomainsFixtures[0],
|
||||
});
|
||||
},
|
||||
);
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count:
|
||||
mailboxesFixtures.domainFr.page1.length +
|
||||
mailboxesFixtures.domainFr.page2.length,
|
||||
next: 'http://localhost:8071/api/v1.0/mail-domains/domainfr/mailboxes/?page=2',
|
||||
previous: null,
|
||||
results: mailboxesFixtures.domainFr.page1,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=2**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count:
|
||||
mailboxesFixtures.domainFr.page1.length +
|
||||
mailboxesFixtures.domainFr.page2.length,
|
||||
next: null,
|
||||
previous:
|
||||
'http://localhost:8071/api/v1.0/mail-domains/domainfr/mailboxes/?page=1',
|
||||
results: mailboxesFixtures.domainFr.page2,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: /Emails/ }).first(),
|
||||
).toBeVisible();
|
||||
await interceptApiCalls();
|
||||
|
||||
await Promise.all(
|
||||
mailboxesFixtures.domainFr.page1.map((mailbox) =>
|
||||
expect(
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).not.toBeInViewport();
|
||||
|
||||
await assertFilledMailboxesTableElementsAreVisible(
|
||||
page,
|
||||
mailDomainsFixtures[0],
|
||||
[mailboxesFixtures.domainFr.page1, mailboxesFixtures.domainFr.page2],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('mail domain creation is pending', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'pending',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: false,
|
||||
put: false,
|
||||
post: false,
|
||||
delete: false,
|
||||
manage_accesses: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test('checks expected elements are visible', async ({ page }) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
await expect(page).toHaveURL(/mail-domains\/domainfr\//);
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', { name: 'domain.fr' }),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByText(
|
||||
`${mailbox.local_part}@${mailDomainDomainFrFixture.name}`,
|
||||
'Your domain name is being validated. ' +
|
||||
'You will not be able to create mailboxes until your domain name has been validated by our team.',
|
||||
),
|
||||
).toBeVisible(),
|
||||
),
|
||||
);
|
||||
).toBeVisible();
|
||||
|
||||
const table = page.locator('table');
|
||||
await expect(table).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).not.toBeInViewport();
|
||||
|
||||
const tdNames = await table.getByText('John Doe').all();
|
||||
expect(tdNames.length).toEqual(20);
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByRole('button', { name: '1' }),
|
||||
).toBeVisible();
|
||||
test.describe('mail domain is disabled', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'disabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: false,
|
||||
put: false,
|
||||
post: false,
|
||||
delete: false,
|
||||
manage_accesses: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByText('navigate_next'),
|
||||
).toBeVisible();
|
||||
test('checks expected elements are visible', async ({ page }) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await page
|
||||
.locator('.c__pagination__list')
|
||||
.getByRole('button', { name: '2' })
|
||||
.click();
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByText('navigate_next'),
|
||||
).toBeHidden();
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await expect(
|
||||
page.locator('.c__pagination__list').getByText('navigate_before'),
|
||||
).toBeVisible();
|
||||
|
||||
await Promise.all(
|
||||
mailboxesFixtures.domainFr.page2.map((mailbox) =>
|
||||
expect(
|
||||
await expect(
|
||||
page.getByText(
|
||||
`${mailbox.local_part}@${mailDomainDomainFrFixture.name}`,
|
||||
'This domain name is deactivated. No new mailboxes can be created.',
|
||||
),
|
||||
).toBeVisible(),
|
||||
),
|
||||
);
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).not.toBeInViewport();
|
||||
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('mail domain creation has failed', () => {
|
||||
const mailDomainsFixtures: MailDomain[] = [
|
||||
{
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'failed',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: false,
|
||||
put: false,
|
||||
post: false,
|
||||
delete: false,
|
||||
manage_accesses: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
test('checks expected elements are visible', async ({ page }) => {
|
||||
await interceptCommonApiCalls(page, mailDomainsFixtures);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
|
||||
await assertMailDomainUpperElementsAreVisible(page);
|
||||
|
||||
await expect(
|
||||
page.getByText(
|
||||
'The domain name encounters an error. Please contact our support team to solve the problem:',
|
||||
),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', { name: 'Create a mailbox' }),
|
||||
).not.toBeInViewport();
|
||||
|
||||
await expect(
|
||||
page.getByText('No mail box was created with this mail domain.'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { keyCloakSignIn, randomName } from './common';
|
||||
|
||||
test.beforeEach(async ({ page, browserName }) => {
|
||||
await page.goto('/');
|
||||
await keyCloakSignIn(page, browserName);
|
||||
});
|
||||
|
||||
test.describe('Add Mail Domains', () => {
|
||||
test('checks all the elements are visible', async ({ page }) => {
|
||||
await page.goto('/mail-domains');
|
||||
|
||||
const buttonFromHomePage = page.getByRole('button', {
|
||||
name: 'Add your mail domain',
|
||||
});
|
||||
|
||||
await expect(buttonFromHomePage).toBeVisible();
|
||||
await buttonFromHomePage.click();
|
||||
|
||||
await expect(buttonFromHomePage).toBeHidden();
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', {
|
||||
name: 'Add your mail domain',
|
||||
level: 3,
|
||||
}),
|
||||
).toBeVisible();
|
||||
|
||||
const form = page.locator('form');
|
||||
|
||||
await expect(form.getByLabel('Domain name')).toBeVisible();
|
||||
|
||||
await expect(page.getByText('Example: saint-laurent.fr')).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', {
|
||||
name: 'Add the domain',
|
||||
}),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByRole('button', {
|
||||
name: 'Cancel',
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks the cancel button interaction', async ({ page }) => {
|
||||
await page.goto('/mail-domains');
|
||||
|
||||
const buttonFromHomePage = page.getByRole('button', {
|
||||
name: 'Add your mail domain',
|
||||
});
|
||||
await buttonFromHomePage.click();
|
||||
|
||||
await expect(buttonFromHomePage).toBeHidden();
|
||||
|
||||
await page
|
||||
.getByRole('button', {
|
||||
name: 'Cancel',
|
||||
})
|
||||
.click();
|
||||
|
||||
await expect(buttonFromHomePage).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks form invalid status', async ({ page }) => {
|
||||
await page.goto('/mail-domains');
|
||||
|
||||
const buttonFromHomePage = page.getByRole('button', {
|
||||
name: 'Add your mail domain',
|
||||
});
|
||||
await buttonFromHomePage.click();
|
||||
|
||||
const form = page.locator('form');
|
||||
|
||||
const inputName = form.getByLabel('Domain name');
|
||||
const buttonSubmit = page.getByRole('button', {
|
||||
name: 'Add the domain',
|
||||
});
|
||||
|
||||
await expect(inputName).toBeVisible();
|
||||
await expect(page.getByText('Example: saint-laurent.fr')).toBeVisible();
|
||||
|
||||
await expect(
|
||||
page.getByRole('button', {
|
||||
name: 'Cancel',
|
||||
}),
|
||||
).toBeEnabled();
|
||||
|
||||
await expect(buttonSubmit).toBeDisabled();
|
||||
|
||||
await inputName.fill('s');
|
||||
await expect(page.getByText('Example: saint-laurent.fr')).toBeVisible();
|
||||
|
||||
await inputName.clear();
|
||||
|
||||
await expect(page.getByText('Example: saint-laurent.fr')).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks the routing on new mail domain added', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
const mailDomainName = randomName('versailles.fr', browserName, 1)[0];
|
||||
const mailDomainSlug = mailDomainName.replace('.', '');
|
||||
|
||||
await page.goto('/mail-domains');
|
||||
|
||||
const panel = page.getByLabel('Mail domains panel').first();
|
||||
|
||||
await panel.getByRole('link', { name: 'Add your mail domain' }).click();
|
||||
|
||||
const form = page.locator('form');
|
||||
|
||||
await form.getByLabel('Domain name').fill(mailDomainName);
|
||||
await page.getByRole('button', { name: 'Add the domain' }).click();
|
||||
|
||||
await expect(page).toHaveURL(`/mail-domains\/${mailDomainSlug}/`);
|
||||
|
||||
await expect(
|
||||
page.getByRole('heading', {
|
||||
name: mailDomainName,
|
||||
}),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks error when duplicate mail domain', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.goto('/mail-domains');
|
||||
|
||||
const panel = page.getByLabel('Mail domains panel').first();
|
||||
const additionLink = panel.getByRole('link', {
|
||||
name: 'Add your mail domain',
|
||||
});
|
||||
const form = page.locator('form');
|
||||
const inputName = form.getByLabel('Domain name');
|
||||
const submitButton = page.getByRole('button', {
|
||||
name: 'Add the domain',
|
||||
});
|
||||
|
||||
const mailDomainName = randomName('duplicate.fr', browserName, 1)[0];
|
||||
const mailDomainSlug = mailDomainName.replace('.', '');
|
||||
|
||||
await additionLink.click();
|
||||
await inputName.fill(mailDomainName);
|
||||
await submitButton.click();
|
||||
|
||||
await expect(page).toHaveURL(`/mail-domains\/${mailDomainSlug}\/`);
|
||||
|
||||
await additionLink.click();
|
||||
|
||||
await inputName.fill(mailDomainName);
|
||||
await submitButton.click();
|
||||
|
||||
await expect(
|
||||
page.getByText(
|
||||
'This mail domain is already used. Please, choose another one.',
|
||||
),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks 404 on mail-domains/[slug] page', async ({ page }) => {
|
||||
await page.goto('/mail-domains/unknown-domain');
|
||||
|
||||
await expect(
|
||||
page.getByText(
|
||||
'It seems that the page you are looking for does not exist or cannot be displayed correctly.',
|
||||
),
|
||||
).toBeVisible({
|
||||
timeout: 15000,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -11,6 +11,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'domainfr',
|
||||
status: 'pending',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -26,6 +27,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'mailsfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -41,6 +43,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'versaillesnet',
|
||||
status: 'disabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -56,6 +59,7 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
created_at: currentDateIso,
|
||||
updated_at: currentDateIso,
|
||||
slug: 'parisfr',
|
||||
status: 'failed',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -99,7 +103,7 @@ test.describe('Mail domains', () => {
|
||||
response.status() === 200,
|
||||
);
|
||||
|
||||
const panel = page.getByLabel('mail domains panel').first();
|
||||
const panel = page.getByLabel('Mail domains panel').first();
|
||||
|
||||
await panel
|
||||
.getByRole('button', {
|
||||
@@ -139,7 +143,7 @@ test.describe('Mail domains', () => {
|
||||
.click();
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
await expect(
|
||||
page.getByLabel('mail domains panel', { exact: true }),
|
||||
page.getByLabel('Mail domains panel', { exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(page.getByText('No domains exist.')).toBeVisible();
|
||||
});
|
||||
@@ -163,13 +167,17 @@ test.describe('Mail domains', () => {
|
||||
.click();
|
||||
await expect(page).toHaveURL(/mail-domains\//);
|
||||
await expect(
|
||||
page.getByLabel('mail domains panel', { exact: true }),
|
||||
page.getByLabel('Mail domains panel', { exact: true }),
|
||||
).toBeVisible();
|
||||
await expect(page.getByText('No domains exist.')).toHaveCount(0);
|
||||
await expect(page.getByText('domain.fr')).toBeVisible();
|
||||
await expect(page.getByText('mails.fr')).toBeVisible();
|
||||
await expect(page.getByText('versailles.net')).toBeVisible();
|
||||
await expect(page.getByText('paris.fr')).toBeVisible();
|
||||
|
||||
await Promise.all(
|
||||
mailDomainsFixtures.map(async ({ name, status }) => {
|
||||
const linkName = page.getByRole('link', { name });
|
||||
await expect(linkName).toBeVisible();
|
||||
await expect(linkName.getByText(`[${status}]`)).toBeVisible();
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||