From c247614c0cbcb3752b52cd13c8946a88874c1ee5 Mon Sep 17 00:00:00 2001 From: Benjamin Morali Date: Mon, 23 Sep 2024 13:56:03 +0200 Subject: [PATCH] Ajout du lien au back-end sur le formulaire coordinateur (#220) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Ajout du lien au back-end sur le formulaire coordinateur * Ajout de tests * Correction de l'appel à la GeoAPI --------- Co-authored-by: Ornella <68587983+Ornella452@users.noreply.github.com> --- .../CandidatureConseiller.css | 6 +- .../candidature-conseiller/useApiAdmin.js | 33 +++- src/views/candidature-conseiller/useGeoApi.js | 2 +- .../BesoinEnCoordinateur.jsx | 10 +- .../CandidatureCoordinateur.jsx | 33 +++- .../CandidatureCoordinateur.test.jsx | 124 +++++++++++++- .../CandidatureStructure.css | 4 + .../CandidatureStructure.test.jsx | 156 +++++++++++++++--- 8 files changed, 328 insertions(+), 40 deletions(-) diff --git a/src/views/candidature-conseiller/CandidatureConseiller.css b/src/views/candidature-conseiller/CandidatureConseiller.css index d091151d..430a0c05 100644 --- a/src/views/candidature-conseiller/CandidatureConseiller.css +++ b/src/views/candidature-conseiller/CandidatureConseiller.css @@ -8,7 +8,7 @@ width: 100%; } -.cc-section legend + * { +.cc-section legend+* { clear: left; } @@ -37,3 +37,7 @@ display: flex; justify-content: center; } + +html { + scroll-behavior: smooth; +} diff --git a/src/views/candidature-conseiller/useApiAdmin.js b/src/views/candidature-conseiller/useApiAdmin.js index 3de4f1ce..b7350c31 100644 --- a/src/views/candidature-conseiller/useApiAdmin.js +++ b/src/views/candidature-conseiller/useApiAdmin.js @@ -33,6 +33,21 @@ export const useApiAdmin = () => { } }; + const creerCandidatureCoordinateur = async structureData => { + const baseUrl = import.meta.env.VITE_APP_API_URL; + const requestOptions = { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: structureData + }; + + try { + return await fetch(`${baseUrl}/candidature-structure-coordinateur`, requestOptions); + } catch (error) { + return error; + } + }; + const convertValueToBoolean = (conseillerData, key) => { conseillerData[key] = conseillerData[key] === 'on' || conseillerData[key] === 'oui'; }; @@ -62,7 +77,7 @@ export const useApiAdmin = () => { convertValueToBoolean(conseillerData, 'estEnFormation'); convertValueToBoolean(conseillerData, 'estDiplomeMedNum'); convertValueToBoolean(conseillerData, 'aUneExperienceMedNum'); - const codePostal = conseillerData.lieuHabitation.split(' ')?.[0]; + const codePostal = conseillerData.lieuHabitation.match(/\d{5}/)?.[0]; await handleInformationsVille(conseillerData, codePostal); delete conseillerData.lieuHabitation; delete conseillerData['g-recaptcha-response']; @@ -108,9 +123,23 @@ export const useApiAdmin = () => { return JSON.stringify(structureData); }; + const buildCoordinateurData = async formData => { + const coordinateurData = Object.fromEntries(formData); + handleContact(coordinateurData); + handleInformationsStructure(coordinateurData); + await handleAdresse(coordinateurData); + convertValueToBoolean(coordinateurData, 'aIdentifieCoordinateur'); + convertValueToBoolean(coordinateurData, 'confirmationEngagement'); + delete coordinateurData['g-recaptcha-response']; + return JSON.stringify(coordinateurData); + }; + return { buildConseillerData, buildStructureData, + buildCoordinateurData, creerCandidatureConseiller, - creerCandidatureStructure }; + creerCandidatureStructure, + creerCandidatureCoordinateur, + }; }; diff --git a/src/views/candidature-conseiller/useGeoApi.js b/src/views/candidature-conseiller/useGeoApi.js index 68a5b320..d1d4aff8 100644 --- a/src/views/candidature-conseiller/useGeoApi.js +++ b/src/views/candidature-conseiller/useGeoApi.js @@ -15,7 +15,7 @@ export const useGeoApi = () => { }; const getVilleParCode = async codePostal => { - const url = `${baseUrl.toString()}&code=${codePostal}`; + const url = `${baseUrl.toString()}&codePostal=${codePostal}`; const ville = await fetch(url); return await ville.json(); }; diff --git a/src/views/candidature-coordinateur/BesoinEnCoordinateur.jsx b/src/views/candidature-coordinateur/BesoinEnCoordinateur.jsx index ad831ad1..d3990630 100644 --- a/src/views/candidature-coordinateur/BesoinEnCoordinateur.jsx +++ b/src/views/candidature-coordinateur/BesoinEnCoordinateur.jsx @@ -13,22 +13,22 @@ export default function BesoinEnCoordinateur() { Avez-vous déjà identifié un candidat pour le poste de coordinateur de conseiller numérique ?*

Si oui, merci d’inviter ce candidat à s’inscrire sur la plateforme Conseiller numérique

- + Oui - + Non

Le coordinateur*

- + Effectuera uniquement des missions de coordination - + Accompagnera également des publics

À partir de quand êtes vous prêt à accueillir votre coordinateur ?*

- + Choisir une date diff --git a/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx b/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx index 44088658..d85ef9b6 100644 --- a/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx +++ b/src/views/candidature-coordinateur/CandidatureCoordinateur.jsx @@ -5,8 +5,11 @@ import InformationsDeStructure from '../candidature-structure/InformationsDeStru import BesoinEnCoordinateur from './BesoinEnCoordinateur'; import Motivation from './Motivation'; import Engagement from './Engagement'; -import { useScrollToSection } from '../../hooks/useScrollToSection'; +import Alert from '../../components/commun/Alert'; import Captcha from '../../components/commun/Captcha'; +import { useScrollToSection } from '../../hooks/useScrollToSection'; +import { useNavigate } from 'react-router-dom'; +import { useApiAdmin } from '../candidature-conseiller/useApiAdmin'; import '@gouvfr/dsfr/dist/component/form/form.min.css'; import '@gouvfr/dsfr/dist/component/input/input.min.css'; @@ -15,16 +18,35 @@ import '@gouvfr/dsfr/dist/component/radio/radio.min.css'; import '@gouvfr/dsfr/dist/component/badge/badge.min.css'; import '@gouvfr/dsfr/dist/component/notice/notice.min.css'; import '@gouvfr/dsfr/dist/component/sidemenu/sidemenu.min.css'; +import '@gouvfr/dsfr/dist/component/alert/alert.min.css'; import '../candidature-conseiller/CandidatureConseiller.css'; export default function CandidatureCoordinateur() { const [geoLocation, setGeoLocation] = useState(null); + const [validationError, setValidationError] = useState(''); + const navigate = useNavigate(); + const { buildCoordinateurData, creerCandidatureCoordinateur } = useApiAdmin(); useScrollToSection(); useEffect(() => { document.title = 'Conseiller numérique - Devenir coordinateur de conseillers numériques'; }, []); + const validerLaCandidature = async event => { + event.preventDefault(); + + const formData = new FormData(event.currentTarget); + const coordinateurData = await buildCoordinateurData(formData); + const resultatCreation = await creerCandidatureCoordinateur(coordinateurData); + if (resultatCreation.status >= 400) { + const error = await resultatCreation.json(); + setValidationError(error.message); + window.scrollTo({ top: 0, behavior: 'smooth' }); + } else { + navigate('/candidature-validee'); + } + }; + return (
@@ -34,7 +56,14 @@ export default function CandidatureCoordinateur() {

Je souhaite engager un coordinateur pour mes conseillers numériques

Les champs avec * sont obligatoires.

-
+ {validationError && +
+ + {validationError} + +
+ } + diff --git a/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx b/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx index 3b40ea5e..c22c1b1e 100644 --- a/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx +++ b/src/views/candidature-coordinateur/CandidatureCoordinateur.test.jsx @@ -1,7 +1,8 @@ -import { render, screen, within } from '@testing-library/react'; +import { render, screen, within, fireEvent, act } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; import CandidatureCoordinateur from './CandidatureCoordinateur'; -import { textMatcher } from '../../../test/test-utils'; +import { textMatcher, dateDujour } from '../../../test/test-utils'; +import * as ReactRouterDom from 'react-router-dom'; vi.mock('react-router-dom', () => ({ useLocation: () => ({ hash: '' }), @@ -142,22 +143,22 @@ describe('candidature coordinateur', () => { const oui = screen.getByRole('radio', { name: 'Oui' }); expect(oui).toBeRequired(); - expect(oui).toHaveAttribute('name', 'aIdentifieCandidat'); + expect(oui).toHaveAttribute('name', 'aIdentifieCoordinateur'); const non = screen.getByRole('radio', { name: 'Non' }); expect(non).toBeRequired(); - expect(non).toHaveAttribute('name', 'aIdentifieCandidat'); + expect(non).toHaveAttribute('name', 'aIdentifieCoordinateur'); const leCoordinateur = within(etapeBesoinCoordinateur).getByText(textMatcher('Le coordinateur*'), { selector: 'p' }); expect(leCoordinateur).toBeInTheDocument(); const coordination = screen.getByRole('radio', { name: 'Effectuera uniquement des missions de coordination' }); expect(coordination).toBeRequired(); - expect(coordination).toHaveAttribute('name', 'coordinateur'); + expect(coordination).toHaveAttribute('name', 'coordinateurTypeContrat'); const publics = screen.getByRole('radio', { name: 'Accompagnera également des publics' }); expect(publics).toBeRequired(); - expect(publics).toHaveAttribute('name', 'coordinateur'); + expect(publics).toHaveAttribute('name', 'coordinateurTypeContrat'); const dateAccueilCoordinateur = within(etapeBesoinCoordinateur).getByText( textMatcher('À partir de quand êtes vous prêt à accueillir votre coordinateur ?*'), @@ -243,5 +244,116 @@ describe('candidature coordinateur', () => { const formulaire = screen.getByRole('form', { name: 'Candidature coordinateur' }); within(formulaire).getByRole('button', { name: 'Envoyer votre candidature' }); }); + + it('quand je remplis le formulaire, que je l’envoie et que le serveur me renvoie une erreur, alors elle s’affiche sur la page', async () => { + // GIVEN + vi.useFakeTimers(); + vi.setSystemTime(new Date(2023, 11, 12, 13)); + + vi.stubGlobal('fetch', vi.fn( + () => ({ status: 400, json: async () => Promise.resolve({ message: 'Cette adresse mail est déjà utilisée' }) })) + ); + + 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: '75056 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 titreErreurValidation = screen.getByRole('heading', { level: 3, name: 'Erreur de validation' }); + expect(titreErreurValidation).toBeInTheDocument(); + const contenuErreurValidation = screen.getByText('Cette adresse mail est déjà utilisée', { selector: 'p' }); + expect(contenuErreurValidation).toBeInTheDocument(); + vi.useRealTimers(); + }); + + it('quand je remplis le formulaire avec toutes les informations valides, alors je suis redirigé vers la page de candidature validée', async () => { + // GIVEN + vi.useFakeTimers(); + vi.setSystemTime(new Date(2023, 11, 12, 13)); + + vi.stubGlobal('fetch', vi.fn( + () => ({ status: 200, json: async () => Promise.resolve({}) })) + ); + + const mockNavigate = vi.fn().mockReturnValue(() => { }); + vi.spyOn(ReactRouterDom, 'useNavigate').mockReturnValue(mockNavigate); + + 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: '75056 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 + expect(mockNavigate).toHaveBeenCalledWith('/candidature-validee'); + + vi.useRealTimers(); + }); }); diff --git a/src/views/candidature-structure/CandidatureStructure.css b/src/views/candidature-structure/CandidatureStructure.css index 52577b0e..034ae7e6 100644 --- a/src/views/candidature-structure/CandidatureStructure.css +++ b/src/views/candidature-structure/CandidatureStructure.css @@ -70,3 +70,7 @@ transform: rotate(360deg); } } + +html { + scroll-behavior: smooth; +} diff --git a/src/views/candidature-structure/CandidatureStructure.test.jsx b/src/views/candidature-structure/CandidatureStructure.test.jsx index ece5d9c3..589c5acb 100644 --- a/src/views/candidature-structure/CandidatureStructure.test.jsx +++ b/src/views/candidature-structure/CandidatureStructure.test.jsx @@ -1,7 +1,8 @@ -import { render, screen, within, waitFor, fireEvent } from '@testing-library/react'; +import { render, screen, within, waitFor, fireEvent, act } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; import CandidatureStructure from './CandidatureStructure'; -import { textMatcher } from '../../../test/test-utils'; +import { textMatcher, dateDujour } from '../../../test/test-utils'; +import * as ReactRouterDom from 'react-router-dom'; vi.mock('react-router-dom', () => ({ useLocation: () => ({ hash: '' }), @@ -9,33 +10,31 @@ vi.mock('react-router-dom', () => ({ })); describe('candidature structure', () => { - describe('étant une structure', () => { - it('quand j’affiche le formulaire alors le titre et le menu s’affichent', () => { - // WHEN - render(); + it('quand j’affiche le formulaire alors le titre et le menu s’affichent', () => { + // WHEN + render(); - // THEN - const titre = screen.getByRole('heading', { level: 1, name: textMatcher('Je souhaite engager un conseiller numérique') }); - expect(titre).toBeInTheDocument(); + // THEN + const titre = screen.getByRole('heading', { level: 1, name: textMatcher('Je souhaite engager un conseiller numérique') }); + expect(titre).toBeInTheDocument(); - const champsObligatoires = screen.getByText(textMatcher('Les champs avec * sont obligatoires.'), { selector: 'p' }); - expect(champsObligatoires).toBeInTheDocument(); + const champsObligatoires = screen.getByText(textMatcher('Les champs avec * sont obligatoires.'), { selector: 'p' }); + expect(champsObligatoires).toBeInTheDocument(); - const navigation = screen.getByRole('navigation', { name: 'Sommaire' }); - const menu = within(navigation).getByRole('list'); - const menuItems = within(menu).getAllByRole('listitem'); + const navigation = screen.getByRole('navigation', { name: 'Sommaire' }); + const menu = within(navigation).getByRole('list'); + const menuItems = within(menu).getAllByRole('listitem'); - const informationsDeStructure = within(menuItems[0]).getByRole('link', { name: 'Vos informations de structure' }); - expect(informationsDeStructure).toHaveAttribute('href', '#informations-de-structure'); + const informationsDeStructure = within(menuItems[0]).getByRole('link', { name: 'Vos informations de structure' }); + expect(informationsDeStructure).toHaveAttribute('href', '#informations-de-structure'); - const informationsDeContact = within(menuItems[1]).getByRole('link', { name: 'Vos informations de contact' }); - expect(informationsDeContact).toHaveAttribute('href', '#informations-de-contact'); + const informationsDeContact = within(menuItems[1]).getByRole('link', { name: 'Vos informations de contact' }); + expect(informationsDeContact).toHaveAttribute('href', '#informations-de-contact'); - const votreBesoinEnConseillerNumerique = within(menuItems[2]).getByRole('link', { name: 'Votre besoin en conseiller numérique' }); - expect(votreBesoinEnConseillerNumerique).toHaveAttribute('href', '#votre-besoin-en-conseiller-numerique'); - const votreMotivation = within(menuItems[3]).getByRole('link', { name: 'Votre motivation' }); - expect(votreMotivation).toHaveAttribute('href', '#votre-motivation'); - }); + const votreBesoinEnConseillerNumerique = within(menuItems[2]).getByRole('link', { name: 'Votre besoin en conseiller numérique' }); + expect(votreBesoinEnConseillerNumerique).toHaveAttribute('href', '#votre-besoin-en-conseiller-numerique'); + const votreMotivation = within(menuItems[3]).getByRole('link', { name: 'Votre motivation' }); + expect(votreMotivation).toHaveAttribute('href', '#votre-motivation'); }); it('quand j’affiche le formulaire alors l’étape "Vos informations de structure" est affiché', () => { @@ -337,5 +336,116 @@ describe('candidature structure', () => { expect(adresseInput).toHaveValue('20 AVENUE DE SEGUR, 75007 PARIS'); }); }); + + it('quand je remplis le formulaire, que je l’envoie et que le serveur me renvoie une erreur, alors elle s’affiche sur la page', async () => { + // GIVEN + vi.useFakeTimers(); + vi.setSystemTime(new Date(2023, 11, 12, 13)); + + vi.stubGlobal('fetch', vi.fn( + () => ({ status: 400, json: async () => Promise.resolve({ message: 'Cette adresse mail est déjà utilisée' }) })) + ); + + 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: '75056 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 titreErreurValidation = screen.getByRole('heading', { level: 3, name: 'Erreur de validation' }); + expect(titreErreurValidation).toBeInTheDocument(); + const contenuErreurValidation = screen.getByText('Cette adresse mail est déjà utilisée', { selector: 'p' }); + expect(contenuErreurValidation).toBeInTheDocument(); + vi.useRealTimers(); + }); + + it('quand je remplis le formulaire avec toutes les informations valides, alors je suis redirigé vers la page de candidature validée', async () => { + // GIVEN + vi.useFakeTimers(); + vi.setSystemTime(new Date(2023, 11, 12, 13)); + + vi.stubGlobal('fetch', vi.fn( + () => ({ status: 200, json: async () => Promise.resolve({}) })) + ); + + const mockNavigate = vi.fn().mockReturnValue(() => { }); + vi.spyOn(ReactRouterDom, 'useNavigate').mockReturnValue(mockNavigate); + + 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: '75056 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 + expect(mockNavigate).toHaveBeenCalledWith('/candidature-validee'); + + vi.useRealTimers(); + }); });