diff --git a/src/components/commun/Input.jsx b/src/components/commun/Input.jsx index 2db9e1c..c08fadc 100644 --- a/src/components/commun/Input.jsx +++ b/src/components/commun/Input.jsx @@ -1,7 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; -export default function Input({ children, id, isRequired = true, type = 'text', pattern, onChange, list, min, readOnly, isLoading, ariaBusy, value, testId = '' }) { +export default function Input({ children, id, isRequired = true, autoComplete = 'on', testId = '', type = 'text', + pattern, onChange, list, min, readOnly, isLoading, ariaBusy, value }) { return (
@@ -11,13 +12,14 @@ export default function Input({ children, id, isRequired = true, type = 'text', type={type} id={id} required={isRequired} + autoComplete={autoComplete} pattern={pattern} onChange={onChange} list={list} min={min} readOnly={readOnly} name={id} - value={value} + value={value?.trim()} aria-busy={ariaBusy} data-testid={testId} /> @@ -35,6 +37,7 @@ Input.propTypes = { children: PropTypes.node, id: PropTypes.string, isRequired: PropTypes.bool, + autoComplete: PropTypes.string, type: PropTypes.string, pattern: PropTypes.string, onChange: PropTypes.func, diff --git a/src/views/candidature-conseiller/AddressChooser.jsx b/src/views/candidature-conseiller/AddressChooser.jsx index 7d112f8..194357a 100644 --- a/src/views/candidature-conseiller/AddressChooser.jsx +++ b/src/views/candidature-conseiller/AddressChooser.jsx @@ -10,6 +10,7 @@ export default function AddressChooser() { return ( <> { diff --git a/src/views/candidature-conseiller/CandidatureConseiller.jsx b/src/views/candidature-conseiller/CandidatureConseiller.jsx index e1ca6e7..ed0f3a6 100644 --- a/src/views/candidature-conseiller/CandidatureConseiller.jsx +++ b/src/views/candidature-conseiller/CandidatureConseiller.jsx @@ -54,10 +54,13 @@ export default function CandidatureConseiller() { } else { const conseillerData = await buildConseillerData(formData); const resultatCreation = await creerCandidatureConseiller(conseillerData); - if (resultatCreation.status >= 400) { + if (resultatCreation?.status >= 400) { const error = await resultatCreation.json(); setValidationError(error.message); window.scrollTo({ top: 0, behavior: 'smooth' }); + } else if (!resultatCreation.status) { + setValidationError(resultatCreation.message); + window.scrollTo({ top: 0, behavior: 'smooth' }); } else { navigate('/candidature-validee-conseiller'); } diff --git a/src/views/candidature-conseiller/CandidatureConseiller.test.jsx b/src/views/candidature-conseiller/CandidatureConseiller.test.jsx index 961eaf5..ee73c21 100644 --- a/src/views/candidature-conseiller/CandidatureConseiller.test.jsx +++ b/src/views/candidature-conseiller/CandidatureConseiller.test.jsx @@ -522,7 +522,7 @@ describe('candidature conseiller', () => { vi.useRealTimers(); }); - it('quand je remplis complètementle formulaire avec un numéro téléphone valide, alors je suis redirigé vers la page de candidature validée', async () => { + it('quand je remplis complètement le formulaire avec un numéro téléphone valide, alors je suis redirigé vers la page de candidature validée', async () => { // GIVEN vi.useFakeTimers(); vi.setSystemTime(new Date(2023, 11, 12, 13)); @@ -661,4 +661,51 @@ describe('candidature conseiller', () => { vi.useRealTimers(); }); + + it('quand je remplis le formulaire et qu’une erreur se produit alors un message d’erreur s’affiche', async () => { + // GIVEN + vi.useFakeTimers(); + vi.setSystemTime(new Date(2023, 11, 12, 13)); + + vi.spyOn(useApiAdmin, 'useApiAdmin').mockImplementation(() => ({ + creerCandidatureConseiller: vi.fn().mockReturnValue({ message: 'Failed to fetch' }), + buildConseillerData: vi.fn(), + })); + + render(); + const prenom = screen.getByLabelText('Prénom *'); + fireEvent.change(prenom, { target: { value: 'Jean' } }); + const nom = screen.getByLabelText('Nom *'); + fireEvent.change(nom, { target: { value: 'Dupont' } }); + const email = screen.getByLabelText('Adresse e-mail * Format attendu : nom@domaine.fr'); + fireEvent.change(email, { target: { value: 'jean.dupont@example.com' } }); + const adresse = screen.getByLabelText('Votre lieu d’habitation * Saississez le nom ou le code postal de votre commune.'); + fireEvent.change(adresse, { target: { value: '93100 Montreuil' } }); + const telephone = screen.getByLabelText('Téléphone Format attendu : +33122334455'); + fireEvent.change(telephone, { target: { value: '+33159590730' } }); + const enEmploi = screen.getByRole('checkbox', { name: 'En emploi' }); + fireEvent.click(enEmploi); + const oui = screen.getByRole('radio', { name: 'Oui' }); + fireEvent.click(oui); + const date = screen.getByLabelText('Choisir une date'); + fireEvent.change(date, { target: { value: dateDujour() } }); + const _5km = screen.getByRole('radio', { name: '5 km' }); + fireEvent.click(_5km); + const descriptionMotivation = screen.getByLabelText('Votre message *'); + fireEvent.change(descriptionMotivation, { target: { value: 'je suis motivé !' } }); + + // WHEN + const envoyer = screen.getByRole('button', { name: 'Envoyer votre candidature' }); + + // eslint-disable-next-line testing-library/no-unnecessary-act + await act(() => { + fireEvent.click(envoyer); + }); + + // THEN + const contenuErreurValidation = screen.getByText('Failed to fetch', { selector: 'p' }); + expect(contenuErreurValidation).toBeInTheDocument(); + + vi.useRealTimers(); + }); }); diff --git a/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx b/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx index b754f52..b1a72b6 100644 --- a/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx +++ b/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx @@ -39,10 +39,13 @@ export default function CandidatureCoordinateur() { const formData = new FormData(event.currentTarget); const coordinateurData = await buildCoordinateurData(formData, geoLocation, codeCommune); const resultatCreation = await creerCandidatureCoordinateur(coordinateurData); - if (resultatCreation.status >= 400) { + if (resultatCreation?.status >= 400) { const error = await resultatCreation.json(); setValidationError(error.message); window.scrollTo({ top: 0, behavior: 'smooth' }); + } else if (!resultatCreation.status) { + setValidationError(resultatCreation.message); + window.scrollTo({ top: 0, behavior: 'smooth' }); } else { navigate('/candidature-validee-structure'); } diff --git a/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx b/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx index 358db4a..f166a49 100644 --- a/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx +++ b/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx @@ -3,7 +3,7 @@ import { describe, expect, it, vi } from 'vitest'; import CandidatureCoordinateur from './CandidatureCoordinateur'; import { textMatcher, dateDujour } from '../../../test/test-utils'; import * as ReactRouterDom from 'react-router-dom'; -import { useApiAdmin } from '../candidature-conseiller/useApiAdmin'; +import * as useApiAdmin from '../candidature-conseiller/useApiAdmin'; import { useEntrepriseFinder } from '../candidature-structure/useEntrepriseFinder'; vi.mock('react-router-dom', () => ({ @@ -427,7 +427,7 @@ describe('candidature coordinateur', () => { ] ]; - const { buildCoordinateurData } = renderHook(() => useApiAdmin()).result.current; + const { buildCoordinateurData } = renderHook(() => useApiAdmin.useApiAdmin()).result.current; const { getGeoLocationFromAddress } = renderHook(() => useEntrepriseFinder()).result.current; // //WHEN @@ -462,5 +462,61 @@ describe('candidature coordinateur', () => { vi.useRealTimers(); }); + + it('quand je remplis le formulaire et qu’une erreur se produit alors un message d’erreur s’affiche', async () => { + // GIVEN + vi.useFakeTimers(); + vi.setSystemTime(new Date(2023, 11, 12, 13)); + + vi.spyOn(useApiAdmin, 'useApiAdmin').mockImplementation(() => ({ + creerCandidatureCoordinateur: vi.fn().mockReturnValue({ message: 'Failed to fetch' }), + buildCoordinateurData: vi.fn(), + })); + + render(); + const siret = screen.getByLabelText('SIRET / RIDET *'); + fireEvent.change(siret, { target: { value: '1234567890123' } }); + const denomination = screen.getByLabelText('Dénomination *'); + fireEvent.change(denomination, { target: { value: 'Entreprise' } }); + const adresse = screen.getByLabelText('Adresse *'); + fireEvent.change(adresse, { target: { value: '75007 Paris' } }); + const typeStructure = screen.getByRole('radio', { name: 'Une commune' }); + fireEvent.click(typeStructure); + const prenom = screen.getByLabelText('Prénom *'); + fireEvent.change(prenom, { target: { value: 'Jean' } }); + const nom = screen.getByLabelText('Nom *'); + fireEvent.change(nom, { target: { value: 'Dupont' } }); + const fonction = screen.getByLabelText('Fonction *'); + fireEvent.change(fonction, { target: { value: 'Test' } }); + const email = screen.getByLabelText('Adresse e-mail *'); + fireEvent.change(email, { target: { value: 'jean.dupont@example.com' } }); + const telephone = screen.getByLabelText('Téléphone *'); + fireEvent.change(telephone, { target: { value: '+33123456789' } }); + const identificationCandidat = screen.getByRole('radio', { name: 'Oui' }); + fireEvent.click(identificationCandidat); + const typeMission = screen.getByRole('radio', { name: 'Accompagnera également des publics' }); + fireEvent.click(typeMission); + const date = screen.getByLabelText('Choisir une date'); + fireEvent.change(date, { target: { value: dateDujour() } }); + const descriptionMotivation = screen.getByLabelText('Votre message *'); + fireEvent.change(descriptionMotivation, { target: { value: 'je suis motivé !' } }); + const confirmation = screen.getByRole('checkbox', { name: 'Je confirme avoir lu et pris connaissance des conditions d’engagement. *' }); + fireEvent.click(confirmation); + + // WHEN + const envoyer = screen.getByRole('button', { name: 'Envoyer votre candidature' }); + + // eslint-disable-next-line testing-library/no-unnecessary-act + await act(() => { + fireEvent.click(envoyer); + }); + + + // THEN + const contenuErreurValidation = screen.getByText('Failed to fetch', { selector: 'p' }); + expect(contenuErreurValidation).toBeInTheDocument(); + + vi.useRealTimers(); + }); }); diff --git a/src/views/candidature-structure/CandidatureStructure.jsx b/src/views/candidature-structure/CandidatureStructure.jsx index 3695c26..9208e5c 100644 --- a/src/views/candidature-structure/CandidatureStructure.jsx +++ b/src/views/candidature-structure/CandidatureStructure.jsx @@ -40,10 +40,13 @@ export default function CandidatureStructure() { const formData = new FormData(event.currentTarget); const structureData = await buildStructureData(formData, geoLocation, codeCommune); const resultatCreation = await creerCandidatureStructure(structureData); - if (resultatCreation.status >= 400) { + if (resultatCreation?.status >= 400) { const error = await resultatCreation.json(); setValidationError(error.message); window.scrollTo({ top: 0, behavior: 'smooth' }); + } else if (!resultatCreation.status) { + setValidationError(resultatCreation.message); + window.scrollTo({ top: 0, behavior: 'smooth' }); } else { navigate('/candidature-validee-structure'); } diff --git a/src/views/candidature-structure/CandidatureStructure.test.jsx b/src/views/candidature-structure/CandidatureStructure.test.jsx index c890545..de05cdd 100644 --- a/src/views/candidature-structure/CandidatureStructure.test.jsx +++ b/src/views/candidature-structure/CandidatureStructure.test.jsx @@ -3,7 +3,7 @@ import { describe, expect, it, vi } from 'vitest'; import CandidatureStructure from './CandidatureStructure'; import { textMatcher, dateDujour } from '../../../test/test-utils'; import * as ReactRouterDom from 'react-router-dom'; -import { useApiAdmin } from '../candidature-conseiller/useApiAdmin'; +import * as useApiAdmin from '../candidature-conseiller/useApiAdmin'; import { useEntrepriseFinder } from './useEntrepriseFinder'; vi.mock('react-router-dom', () => ({ @@ -519,7 +519,7 @@ describe('candidature structure', () => { ] ]; - const { buildStructureData } = renderHook(() => useApiAdmin()).result.current; + const { buildStructureData } = renderHook(() => useApiAdmin.useApiAdmin()).result.current; const { getGeoLocationFromAddress } = renderHook(() => useEntrepriseFinder()).result.current; // //WHEN @@ -555,5 +555,61 @@ describe('candidature structure', () => { vi.useRealTimers(); }); + + it('quand je remplis le formulaire et qu’une erreur se produit alors un message d’erreur s’affiche', async () => { + // GIVEN + vi.useFakeTimers(); + vi.setSystemTime(new Date(2023, 11, 12, 13)); + + vi.spyOn(useApiAdmin, 'useApiAdmin').mockImplementation(() => ({ + creerCandidatureStructure: vi.fn().mockReturnValue({ message: 'Failed to fetch' }), + buildStructureData: vi.fn(), + })); + + render(); + const siret = screen.getByLabelText('SIRET / RIDET *'); + fireEvent.change(siret, { target: { value: '1234567890123' } }); + const denomination = screen.getByLabelText('Dénomination *'); + fireEvent.change(denomination, { target: { value: 'Entreprise' } }); + const adresse = screen.getByLabelText('Adresse *'); + fireEvent.change(adresse, { target: { value: '75007 Paris' } }); + const typeStructure = screen.getByRole('radio', { name: 'Une commune' }); + fireEvent.click(typeStructure); + const prenom = screen.getByLabelText('Prénom *'); + fireEvent.change(prenom, { target: { value: 'Jean' } }); + const nom = screen.getByLabelText('Nom *'); + fireEvent.change(nom, { target: { value: 'Dupont' } }); + const fonction = screen.getByLabelText('Fonction *'); + fireEvent.change(fonction, { target: { value: 'Test' } }); + const email = screen.getByLabelText('Adresse e-mail *'); + fireEvent.change(email, { target: { value: 'jean.dupont@example.com' } }); + const telephone = screen.getByLabelText('Téléphone *'); + fireEvent.change(telephone, { target: { value: '+33123456789' } }); + const nombre = screen.getByLabelText('Combien de conseillers numériques souhaitez-vous accueillir ?*'); + fireEvent.change(nombre, { target: { value: 1 } }); + const identificationCandidat = screen.getByRole('radio', { name: 'Oui' }); + fireEvent.click(identificationCandidat); + const date = screen.getByLabelText('Choisir une date'); + fireEvent.change(date, { target: { value: dateDujour() } }); + const descriptionMotivation = screen.getByLabelText('Votre message *'); + fireEvent.change(descriptionMotivation, { target: { value: 'je suis motivé !' } }); + const confirmation = screen.getByRole('checkbox', { name: 'Je confirme avoir lu et pris connaissance des conditions d’engagement. *' }); + fireEvent.click(confirmation); + + // WHEN + const envoyer = screen.getByRole('button', { name: 'Envoyer votre candidature' }); + + // eslint-disable-next-line testing-library/no-unnecessary-act + await act(() => { + fireEvent.click(envoyer); + }); + + + // THEN + const contenuErreurValidation = screen.getByText('Failed to fetch', { selector: 'p' }); + expect(contenuErreurValidation).toBeInTheDocument(); + + vi.useRealTimers(); + }); });