diff --git a/src/components/commun/Checkbox.jsx b/src/components/commun/Checkbox.jsx index 78c6600..1f72a88 100644 --- a/src/components/commun/Checkbox.jsx +++ b/src/components/commun/Checkbox.jsx @@ -17,6 +17,7 @@ export default function Checkbox({ children, id, onCheck, checked, required = tr Checkbox.propTypes = { children: PropTypes.node, id: PropTypes.string, + name: PropTypes.string, onCheck: PropTypes.func, checked: PropTypes.bool, required: PropTypes.bool, diff --git a/src/views/candidature-conseiller/CandidatureConseiller.jsx b/src/views/candidature-conseiller/CandidatureConseiller.jsx index 228ceac..fe4b14a 100644 --- a/src/views/candidature-conseiller/CandidatureConseiller.jsx +++ b/src/views/candidature-conseiller/CandidatureConseiller.jsx @@ -18,18 +18,18 @@ import '@gouvfr/dsfr/dist/component/sidemenu/sidemenu.min.css'; import './CandidatureConseiller.css'; export default function CandidatureConseiller() { - const [dateDisponibilite, setDateDisponibilite] = useState(); + const [dateDisponibilite, setDateDisponibilite] = useState(''); const [isSituationValid, setIsSituationValid] = useState(true); - const [situationChecks, setSituationChecks] = useState( - new Array(situations.length).fill(false) - ); useScrollToSection(); const valider = () => { setIsSituationValid(situationChecks.some(checked => checked)); if (!isSituationValid) { + document.getElementById('situationEtExperience').scrollIntoView(); + } else { + event.currentTarget.submit(); } }; @@ -42,17 +42,13 @@ export default function CandidatureConseiller() {

Je veux devenir conseiller numérique

Les champs avec * sont obligatoires.

-
+ - + - diff --git a/src/views/candidature-conseiller/CandidatureConseiller.test.jsx b/src/views/candidature-conseiller/CandidatureConseiller.test.jsx index 07b0b98..d7c9a02 100644 --- a/src/views/candidature-conseiller/CandidatureConseiller.test.jsx +++ b/src/views/candidature-conseiller/CandidatureConseiller.test.jsx @@ -8,34 +8,32 @@ vi.mock('react-router-dom', () => ({ })); describe('candidature conseiller', () => { - describe('étant un candidat', () => { - 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: 'Je veux devenir conseiller numérique' }); - expect(titre).toBeInTheDocument(); + // THEN + const titre = screen.getByRole('heading', { level: 1, name: 'Je veux devenir 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 informationsDeContact = within(menuItems[0]).getByRole('link', { name: 'Vos informations de contact' }); - expect(informationsDeContact).toHaveAttribute('href', '#informations-de-contact'); + const informationsDeContact = within(menuItems[0]).getByRole('link', { name: 'Vos informations de contact' }); + expect(informationsDeContact).toHaveAttribute('href', '#informations-de-contact'); - const situationEtExperience = within(menuItems[1]).getByRole('link', { name: 'Votre situation et expérience' }); - expect(situationEtExperience).toHaveAttribute('href', '#situation-et-experience'); + const situationEtExperience = within(menuItems[1]).getByRole('link', { name: 'Votre situation et expérience' }); + expect(situationEtExperience).toHaveAttribute('href', '#situation-et-experience'); - const votreDisponibilite = within(menuItems[2]).getByRole('link', { name: 'Votre disponibilité' }); - expect(votreDisponibilite).toHaveAttribute('href', '#votre-disponibilite'); + const votreDisponibilite = within(menuItems[2]).getByRole('link', { name: 'Votre disponibilité' }); + expect(votreDisponibilite).toHaveAttribute('href', '#votre-disponibilite'); - const votreMotivation = within(menuItems[3]).getByRole('link', { name: 'Votre motivation' }); - expect(votreMotivation).toHaveAttribute('href', '#votre-motivation'); - }); + 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 contact" est affiché', () => { @@ -113,7 +111,7 @@ describe('candidature conseiller', () => { expect(non).toHaveAttribute('name', 'experienceProfessionnelle'); }); - it('quand je coche "diplomé", un champ pour préciser le diplôme s’affiche', () => { + it('quand je coche "diplomé" alors un champ pour préciser le diplôme s’affiche', () => { // GIVEN render(); @@ -221,7 +219,7 @@ describe('candidature conseiller', () => { render(); // THEN - const enResume = screen.getByText(textMatcher('En résumé'), { selector: 'p' }); + const enResume = screen.getByText('En résumé', { selector: 'p' }); expect(enResume).toBeInTheDocument(); const titreResume = screen.getByText( @@ -242,11 +240,10 @@ describe('candidature conseiller', () => { it('quand je modifie la date de disponibilité, alors elle s’affiche dans l’encart "En résumé"', () => { // GIVEN render(); - const dateDisponibilite = '2023-12-12'; // WHEN - const date = screen.getByLabelText('Choisir une date'); - fireEvent.change(date, { target: { value: dateDisponibilite } }); + const dateDisponibilite = screen.getByLabelText('Choisir une date'); + fireEvent.change(dateDisponibilite, { target: { value: '2023-12-12' } }); // THEN const titreResume = screen.getByText( @@ -270,8 +267,8 @@ describe('candidature conseiller', () => { }, ]; - vi.spyOn(global, 'fetch').mockResolvedValue({ - json: () => Promise.resolve(geoApiResponse) + vi.spyOn(global, 'fetch').mockResolvedValueOnce({ + json: async () => Promise.resolve(geoApiResponse) }); // WHEN @@ -279,8 +276,8 @@ describe('candidature conseiller', () => { fireEvent.change(adresse, { target: { value: 'par' } }); // THEN - const paris = await screen.findByText(textMatcher('75001 Paris'), { selector: 'option' }); - const parisot = await screen.findByText(textMatcher('82137 Parisot'), { selector: 'option' }); + const paris = await screen.findByRole('option', { name: '75001 Paris', hidden: true }); + const parisot = await screen.findByRole('option', { name: '82137 Parisot', hidden: true }); expect(paris).toBeInTheDocument(); expect(parisot).toBeInTheDocument(); }); @@ -288,28 +285,56 @@ describe('candidature conseiller', () => { it('quand je coche au moins une case de situation et que je valide le formulaire alors il n’y a pas d’erreur de validation', () => { // GIVEN 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 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: '2023-12-12' } }); + 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', { type: 'submit' }); + const envoyer = screen.getByRole('button', { name: 'Envoyer votre candidature' }); fireEvent.click(envoyer); // THEN - const erreurCheckboxes = screen.queryByText(textMatcher('Vous devez cocher au moins une case'), { selector: 'p' }); + const erreurCheckboxes = screen.queryByText('Vous devez cocher au moins une case', { selector: 'p' }); expect(erreurCheckboxes).not.toBeInTheDocument(); }); it('quand je ne coche pas de case de situation et que je valide le formulaire alors il y a une erreur de validation', () => { // GIVEN 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 oui = screen.getByRole('radio', { name: 'Oui' }); + fireEvent.click(oui); + const date = screen.getByLabelText('Choisir une date'); + fireEvent.change(date, { target: { value: '2023-12-12' } }); + 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', { type: 'submit' }); + const envoyer = screen.getByRole('button', { name: 'Envoyer votre candidature' }); fireEvent.click(envoyer); // THEN - const erreurCheckboxes = screen.getByText(textMatcher('Vous devez cocher au moins une case'), { selector: 'p' }); + const erreurCheckboxes = screen.getByText('Vous devez cocher au moins une case', { selector: 'p' }); expect(erreurCheckboxes).toBeInTheDocument(); }); }); diff --git a/src/views/candidature-conseiller/EnResume.jsx b/src/views/candidature-conseiller/EnResume.jsx index f45eab7..18ee81f 100644 --- a/src/views/candidature-conseiller/EnResume.jsx +++ b/src/views/candidature-conseiller/EnResume.jsx @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; export default function EnResume({ dateDisponibilite }) { const formatDate = () => { - if (!dateDisponibilite) { + if (dateDisponibilite === '') { return '[Renseignez votre date de disponibilité]'; } return new Date(dateDisponibilite).toLocaleDateString(); diff --git a/src/views/candidature-conseiller/SituationEtExperience.jsx b/src/views/candidature-conseiller/SituationEtExperience.jsx index d3aea37..89f4d55 100644 --- a/src/views/candidature-conseiller/SituationEtExperience.jsx +++ b/src/views/candidature-conseiller/SituationEtExperience.jsx @@ -5,16 +5,10 @@ import Input from '../../components/commun/Input'; import { situations } from './situations'; import PropTypes from 'prop-types'; -export default function SituationEtExperience({ situationChecks, setSituationChecks, isSituationValid }) { +export default function SituationEtExperience({ isSituationValid }) { const [isDiplomeSelected, setIsDiplomeSelected] = useState(false); const handleCheck = event => { - const indexCaseCochee = situations.findIndex(situation => situation.id === event.target.id); - const updatedCheckedState = situationChecks.map((item, index) => - index === indexCaseCochee ? !item : item - ); - setSituationChecks(updatedCheckedState); - setIsDiplomeSelected(event.target.id === 'diplome' && event.target.checked); }; @@ -58,7 +52,5 @@ export default function SituationEtExperience({ situationChecks, setSituationChe } SituationEtExperience.propTypes = { - situationChecks: PropTypes.array, - setSituationChecks: PropTypes.func, isSituationValid: PropTypes.bool }; diff --git a/vitest.setup.js b/vitest.setup.js index e856011..730c7d2 100644 --- a/vitest.setup.js +++ b/vitest.setup.js @@ -1 +1,5 @@ +import { vi } from 'vitest'; import 'vitest-dom/extend-expect'; + +// scrollIntoView is not implemented in jsdom +window.HTMLElement.prototype.scrollIntoView = vi.fn();