🥅(frontend) catch new errors on mailbox creation
- catch errors related to MAIL_PROVISIONING_API_CREDENTIALS introduced in commit #ba30b1d3eec73718add6585f30c6b7959cb21850. Intentionally does not parse the error "Permission denied. Please check your MAIL_PROVISIONING_API_CREDENTIALS." as it means the user is neither admin or owner of the domain and should not access the mailbox creation form - update translations and component tests
This commit is contained in:
committed by
Sebastien Nobour
parent
ae05b430db
commit
f04c8bc6aa
@@ -21,6 +21,7 @@ and this project adheres to
|
||||
- ✨(mailbox) send new mailbox confirmation email #397
|
||||
- ✨(domains) domain accesses update API #423
|
||||
- ✨(backend) domain accesses create API #428
|
||||
- 🥅(frontend) catch new errors on mailbox creation #392
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import React from 'react';
|
||||
|
||||
import { APIError } from '@/api';
|
||||
import { AppWrapper } from '@/tests/utils';
|
||||
|
||||
import { CreateMailboxParams } from '../../api';
|
||||
import { MailDomain } from '../../types';
|
||||
import { ModalCreateMailbox } from '../ModalCreateMailbox';
|
||||
|
||||
const mockMailDomain: MailDomain = {
|
||||
name: 'domain.fr',
|
||||
id: '456ac6ca-0402-4615-8005-69bc1efde43f',
|
||||
name: 'example.com',
|
||||
slug: 'example-com',
|
||||
status: 'enabled',
|
||||
created_at: new Date().toISOString(),
|
||||
updated_at: new Date().toISOString(),
|
||||
slug: 'domainfr',
|
||||
status: 'enabled',
|
||||
abilities: {
|
||||
get: true,
|
||||
patch: true,
|
||||
@@ -28,23 +24,18 @@ const mockMailDomain: MailDomain = {
|
||||
},
|
||||
};
|
||||
|
||||
const mockOnSuccess = jest.fn();
|
||||
jest.mock('../../api/useCreateMailbox', () => {
|
||||
const { createMailbox } = jest.requireActual('../../api/useCreateMailbox');
|
||||
|
||||
return {
|
||||
useCreateMailbox: jest.fn().mockImplementation(({ onError }) =>
|
||||
useMutation<void, APIError, CreateMailboxParams>({
|
||||
mutationFn: createMailbox,
|
||||
onSuccess: mockOnSuccess,
|
||||
onError: (error) => onError(error),
|
||||
}),
|
||||
),
|
||||
};
|
||||
});
|
||||
const toast = jest.fn();
|
||||
jest.mock('@openfun/cunningham-react', () => ({
|
||||
...jest.requireActual('@openfun/cunningham-react'),
|
||||
useToastProvider: () => ({
|
||||
toast,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('ModalCreateMailbox', () => {
|
||||
const mockCloseModal = jest.fn();
|
||||
const apiUrl = `end:/mail-domains/${mockMailDomain.slug}/mailboxes/`;
|
||||
|
||||
const renderModalCreateMailbox = () => {
|
||||
return render(
|
||||
<ModalCreateMailbox
|
||||
@@ -70,14 +61,12 @@ describe('ModalCreateMailbox', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
it('renders all the elements', () => {
|
||||
it('renders the modal with all fields and buttons', () => {
|
||||
renderModalCreateMailbox();
|
||||
|
||||
const {
|
||||
formTag,
|
||||
inputFirstName,
|
||||
@@ -98,23 +87,7 @@ describe('ModalCreateMailbox', () => {
|
||||
expect(buttonSubmit).toBeVisible();
|
||||
});
|
||||
|
||||
it('clicking on cancel button closes modal', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderModalCreateMailbox();
|
||||
|
||||
const { buttonCancel } = getFormElements();
|
||||
|
||||
expect(buttonCancel).toBeVisible();
|
||||
|
||||
await user.click(buttonCancel);
|
||||
|
||||
expect(mockCloseModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('displays validation errors on empty submit', async () => {
|
||||
const user = userEvent.setup();
|
||||
|
||||
it('shows validation errors for empty fields', async () => {
|
||||
renderModalCreateMailbox();
|
||||
|
||||
const {
|
||||
@@ -126,17 +99,16 @@ describe('ModalCreateMailbox', () => {
|
||||
} = getFormElements();
|
||||
|
||||
// To bypass html form validation we need to fill and clear the fields
|
||||
await user.type(inputFirstName, 'John');
|
||||
await user.type(inputLastName, 'Doe');
|
||||
await user.type(inputLocalPart, 'john.doe');
|
||||
await user.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
await userEvent.type(inputFirstName, 'John');
|
||||
await userEvent.type(inputLastName, 'Doe');
|
||||
await userEvent.type(inputLocalPart, 'john.doe');
|
||||
await userEvent.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
await userEvent.clear(inputFirstName);
|
||||
await userEvent.clear(inputLastName);
|
||||
await userEvent.clear(inputLocalPart);
|
||||
await userEvent.clear(inputEmailAddress);
|
||||
|
||||
await user.clear(inputFirstName);
|
||||
await user.clear(inputLastName);
|
||||
await user.clear(inputLocalPart);
|
||||
await user.clear(inputEmailAddress);
|
||||
|
||||
await user.click(buttonSubmit);
|
||||
await userEvent.click(buttonSubmit);
|
||||
|
||||
expect(screen.getByText(`@${mockMailDomain.name}`)).toBeVisible();
|
||||
|
||||
@@ -161,10 +133,10 @@ describe('ModalCreateMailbox', () => {
|
||||
expect(buttonSubmit).toBeDisabled();
|
||||
});
|
||||
|
||||
it('submits the form when validation passes', async () => {
|
||||
fetchMock.mock(`end:mail-domains/${mockMailDomain.slug}/mailboxes/`, 201);
|
||||
|
||||
const user = userEvent.setup();
|
||||
it('calls the createMailbox API on form submission with valid data', async () => {
|
||||
fetchMock.postOnce(apiUrl, {
|
||||
status: 201,
|
||||
});
|
||||
|
||||
renderModalCreateMailbox();
|
||||
|
||||
@@ -176,98 +148,34 @@ describe('ModalCreateMailbox', () => {
|
||||
buttonSubmit,
|
||||
} = getFormElements();
|
||||
|
||||
await user.type(inputFirstName, 'John');
|
||||
await user.type(inputLastName, 'Doe');
|
||||
await user.type(inputLocalPart, 'john.doe');
|
||||
await user.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
await userEvent.type(inputFirstName, 'John');
|
||||
await userEvent.type(inputLastName, 'Doe');
|
||||
await userEvent.type(inputLocalPart, 'johndoe');
|
||||
await userEvent.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
|
||||
await user.click(buttonSubmit);
|
||||
await userEvent.click(buttonSubmit);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.queryByText(/Please enter your first name/i),
|
||||
).not.toBeInTheDocument();
|
||||
expect(fetchMock.called(apiUrl)).toBeTruthy();
|
||||
});
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.queryByText(/Please enter your last name/i),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.queryByText(/You must have minimum 1 character/i),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(fetchMock.lastOptions()).toEqual({
|
||||
body: JSON.stringify({
|
||||
expect(fetchMock.lastCall(apiUrl)?.[1]?.body).toEqual(
|
||||
JSON.stringify({
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
local_part: 'john.doe',
|
||||
local_part: 'johndoe',
|
||||
secondary_email: 'john.doe@mail.com',
|
||||
}),
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
expect(mockOnSuccess).toHaveBeenCalled();
|
||||
);
|
||||
});
|
||||
|
||||
it('submits the form on key enter press', async () => {
|
||||
fetchMock.mock(`end:mail-domains/${mockMailDomain.slug}/mailboxes/`, 201);
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderModalCreateMailbox();
|
||||
|
||||
const {
|
||||
inputFirstName,
|
||||
inputLastName,
|
||||
inputLocalPart,
|
||||
inputEmailAddress,
|
||||
buttonSubmit,
|
||||
} = getFormElements();
|
||||
|
||||
await user.type(inputFirstName, 'John');
|
||||
await user.type(inputLastName, 'Doe');
|
||||
await user.type(inputLocalPart, 'john.doe');
|
||||
|
||||
await user.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
|
||||
await user.type(buttonSubmit, '{enter}');
|
||||
|
||||
expect(fetchMock.lastOptions()).toEqual({
|
||||
body: JSON.stringify({
|
||||
first_name: 'John',
|
||||
last_name: 'Doe',
|
||||
local_part: 'john.doe',
|
||||
secondary_email: 'john.doe@mail.com',
|
||||
}),
|
||||
credentials: 'include',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
expect(mockOnSuccess).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('displays right error message error when mailbox prefix is already used', async () => {
|
||||
// mockCreateMailbox.mockRejectedValueOnce(
|
||||
// new APIError('Failed to create the mailbox', {
|
||||
// status: 400,
|
||||
// cause: ['Mailbox with this Local_part and Domain already exists.'],
|
||||
// }),
|
||||
// );
|
||||
fetchMock.mock(`end:mail-domains/${mockMailDomain.slug}/mailboxes/`, {
|
||||
it('shows error message when mailbox prefix is already used', async () => {
|
||||
fetchMock.postOnce(apiUrl, {
|
||||
status: 400,
|
||||
body: {
|
||||
local_part: 'Mailbox with this Local_part and Domain already exists.',
|
||||
},
|
||||
});
|
||||
|
||||
const user = userEvent.setup();
|
||||
|
||||
renderModalCreateMailbox();
|
||||
|
||||
const {
|
||||
@@ -278,28 +186,32 @@ describe('ModalCreateMailbox', () => {
|
||||
buttonSubmit,
|
||||
} = getFormElements();
|
||||
|
||||
await user.type(inputFirstName, 'John');
|
||||
await user.type(inputLastName, 'Doe');
|
||||
await user.type(inputLocalPart, 'john.doe');
|
||||
await user.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
await userEvent.type(inputFirstName, 'John');
|
||||
await userEvent.type(inputLastName, 'Doe');
|
||||
await userEvent.type(inputLocalPart, 'johndoe');
|
||||
await userEvent.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
|
||||
await user.click(buttonSubmit);
|
||||
await userEvent.click(buttonSubmit);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText(/This email prefix is already used./i),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(inputLocalPart).toHaveFocus();
|
||||
});
|
||||
|
||||
it('displays right error message error when error 500 is received', async () => {
|
||||
fetchMock.mock(`end:mail-domains/${mockMailDomain.slug}/mailboxes/`, {
|
||||
status: 500,
|
||||
});
|
||||
it('closes the modal when cancel button is clicked', async () => {
|
||||
renderModalCreateMailbox();
|
||||
|
||||
const user = userEvent.setup();
|
||||
const { buttonCancel } = getFormElements();
|
||||
|
||||
await userEvent.click(buttonCancel);
|
||||
|
||||
expect(mockCloseModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('disables the submit button while the form is submitting', async () => {
|
||||
fetchMock.postOnce(apiUrl, new Promise(() => {})); // Simulate pending state
|
||||
|
||||
renderModalCreateMailbox();
|
||||
|
||||
@@ -311,23 +223,15 @@ describe('ModalCreateMailbox', () => {
|
||||
buttonSubmit,
|
||||
} = getFormElements();
|
||||
|
||||
await user.type(inputFirstName, 'John');
|
||||
await user.type(inputLastName, 'Doe');
|
||||
await user.type(inputLocalPart, 'john.doe');
|
||||
await user.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
await userEvent.type(inputFirstName, 'John');
|
||||
await userEvent.type(inputLastName, 'Doe');
|
||||
await userEvent.type(inputLocalPart, 'johndoe');
|
||||
await userEvent.type(inputEmailAddress, 'john.doe@mail.com');
|
||||
|
||||
await user.click(buttonSubmit);
|
||||
await userEvent.click(buttonSubmit);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Your request cannot be processed because the server is experiencing an error. If the problem ' +
|
||||
'persists, please contact our support to resolve the issue: suiteterritoriale@anct.gouv.fr',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(buttonSubmit).toBeDisabled();
|
||||
});
|
||||
|
||||
expect(inputFirstName).toHaveFocus();
|
||||
expect(buttonSubmit).toBeEnabled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -138,7 +138,6 @@
|
||||
"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 mail domain secret is misconfigured. Please, contact our support team to solve the issue: suiteterritoriale@anct.gouv.fr": "Le secret du domaine de messagerie est mal configuré. Veuillez contacter notre support pour résoudre le problème : suiteterritoriale@anct.gouv.fr",
|
||||
"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é.",
|
||||
@@ -171,6 +170,7 @@
|
||||
"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.",
|
||||
"Your request cannot be processed because the server is experiencing an error. If the problem persists, please contact our support to resolve the issue: suiteterritoriale@anct.gouv.fr": "Votre demande ne peut pas être traitée car le serveur rencontre une erreur. Si le problème persiste, veuillez contacter notre support pour résoudre le problème : suiteterritoriale@anct.gouv.fr",
|
||||
"Your request to create a mailbox cannot be completed due to incorrect settings on our server. Please contact our support team to resolve the problem: suiteterritoriale@anct.gouv.fr": "Votre demande de création de boîte mail ne peut pas être complétée en raison de paramètres incorrects sur notre serveur. Veuillez contacter notre équipe support pour résoudre le problème : suiteterritoriale@anct.gouv.fr",
|
||||
"[disabled]": "[désactivé]",
|
||||
"[enabled]": "[actif]",
|
||||
"[failed]": "[erroné]",
|
||||
|
||||
Reference in New Issue
Block a user