From 341c08de65907890b25e7c18d20b797cbca31d42 Mon Sep 17 00:00:00 2001 From: Fabien Mercier Date: Wed, 26 Jun 2024 14:01:26 +0200 Subject: [PATCH] Mise en place du formulaire candidature d'un conseiller --- .github/workflows/continuous-integration.yml | 30 +++++++++ .github/workflows/eslint.yml | 17 ----- src/App.js | 2 + .../CandidatureConseiller.css | 11 +++ .../CandidatureConseiller.jsx | 22 ++++++ .../CandidatureConseiller.test.jsx | 67 +++++++++++++++++++ .../InformationsDeContact.jsx | 40 +++++++++++ src/views/candidature-conseiller/Input.jsx | 21 ++++++ .../PageCandidatureConseiller.jsx | 12 ++++ src/views/candidature-conseiller/Sommaire.jsx | 30 +++++++++ 10 files changed, 235 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/continuous-integration.yml delete mode 100644 .github/workflows/eslint.yml create mode 100644 src/views/candidature-conseiller/CandidatureConseiller.css create mode 100644 src/views/candidature-conseiller/CandidatureConseiller.jsx create mode 100644 src/views/candidature-conseiller/CandidatureConseiller.test.jsx create mode 100644 src/views/candidature-conseiller/InformationsDeContact.jsx create mode 100644 src/views/candidature-conseiller/Input.jsx create mode 100644 src/views/candidature-conseiller/PageCandidatureConseiller.jsx create mode 100644 src/views/candidature-conseiller/Sommaire.jsx diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 0000000..104a997 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,30 @@ +name: Continuous Integration + +on: pull_request + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + cache: npm + node-version-file: package.json + - name: Install modules + run: npm i + - name: Lint + run: npm run lint + + tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + cache: npm + node-version-file: package.json + - name: Install modules + run: npm i + - name: Lint + run: npm run test diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml deleted file mode 100644 index 73ee1da..0000000 --- a/.github/workflows/eslint.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: ESLint - -on: pull_request - -jobs: - eslint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - cache: npm - node-version-file: package.json - - name: Install modules - run: npm i - - name: Lint - run: npm run lint diff --git a/src/App.js b/src/App.js index 734152f..4ec23ae 100644 --- a/src/App.js +++ b/src/App.js @@ -15,6 +15,7 @@ import Carte from './views/Carte'; import CarteCoordinateur from './views/coordination-territoriale/CarteCoordinateur'; import Formation from './views/formation'; import DonneesPersonnelles from './views/donnees-personnelles'; +import PageCandidatureConseiller from './views/candidature-conseiller/PageCandidatureConseiller'; const RedirectCarto = () => { const { permanence } = useParams(); @@ -37,6 +38,7 @@ function App() { }/> + }/> }/> }/> }/> diff --git a/src/views/candidature-conseiller/CandidatureConseiller.css b/src/views/candidature-conseiller/CandidatureConseiller.css new file mode 100644 index 0000000..d5b2249 --- /dev/null +++ b/src/views/candidature-conseiller/CandidatureConseiller.css @@ -0,0 +1,11 @@ +.cc-section { + border: 1px solid var(--grey-900-175); +} + +.cc-titre { + color: var(--blue-france-sun-113-625); +} + +.cc-obligatoire { + color: var(--error-425-625); +} diff --git a/src/views/candidature-conseiller/CandidatureConseiller.jsx b/src/views/candidature-conseiller/CandidatureConseiller.jsx new file mode 100644 index 0000000..bbc4d75 --- /dev/null +++ b/src/views/candidature-conseiller/CandidatureConseiller.jsx @@ -0,0 +1,22 @@ +import React from 'react'; +import Sommaire from './Sommaire'; +import InformationsDeContact from './InformationsDeContact'; +import './CandidatureConseiller.css'; + +export default function CandidatureConseiller() { + return ( +
+
+
+ +
+
+

Je veux devenir conseiller numérique

