🚸(frontend) improve mailbox creation validations and error handling
- replace known error causes returned by the API on unsuccessful mailbox creation requests by meaningful interpolated message shown above the form - strengthen form validation rules to be identical as those of the api endpoint to prevent emitting invalid requests - designate which form fields are mandatory for accessiblity - update texts for better ux writting, and their translations - fix css style input errors - update related e2e tests.
This commit is contained in:
committed by
Sebastien Nobour
parent
cda4373544
commit
32e6602dda
@@ -41,8 +41,57 @@ const mailDomainsFixtures: MailDomain[] = [
|
||||
|
||||
const mailDomainDomainFrFixture = mailDomainsFixtures[0];
|
||||
|
||||
const clickOnMailDomainsNavButton = async (page: Page): Promise<void> =>
|
||||
const mailboxesFixtures = {
|
||||
domainFr: {
|
||||
page1: Array.from({ length: 1 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}f`,
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
const interceptCommonApiRequests = (page: Page) => {
|
||||
void page.route('**/api/v1.0/mail-domains/?page=*', (route) => {
|
||||
void route.fulfill({
|
||||
json: {
|
||||
count: mailDomainsFixtures.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailDomainsFixtures,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
void page.route('**/api/v1.0/mail-domains/domainfr', (route) => {
|
||||
void route.fulfill({
|
||||
json: mailDomainDomainFrFixture,
|
||||
});
|
||||
});
|
||||
|
||||
void page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**',
|
||||
(route) => {
|
||||
void route.fulfill({
|
||||
json: {
|
||||
count: mailboxesFixtures.domainFr.page1.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailboxesFixtures.domainFr.page1,
|
||||
},
|
||||
});
|
||||
},
|
||||
{ times: 1 },
|
||||
);
|
||||
};
|
||||
|
||||
const navigateToMailboxCreationFormForMailDomainFr = async (
|
||||
page: Page,
|
||||
): Promise<void> => {
|
||||
await page.locator('menu').first().getByLabel(`Mail Domains button`).click();
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
await page.getByRole('button', { name: 'Create a mailbox' }).click();
|
||||
};
|
||||
|
||||
test.describe('Mail domain create mailbox', () => {
|
||||
test.beforeEach(async ({ page, browserName }) => {
|
||||
@@ -54,57 +103,19 @@ test.describe('Mail domain create mailbox', () => {
|
||||
test('checks user can create a mailbox for a mail domain', async ({
|
||||
page,
|
||||
}) => {
|
||||
const mailboxesFixtures = {
|
||||
domainFr: {
|
||||
page1: Array.from({ length: 1 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}f`,
|
||||
local_part: `local_part-${i}`,
|
||||
secondary_email: `secondary_email-${i}`,
|
||||
})),
|
||||
},
|
||||
};
|
||||
|
||||
const newMailbox = {
|
||||
id: '04433733-c9b7-453a-8122-755ac115bb00',
|
||||
local_part: 'john.doe',
|
||||
secondary_email: 'john.doe@mail.com',
|
||||
secondary_email: 'john.doe-complex2024@mail.com',
|
||||
};
|
||||
|
||||
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: mailDomainDomainFrFixture,
|
||||
});
|
||||
});
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: mailboxesFixtures.domainFr.page1.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailboxesFixtures.domainFr.page1,
|
||||
},
|
||||
});
|
||||
},
|
||||
{ times: 1 },
|
||||
);
|
||||
const interceptRequests = (page: Page) => {
|
||||
void interceptCommonApiRequests(page);
|
||||
|
||||
await page.route(
|
||||
void page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
(route) => {
|
||||
void route.fulfill({
|
||||
json: {
|
||||
count: [...mailboxesFixtures.domainFr.page1, newMailbox].length,
|
||||
next: null,
|
||||
@@ -115,7 +126,7 @@ test.describe('Mail domain create mailbox', () => {
|
||||
},
|
||||
);
|
||||
|
||||
await page.route(
|
||||
void page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/',
|
||||
(route) => {
|
||||
if (route.request().method() === 'POST') {
|
||||
@@ -149,13 +160,10 @@ test.describe('Mail domain create mailbox', () => {
|
||||
}
|
||||
});
|
||||
|
||||
await interceptApiCalls();
|
||||
void interceptRequests(page);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
await navigateToMailboxCreationFormForMailDomainFr(page);
|
||||
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
|
||||
await page.getByRole('button', { name: 'Create a mailbox' }).click();
|
||||
await page.getByRole('button', { name: 'Cancel' }).click();
|
||||
|
||||
await expect(page.getByTitle('Mailbox creation form')).toBeHidden();
|
||||
@@ -167,13 +175,37 @@ test.describe('Mail domain create mailbox', () => {
|
||||
page.getByRole('heading', { name: 'Create a mailbox' }),
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByLabel('First name').fill('John');
|
||||
await page.getByLabel('Last name').fill('Doe');
|
||||
await page.getByLabel('Main email address').fill('john.doe');
|
||||
await expect(page.locator('span').getByText('@domain.fr')).toBeVisible();
|
||||
await page.getByLabel('Secondary email address').fill('john.doe@mail.com');
|
||||
const inputFirstName = page.getByLabel('First name');
|
||||
const inputLastName = page.getByLabel('Last name');
|
||||
const inputLocalPart = page.getByLabel('Email address prefix');
|
||||
const instructionInputLocalPart = page.getByText(
|
||||
'It must not contain spaces, accents or special characters (except "." or "-"). E.g.: jean.dupont',
|
||||
);
|
||||
const inputSecondaryEmailAddress = page.getByLabel(
|
||||
'Secondary email address',
|
||||
);
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
await expect(inputFirstName).toHaveAttribute('aria-required', 'true');
|
||||
await expect(inputFirstName).toHaveAttribute('required', '');
|
||||
await expect(inputLastName).toHaveAttribute('aria-required', 'true');
|
||||
await expect(inputLastName).toHaveAttribute('required', '');
|
||||
await expect(inputLocalPart).toHaveAttribute('aria-required', 'true');
|
||||
await expect(inputLocalPart).toHaveAttribute('required', '');
|
||||
await expect(inputSecondaryEmailAddress).toHaveAttribute(
|
||||
'aria-required',
|
||||
'true',
|
||||
);
|
||||
await expect(inputSecondaryEmailAddress).toHaveAttribute('required', '');
|
||||
|
||||
await inputFirstName.fill('John');
|
||||
await inputLastName.fill('Doe');
|
||||
await inputLocalPart.fill('john.doe');
|
||||
|
||||
await expect(instructionInputLocalPart).toBeVisible();
|
||||
await expect(page.locator('span').getByText('@domain.fr')).toBeVisible();
|
||||
await inputSecondaryEmailAddress.fill('john.doe@mail.com');
|
||||
|
||||
await page.getByRole('button', { name: 'Create the mailbox' }).click();
|
||||
|
||||
expect(isCreateMailboxRequestSentWithExpectedPayload).toBeTruthy();
|
||||
await expect(page.getByAltText('Mailbox creation form')).toBeHidden();
|
||||
@@ -192,51 +224,9 @@ test.describe('Mail domain create mailbox', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('checks client invalidation messages are displayed when fields are not properly filled', async ({
|
||||
test('checks client invalidation messages are displayed and no mailbox creation request is sent when fields are not properly filled', async ({
|
||||
page,
|
||||
}) => {
|
||||
const mailboxesFixtures = {
|
||||
domainFr: {
|
||||
page1: Array.from({ length: 1 }, (_, i) => ({
|
||||
id: `456ac6ca-0402-4615-8005-69bc1efde${i}f`,
|
||||
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: mailDomainDomainFrFixture,
|
||||
});
|
||||
});
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/?page=1**',
|
||||
async (route) => {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
count: mailboxesFixtures.domainFr.page1.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: mailboxesFixtures.domainFr.page1,
|
||||
},
|
||||
});
|
||||
},
|
||||
{ times: 1 },
|
||||
);
|
||||
};
|
||||
|
||||
let isCreateMailboxRequestSent = false;
|
||||
page.on(
|
||||
'request',
|
||||
@@ -246,27 +236,144 @@ test.describe('Mail domain create mailbox', () => {
|
||||
request.method() === 'POST'),
|
||||
);
|
||||
|
||||
await interceptApiCalls();
|
||||
void interceptCommonApiRequests(page);
|
||||
|
||||
await clickOnMailDomainsNavButton(page);
|
||||
await navigateToMailboxCreationFormForMailDomainFr(page);
|
||||
|
||||
await page.getByRole('listbox').first().getByText('domain.fr').click();
|
||||
|
||||
await page.getByRole('button', { name: 'Create a mailbox' }).click();
|
||||
|
||||
await page.getByRole('button', { name: 'Submit' }).click();
|
||||
const inputFirstName = page.getByLabel('First name');
|
||||
const inputLastName = page.getByLabel('Last name');
|
||||
const inputLocalPart = page.getByLabel('Email address prefix');
|
||||
const inputSecondaryEmailAddress = page.getByLabel(
|
||||
'Secondary email address',
|
||||
);
|
||||
const textInvalidLocalPart = page.getByText(
|
||||
'It must not contain spaces, accents or special characters (except "." or "-"). E.g.: jean.dupont',
|
||||
);
|
||||
const textInvalidSecondaryEmailAddress = page.getByText(
|
||||
'Please enter a valid email address.\nE.g. : jean.dupont@mail.fr',
|
||||
);
|
||||
|
||||
await inputFirstName.fill(' ');
|
||||
await inputFirstName.clear();
|
||||
await expect(page.getByText('Please enter your first name')).toBeVisible();
|
||||
|
||||
await inputLastName.fill(' ');
|
||||
await inputLastName.clear();
|
||||
await expect(page.getByText('Please enter your last name')).toBeVisible();
|
||||
|
||||
await inputLocalPart.fill('wrong@');
|
||||
await expect(textInvalidLocalPart).toBeVisible();
|
||||
|
||||
await inputSecondaryEmailAddress.fill('uncomplete@mail');
|
||||
await expect(textInvalidSecondaryEmailAddress).toBeVisible();
|
||||
|
||||
await inputLocalPart.clear();
|
||||
await inputLocalPart.fill('wrong ');
|
||||
await expect(textInvalidLocalPart).toBeVisible();
|
||||
|
||||
await inputLocalPart.clear();
|
||||
await expect(
|
||||
page.getByText(
|
||||
'Please enter the first part of the email address, without including "@" in it',
|
||||
),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText('Please enter your secondary email address'),
|
||||
page.getByText('You must have minimum 1 character'),
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: 'Create the mailbox' }).click();
|
||||
|
||||
expect(isCreateMailboxRequestSent).toBeFalsy();
|
||||
});
|
||||
|
||||
test('checks field invalidation messages are displayed when sending already existing local_part data in mail domain to api', async ({
|
||||
page,
|
||||
}) => {
|
||||
const interceptRequests = (page: Page) => {
|
||||
void interceptCommonApiRequests(page);
|
||||
|
||||
void page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/',
|
||||
(route) => {
|
||||
if (route.request().method() === 'POST') {
|
||||
void route.fulfill({
|
||||
status: 400,
|
||||
json: {
|
||||
local_part: [
|
||||
'Mailbox with this Local_part and Domain already exists.',
|
||||
],
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
{ times: 1 },
|
||||
);
|
||||
};
|
||||
|
||||
void interceptRequests(page);
|
||||
|
||||
await navigateToMailboxCreationFormForMailDomainFr(page);
|
||||
|
||||
const inputFirstName = page.getByLabel('First name');
|
||||
const inputLastName = page.getByLabel('Last name');
|
||||
const inputLocalPart = page.getByLabel('Email address prefix');
|
||||
const inputSecondaryEmailAddress = page.getByLabel(
|
||||
'Secondary email address',
|
||||
);
|
||||
const submitButton = page.getByRole('button', {
|
||||
name: 'Create the mailbox',
|
||||
});
|
||||
|
||||
const textAlreadyUsedLocalPart = page.getByText(
|
||||
'This email prefix is already used.',
|
||||
);
|
||||
|
||||
await inputFirstName.fill('John');
|
||||
await inputLastName.fill('Doe');
|
||||
await inputLocalPart.fill('john.already');
|
||||
await inputSecondaryEmailAddress.fill('john.already@mail.com');
|
||||
|
||||
await submitButton.click();
|
||||
|
||||
await expect(textAlreadyUsedLocalPart).toBeVisible();
|
||||
});
|
||||
|
||||
test('checks unknown api error causes are displayed above form when they are not related with invalid field', async ({
|
||||
page,
|
||||
}) => {
|
||||
const interceptRequests = async (page: Page) => {
|
||||
void interceptCommonApiRequests(page);
|
||||
|
||||
await page.route(
|
||||
'**/api/v1.0/mail-domains/domainfr/mailboxes/',
|
||||
async (route) => {
|
||||
if (route.request().method() === 'POST') {
|
||||
await route.fulfill({
|
||||
status: 500,
|
||||
json: {
|
||||
unknown_error: ['Unknown error from server'],
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
{ times: 1 },
|
||||
);
|
||||
};
|
||||
|
||||
void interceptRequests(page);
|
||||
|
||||
await navigateToMailboxCreationFormForMailDomainFr(page);
|
||||
|
||||
const inputFirstName = page.getByLabel('First name');
|
||||
const inputLastName = page.getByLabel('Last name');
|
||||
const inputLocalPart = page.getByLabel('Email address prefix');
|
||||
const inputSecondaryEmailAddress = page.getByLabel(
|
||||
'Secondary email address',
|
||||
);
|
||||
|
||||
await inputFirstName.fill('John');
|
||||
await inputLastName.fill('Doe');
|
||||
await inputLocalPart.fill('john.doe');
|
||||
|
||||
await inputSecondaryEmailAddress.fill('john.do@mail.fr');
|
||||
|
||||
await page.getByRole('button', { name: 'Create the mailbox' }).click();
|
||||
|
||||
await expect(page.getByText('Unknown error from server')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user