+
+ + +
+
+
+ ); +} diff --git a/src/views/candidature-conseiller/CandidatureConseiller.test.jsx b/src/views/candidature-conseiller/CandidatureConseiller.test.jsx new file mode 100644 index 0000000..a913532 --- /dev/null +++ b/src/views/candidature-conseiller/CandidatureConseiller.test.jsx @@ -0,0 +1,67 @@ +import { render, screen, within } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; +import CandidatureConseiller from './CandidatureConseiller'; + +export const textMatcher = wording => (_, element) => { + return element?.textContent === wording; +}; + +describe('candidature conseiller', () => { + describe('étant un candidat', () => { + it('quand j’affiche le formulaire alors le titre et le menu s’affiche', () => { + // WHEN + render(); + + // THEN + const titre = screen.getByRole('heading', { level: 1, name: 'Je veux devenir conseiller numérique' }); + expect(titre).toBeInTheDocument(); + + 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', '#informationsDeContact'); + + const situationEtExperience = within(menuItems[1]).getByRole('link', { name: 'Votre situation et expérience' }); + expect(situationEtExperience).toHaveAttribute('href', '#situtationEtExperience'); + + const votreDisponibilite = within(menuItems[2]).getByRole('link', { name: 'Votre disponibilité' }); + expect(votreDisponibilite).toHaveAttribute('href', '#votreDisponibilite'); + + const votreMotivation = within(menuItems[3]).getByRole('link', { name: 'Votre motivation' }); + expect(votreMotivation).toHaveAttribute('href', '#votreDisponibilite'); + }); + }); + + it('quand j’affiche le formulaire alors l’étape "Vos informations de contact" est affiché', () => { + // WHEN + render(); + + // THEN + const formulaire = screen.getByRole('form', { name: 'Candidature conseiller' }); + const etapeInformationsDeContact = within(formulaire).getByRole('group', { name: 'Vos informations de contact' }); + expect(etapeInformationsDeContact).toHaveAttribute('id', 'informationsDeContact'); + + const champsObligatoires = within(etapeInformationsDeContact).getByText(textMatcher('Les champs avec * sont obligatoires.'), { selector: 'p' }); + expect(champsObligatoires).toBeInTheDocument(); + + const prenom = within(etapeInformationsDeContact).getByLabelText('Prénom *'); + expect(prenom).toHaveAttribute('type', 'text'); + expect(prenom).toBeRequired(); + + const nom = within(etapeInformationsDeContact).getByLabelText('Nom *'); + expect(nom).toHaveAttribute('type', 'text'); + expect(nom).toBeRequired(); + + const email = within(etapeInformationsDeContact).getByLabelText('Adresse e-mail * Format attendu : nom@domaine.fr'); + expect(email).toHaveAttribute('type', 'email'); + expect(email).toBeRequired(); + + const telephone = within(etapeInformationsDeContact).getByLabelText('Téléphone Format attendu : 0122334455'); + expect(telephone).toHaveAttribute('type', 'text'); + + const habitation = within(etapeInformationsDeContact).getByLabelText('Votre lieu d’habitation Saississez le nom ou le code postal de votre commune.'); + expect(habitation).toHaveAttribute('type', 'text'); + }); +}); diff --git a/src/views/candidature-conseiller/InformationsDeContact.jsx b/src/views/candidature-conseiller/InformationsDeContact.jsx new file mode 100644 index 0000000..3e63e9f --- /dev/null +++ b/src/views/candidature-conseiller/InformationsDeContact.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import Input from './Input'; + +export default function InformationsDeContact() { + return ( +
+ Vos informations de contact +

Les champs avec * sont obligatoires.

+
+ + Prénom * + + + Nom * + + + Adresse e-mail * Format attendu : nom@domaine.fr + + + Téléphone Format attendu : 0122334455 + + + Votre lieu d’habitation Saississez le nom ou le code postal de votre commune. + +
+ ); +} diff --git a/src/views/candidature-conseiller/Input.jsx b/src/views/candidature-conseiller/Input.jsx new file mode 100644 index 0000000..660e5fc --- /dev/null +++ b/src/views/candidature-conseiller/Input.jsx @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './CandidatureConseiller.css'; + +export default function Input({ children, id, isRequired = true, type = 'text' }) { + return ( +
+
+ + +
+
+ ); +} + +Input.propTypes = { + children: PropTypes.node, + id: PropTypes.string, + isRequired: PropTypes.bool, + type: PropTypes.string, +}; diff --git a/src/views/candidature-conseiller/PageCandidatureConseiller.jsx b/src/views/candidature-conseiller/PageCandidatureConseiller.jsx new file mode 100644 index 0000000..e7e3ac0 --- /dev/null +++ b/src/views/candidature-conseiller/PageCandidatureConseiller.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import Header from '../../components/Header'; +import CandidatureConseiller from './CandidatureConseiller'; + +export default function PageCandidatureConseiller() { + return ( + <> +
+ + + ); +} diff --git a/src/views/candidature-conseiller/Sommaire.jsx b/src/views/candidature-conseiller/Sommaire.jsx new file mode 100644 index 0000000..120ea90 --- /dev/null +++ b/src/views/candidature-conseiller/Sommaire.jsx @@ -0,0 +1,30 @@ +import React from 'react'; + +export default function Sommaire() { + return ( + + ); +}